[
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]\npatreon: # Replace with a single Patreon username\nopen_collective: # Replace with a single Open Collective username\nko_fi: jonataslaw\ntidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel\ncommunity_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry\nliberapay: # Replace with a single Liberapay username\nissuehunt: # Replace with a single IssueHunt username\notechie: # Replace with a single Otechie username\ncustom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: jonataslaw\n\n---\n**ATTENTION: DO NOT USE THIS FIELD TO ASK SUPPORT QUESTIONS. USE THE PLATFORM CHANNELS FOR THIS. THIS SPACE IS DEDICATED ONLY FOR BUGS DESCRIPTION.**\n**Fill in the template. Issues that do not respect the model will be closed.**\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**Reproduction code\nNOTE: THIS IS MANDATORY, IF YOUR ISSUE DOES NOT CONTAIN IT, IT WILL BE CLOSED PRELIMINARY)**\n\nexample:\n\n```dart\nvoid main() => runApp(MaterialApp(home: Home()));\n\nclass Home extends StatelessWidget {\n  final count = 0.obs;\n  @override\n  Widget build(context) => Scaffold(\n      appBar: AppBar(title: Text(\"counter\")),\n      body: Center(\n        child: Obx(() => Text(\"$count\")),\n      ),\n      floatingActionButton: FloatingActionButton(\n        child: Icon(Icons.add),\n        onPressed: () => count.value++,\n      ));\n}\n```\n\n**To Reproduce**\nSteps to reproduce the behavior:\n1. Go to '...'\n2. Click on '....'\n3. Scroll down to '....'\n4. See error\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Screenshots**\nIf applicable, add screenshots to help explain your problem.\n\n**Flutter Version:**\nEnter the version of the Flutter you are using\n\n**Getx Version:**\nEnter the version of the Getx you are using\n\n**Describe on which device you found the bug:**\nex: Moto z2 - Android.\n\n**Minimal reproduce code**\nProvide a minimum reproduction code for the problem\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n**ATTENTION: DO NOT USE THIS FIELD TO ASK SUPPORT QUESTIONS. USE THE PLATFORM CHANNELS FOR THIS. THIS SPACE IS DEDICATED ONLY FOR FEATURE REQUESTS**\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n"
  },
  {
    "path": ".github/pull_request_template.md",
    "content": "*Replace this paragraph with a description of what this PR is changing or adding, and why. Consider including before/after screenshots.*\n\nEvery PR must update the corresponding documentation in the `code`, and also the readme in english with the following changes.\n\n## Pre-launch Checklist\n\n- [ ] I updated/added relevant documentation (doc comments with `///`).\n- [ ] I added new tests to check the change I am making or feature I am adding, or @jonataslaw said the PR is test-exempt.\n- [ ] All existing and new tests are passing.\n"
  },
  {
    "path": ".github/workflows/main.yml",
    "content": "#The name of your workflow.\nname: build\n# Trigger the workflow on push or pull request\non:\n  push:\n    branches: [master]\n  pull_request:\n    branches: [master]\n#A workflow run is made up of one or more jobs. Jobs run in parallel by default.\njobs:\n  test:\n    #The type of machine to run the job on. [windows,macos, ubuntu , self-hosted]\n    defaults:\n      run:\n        working-directory: ./\n    runs-on: ubuntu-latest\n    #sequence of tasks called\n    steps:\n      # The branch or tag ref that triggered the workflow will be checked out.\n      # https://github.com/actions/checkout\n      - uses: actions/checkout@v4\n      # Setup a flutter environment.\n      # https://github.com/marketplace/actions/flutter-action\n      - uses: subosito/flutter-action@v2\n        with:\n          flutter-version: \"3.32.1\"\n          channel: \"stable\"\n      - run: flutter pub get\n      #- run: flutter analyze\n      # run  flutter widgets tests  and unit tests\n      - run: flutter test --coverage\n      # Upload coverage reports to Codecov\n      # https://github.com/marketplace/actions/codecov\n      - uses: codecov/codecov-action@v4\n"
  },
  {
    "path": ".gitignore",
    "content": "# See https://www.dartlang.org/guides/libraries/private-files\n\n# See https://www.dartlang.org/guides/libraries/private-files\n\n# Files and directories created by pub\n.dart_tool/\n.packages\nbuild/\n# If you're building an application, you may want to check-in your pubspec.lock\npubspec.lock\n.pub/\n\n# Directory created by dartdoc\n# If you don't generate documentation locally you can remove this line.\ndoc/api/\n\n# Avoid committing generated Javascript files:\n*.dart.js\n*.info.json      # Produced by the --dump-info flag.\n*.js             # When generated by dart2js. Don't specify *.js if your\n                 # project includes source files written in JavaScript.\n*.js_\n*.js.deps\n*.js.map\n\n# Files and directories created when test or run example\nexample/android/local.properties\nexample/ios/\nexample/.dart_tool/\nexample/.packages\n\n# IntelliJ\n*.iml\n.idea/*\n#.idea/workspace.xml\n#.idea/tasks.xml\n#.idea/gradle.xml\n#.idea/assetWizardSettings.xml\n#.idea/dictionaries\n#.idea/libraries\n#.idea/caches\n\n# User-specific stuff\n.idea/**/workspace.xml\n.idea/**/tasks.xml\n.idea/**/dictionaries\n.idea/**/shelf\n\n# Sensitive or high-churn files\n.idea/**/dataSources/\n.idea/**/dataSources.ids\n.idea/**/dataSources.local.xml\n.idea/**/sqlDataSources.xml\n.idea/**/dynamic.xml\n.idea/**/uiDesigner.xml\n.idea/**/dbnavigator.xml\n\n# Gradle\n.idea/**/gradle.xml\n.idea/**/libraries\n\n# Android Studio Navigation editor temp files\n.navigation/\n\n# Android Studio captures folder\ncaptures/\n\n# External native build folder generated in Android Studio 2.2 and later\n.externalNativeBuild\n\n### https://raw.github.com/github/gitignore/80a8803b004013d17291196825a327b9e871f009/Global/VisualStudioCode.gitignore\n.vscode/*\n!.vscode/settings.json\n!.vscode/tasks.json\n!.vscode/launch.json\n!.vscode/extensions.json\n\nexample/macos/Flutter/ephemeral/Flutter-Generated.xcconfig\n\nexample/macos/Flutter/ephemeral/\n\nexample/macos/Flutter/GeneratedPluginRegistrant.swift\n\n# Coverage files\ncoverage/"
  },
  {
    "path": ".metadata",
    "content": "# This file tracks properties of this Flutter project.\n# Used by Flutter tool to assess capabilities and perform upgrades etc.\n#\n# This file should be version controlled and should not be manually edited.\n\nversion:\n  revision: 60bd88df915880d23877bfc1602e8ddcf4c4dd2a\n  channel: stable\n\nproject_type: app\n"
  },
  {
    "path": ".vscode/launch.json",
    "content": "{\n    // Use IntelliSense to learn about possible attributes.\n    // Hover to view descriptions of existing attributes.\n    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387\n    \"version\": \"0.2.0\",\n    \"configurations\": [\n        {\n            \"name\": \"getx\",\n            \"request\": \"launch\",\n            \"type\": \"dart\"\n        },\n        {\n            \"name\": \"example\",\n            \"cwd\": \"example\",\n            \"request\": \"launch\",\n            \"type\": \"dart\"\n        },\n        {\n            \"name\": \"example_nav2\",\n            \"cwd\": \"example_nav2\",\n            \"request\": \"launch\",\n            \"type\": \"dart\"\n        },\n        {\n            \"name\": \"example_nav2 WEB\",\n            \"cwd\": \"example_nav2\",\n            \"request\": \"launch\",\n            \"type\": \"dart\",\n            \"deviceId\": \"Chrome\"\n        }\n    ]\n}"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n  \"cSpell.enableFiletypes\": [\"!markdown\"]\n}\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "## [5.0.0-release-candidate-9.3.2]\n\n- Fix pana score\n\n## [5.0.0-release-candidate-9.3.1]\n\n- Fix lint errors\n\n## [5.0.0-release-candidate-9.3.0]\n\n- Support for Flutter 3.29.0\n\n- Remove remaining dart:html references\n\n## [5.0.0-release-candidate-9.2.1]\n\n- Remove remaining dart:html references\n\n## [5.0.0-release-candidate-9.2]\n\n- Remove dart:html references\n\n## [5.0.0-release-candidate-9.1]\n\n- Add canPop to GetPage\n- Fix Get.offNamedUntil\n- Fix GetObserver\n\n## [5.0.0-release-candidate-9]\n\n- Fix redirectDelegate middleware\n- Fix Get.until\n\n## [5.0.0-release-candidate-8]\n\n- Add wasm compilation support to GetConnect\n- Refactor example\n\n## [5.0.0-release-candidate-7]\n\n- Fix latest flutter version\n\n## [5.0.0-release-candidate-6]\n\n-Fix Snackbar, upgrade to flutter 3.22 @Aniketkhote, improve parse route @korutx, fix popScope @wowbox, improve defaultDialog @leeyi, add support to wasm compilation @Ty, fix typos @CodeWithEmad, fix snackbar cancel @seungsuyoo update GetConnect @DaZealous and @ wheeOs, add bengali language @aratheunseen, fix lint issues: @MuhammamdArslanKhan\n\n## [5.0.0-release-candidate-5]\n\n-Fix nested route issues, fixed issues in the latest flutter version\n\n## [5.0.0-release-candidate-4]\n\n-Fix changeThemeMode and RxList\n\n## [5.0.0-release-candidate-3]\n\n-Fix changeTheme\n\n## [5.0.0-release-candidate-2]\n\nThis version adds built-in support for animation in Flutter in an easy, clear way, and without having to create a StatefulWidget with controllers and animations. All you need to do is call the name of the animation.\n\nIf you want to add a \"fadeIn\" effect to any widget, simply add .fadeIn() to the end of it.\n\n```dart\n Container(\n              color: Colors.blue,\n              height: 100,\n              width: 100,\n       ).fadeIn(),\n```\n\nhttps://user-images.githubusercontent.com/35742643/221383556-075a0b71-1617-4a31-a3c7-1acc68732f59.mp4\n\nMaybe you want to merge two or more animations, just concatenate them at the end of the widget.\n\n```dart\n Container(\n              color: Colors.blue,\n              height: 100,\n              width: 100,\n      ).fadeIn().bounce(begin: -0.8, end: 0.3),\n```\n\nhttps://user-images.githubusercontent.com/35742643/221383613-9044c92f-7c6b-48c4-aa79-0a0c20d4068a.mp4\n\nCreating animation sequences in Flutter is one of the most painful things to do with the framework. You need to create tons of AnimationControllers. Well, using GetX 5 you just need to tell your animation that it is sequential. Just like that.\n\n```dart\n const FlutterLogo(size: 110)\n                        .bounce(begin: -0.8, end: 0.4)\n                        .fadeIn()\n                        .spin(isSequential: true)\n                        .wobble(isSequential: true, begin: 0, end: 8)\n                        .flip(isSequential: true)\n                        .fadeOut(isSequential: true),\n```\n\nResult:\n\nhttps://user-images.githubusercontent.com/35742643/221393968-20cb2411-516b-44a7-8b85-45090bece532.mp4\n\n## [5.0.0-release-candidate]\n\nRefactor StateManager, RouteManager and InstanceManager from scratch\nFixed Bugs\nAdded a Scopped DI\nApi now uses Navigator 2\nAdded new RouteOutlet\nAdded a new futurize method to StateMixin, that tracks updates, errors, and states programatically,\n\n## [4.6.1]\n\nFix GetConnect on Flutter web\n\n## [4.6.0]\n\nAdd useInheritedMediaQuery to GetMaterialApp and GetCupertinoApp (@davidhole)\nAdd Circular reveal Transition (@parmarravi)\nAdd request to failed response (@heftekharm)\nFix internationalization with only country code (@codercengiz)\nAdd GetTickerProviderStateMixin when multiple AnimationController objects are used (@NatsuOnFire)\nAdd the followRedirects and maxRedirects fields to the Request object (@wei53881)\nFix to rx.trigger fires twice (@gslender)\nAdd proxy setting support to GetConnect (@jtans)\nFix markAsDirty used on permanent controllers (@zenalex)\nUpdate Korean readme (@dumbokim)\n\n## [4.5.1]\n\nFix Snackbar when it have action and icon the same time\n\n## [4.5.0] - Big Update\n\nTo have a page-agnostic snackbar, we used OverlayRoute to display a partial route.\nHowever this had several problems:\n\n1: There was no possibility to close the page without closing the snackbar\n2: Get.back() could cause problems with tests of Get.isSnackbarOpen not being properly invoked\n3: Sometimes when using iOS popGesture with an open snackbar, some visual inconsistency might appear.\n4: When going to another route, the snackbar was not displayed on the new page, and if the user clicked on the new route as soon as he received a Snackbar, he could not read it.\n\nWe remade the Snackbar from scratch, having its Api based on Overlay, and now opening a Snackbar won't be tied to a route, you can normally navigate routes while a Snackbar is shown at the top (or bottom), and even the PopGesture of the iOS is not influenced by it.\n\nUsing Get.back() is handy, it's a small command, which closes routes, dialogs, snackbars, bottomsheets, etc, however Getx 5 will prioritize code safety, and splitting will reduce the check code as well. Currently we have to check if a snackbar is open, to close the snackbar and prevent the app from going back a page, all this boilerplate code will be removed, at the cost of having what it closes in front of Get.back command.\n\nFor backwards compatibility, Get.back() still works for closing routes and overlays, however two new commands have been added: Get.closeCurrentSnackbar() and Get.closeAllSnackbars().\nMaybe we will have a clearer api in GetX 5, and maybe Get.back() will continue to do everything like it does today. The community will be consulted about the desired api. However version 5 will definitely have commands like: Get.closeCurrentSnackbar, Get.closeCurrentDialog etc. There is also the possibility to close a specific snackbar using the return of Get.snackbar, which will no longer return a void, and now return a SnackbarController.\n\nSnackbars now also have a Queue, and no longer stack one on top of the other, preventing viewing. GetX now has flexible, customizable, route-independent, and completely stable Snackbars.\n\nFixed bugs where the snackbar showed an error in debug mode for a fraction of a second. We found that Flutter has a bug with blur below 0.001, so we set the minimum overlayBlur value to this value if it is ==true.\n\nErrors with internationalization were also fixed, where if you are in UK, and the app had the en_US language, you didn't have American English by default. Now, if the country code is not present, it will automatically fetch the language code before fetching a fallbackLanguage.\n\nUpdate locale also now returns a Future, allowing you to perform an action only when the language has already changed (@MHosssam)\n\nWe are very happy to announce that GetX is now documented in Japanese as well, thanks to (@toshi-kuji)\n\nGetX has always been focused on transparency. You can tell what's going on with your app just by reading the logs on the console. However, these logs shouldn't appear in production, so it now only appears in debug mode (@maxzod)\n\n@maxzod has also started translating the docs into Arabic, we hope the documentation will be complete soon.\n\nSome remaining package logs have been moved to Get.log (@gairick-saha)\n\nRxList.removeWhere received performance optimizations (@zuvola)\n\nOptimizations in GetConnect and added the ability to modify all request items in GetConnect (@rodrigorahman)\n\nThe current route could be inconsistent if a dialog were opened after a transition, fixed by @xiangzy1\n\nFixed try/catch case missed in socket_notifier (@ShookLyngs)\n\nAlso we had fixes in the docs: @DeathGun3344 @pinguluk\n\nGetX also surpassed the incredible mark of more than 7000 likes, being the most liked package in all pub.dev, went from 99% to 100% popularity, and has more than 5.3k stars on github. Documentation is now available in 12 languages, and we're happy for all the engagement from your community.\n\nThis update is a preparation update for version 5, which will be released later this year.\n\nBreaking and Depreciation:\nGetBar is now deprecated, use GetSnackbar instead.\ndismissDirection now gets a DismissDirection, making the Snackbar more customizable.\n\n## [4.3.8]\n\n- Fix nav2 toNamed remove the route\n\n## [4.3.7]\n\n- Fix wrong currentRoute when a route is removed\n- Remove take that limits the router outlet depth (@steven-spiel)\n\n## [4.3.6]\n\n- Fix error with autodispose of additional dependencies beyond GetxController\n- Added ability to add your own delegate to RouterOutlet (@steven-spiel)\n- Added listenAndPump to Rx to give Rx the same behavior as BehaviorSubject (@steven-spiel)\n\n## [4.3.5]\n\n- Fix GetConnect timeout (@jasonlaw)\n- Improve Vietnamese docs (@hp1909)\n- Refactor placeholder name route to unnamed routes (@roipeker).\n- Fix: Navigate to a page identical to Get.offNamed.\n- Fix: Wrong nameRoute after a route is removed\n- Added assert to prevent the user from starting a route name without slash.\n\n## [4.3.4]\n\n- Improve docs\n\n## [4.3.3]\n\n- Fix Get.reset\n\n## [4.3.2]\n\n- Fix nullable on internacionalization (@jmguillens)\n- Fix nullable on Rx.stream (@steven-spiel)\n\n## [4.3.1]\n\n- Fix controller is not removed when keyboard is open.\n- Improved: Safe removal and insertion of controllers.\n\n## [4.3.0]\n\n- Added GetResponsiveWidget (@ahmednfwela)\n- Added `Get.replace()` (@jwelmac)\n- Added Improve korean doc (@sejun2)\n- Fix multiple middlewares redirect (@liasica)\n- Added gestureWidth and showCupertinoParallax to GetPage to customize cupertino transitions\n\n## [4.2.5]\n\n- Added anchorRoute and filterPages to GetRouterOutlet (@ahmednfwela)\n- Added scrollBehavior and scaffoldMessengerKey to GetMaterialapp(@ejabu and @alionour)\n- Fix error when child on MaterialApp is null (@ahmednfwela)\n- Fix Korean docs (@rws08)\n- Fix error with onClose called before routeTransition on Get.offNamed\n\n## [4.2.4]\n\n- Fix Get.offAll removing GetxServices from memory\n\n## [4.2.3]\n\n- Fix back button on navigator 2\n- Added parameters and arguments to Get.rootDelegate\n\n## [4.2.1]\n\n- Remove [] from docs to try fix pub score\n\n## [4.2.0] - Big update\n\nThis update fixes important bugs as well as integrates with Navigator 2. It also adds GetRouterOutlet, similar to angular RouterOutlet thanks to @ahmednfwela. Also, the documentation translation for Vietnamese (@khangahs) has been added, making the GetX documentation available for 11 different languages, which is just fantastic for any opensource project. GetX has achieved more than 5.4k likes from the pub, and more than 4k stars on github, has videos about it with 48k on youtube, and has communities in the 4 hemispheres of the earth, besides having a large list of contributors as you see bellow. We're all happy to facilitate development with dart and flutter, and that making programming hassle-free has been taken around the world.\n\nChanges in this version:\n\n- Fix: Navigating to the same page with Get.offNamed does not delete the controller from that page using Get.lazyPut.\n\n- Fix Readme GetMiddleware typos\n  by @nivisi\n\n- Fix url replace error\n  by @KevinZhang19870314\n\n- Changed response default encoding from latin1 to utf8\n  by @heftekharm\n\n- Add Duration in ExtensionBottomSheet\n  by @chanonpingpong\n\n- Added compatibility with dart-lang/mockito\n  by @lifez\n\n- Added extensions methods to convert value in percent value\n  by @kauemurakami\n\n- Set darkTheme equal theme when darkTheme is null\n  by @eduardoFlorence\n\n- Add padding to 'defaultDialog'\n  by @KevinZhang19870314\n\n- GraphQLResponse inherit Response info\n  by @jasonlaw\n\n- Fix Redundant concatenating base url\n  by @jasonlaw\n\n- Add content type and length into the headers when the content type is 'application/x-www-form-urlencoded'\n  by @calvingit\n\n- Make withCredentials configurable\n  by @jasonlaw\n\n- Fix flutter 2.0 error\n  by @yunchiri\n\n- Allow deleting all registered instances\n  by @lemps\n\n- Refactor/rx interface notify children\n  @by kranfix\n\n- Fixed parameter parsing and middleware sorting\n  by @ahmednfwela\n\n- Improvements to router outlet\n  by @ahmednfwela\n\n- Minor improvements and bug fixes\n  by @ahmednfwela\n\n- Adding route guards and improving navigation\n  by @ahmednfwela\n\n- Fix RxInterface.proxy losing its previous value on exception\n  by @WillowWisp\n\n- Added dispose() for bottomSheet.\n  by @furkankurt\n\n- Added Pull request template\n  by @unacorbatanegra\n\n- Fix and update documentation:\n  @Farid566,\n  @galaxykhh,\n  @arslee07,\n  @GoStaRoff,\n  @BondarenkoArtur,\n  @denisrudnei,\n  @Charly6596,\n  @nateshmbhat,\n  @hrithikrtiwari,\n  @Undeadlol1,\n  @rws08,\n  @inuyashaaa,\n  @broccolism,\n  @aadarshadhakalg,\n  @ZeroMinJeon\n\n## [4.1.4]\n\n- Adjust operator + and - to RxInt (@eduardoflorence)\n- Fix dark theme (@eduardoflorence)\n- Fix form-urlencoded on GetConnect (@aramayyes)\n\n## [4.1.3]\n\n- Fix \"Error: A value of type 'Locale?' can't be returned from a function\"on flutter web (@nickwri)\n- Fix plural translations to expressions >1 (@WolfVic)\n\n## [4.1.2]\n\n- Fix warning ˜can add data to a closed stream˜ when GetBuilder and Obx are nested\n- Fix get_connect decoder can not be null (@Goddchen)\n- Migrate example code (@3lB4rt0)\n- Fix initial value of nullables (@RafaRuiz)\n- Improve error message to navigation (@maxzod)\n- Fix typo on docs (@Rahulshahare)\n- Fixed darktheme being changed only through Get.changeTheme and not through the DarkTheme theme property in MaterialApp (@GoldenSoju)\n- Fix controller is removed when navigate to same page (@eduardoflorence)\n- Fix missing reload() and reloadAll() to Get extensions (@lkloon123)\n\n## [4.1.1]\n\n- Remove mandatory initialValue to nullables types\n\n## [4.1.0]\n\n- Added Rxn to non nullables reactives types\n\n## [4.0.3]\n\n- Added new linter rules to improve score\n\n## [4.0.2]\n\n- Removed \"!\" of if else conditions until the null-safety of the dart is consistent for using it.\n\n## [4.0.1]\n\n- Fix changelog\n\n## [4.0.0]\n\n- Added append function to StateMixin. Now is possible track loading, success and error handle of your application with ONE LINE OF CODE. Ex: append(()=> api.getUser);\n- Migrate to null-safety\n- Added ScrollMixin to controllers\n- Added loadingMore status to RxStatus\n- Fix content-type qual null (@katekko)\n- Made GetInstance non nullable (@eduardoflorence)\n- Fix multi-parameters url (@iMrLopez)\n- Fix Expected value of SkDeletable error (@obadajasm)\n- Added triggers, an Rx method that triggers events, even if they are the same as the previous event (@RafaRuiz)\n- Improve docs: (@CNAD666), (@dhhAndroid), (@Jackylee1992),\n\nSwitching to null-safety:\nYou can continue using GetX as normal, with as little breaking changes as possible.\nIt is still possible to declare the var.obs variable, and this remains the preferred way, forcing null-safety and giving you all the security that sound null-safety delivers to your app. However, if you need to use null, we also provide a solution for you.\nDeclare the variables with `?` Ex: `final Rx<int?> count = 0.obs`.\nYou can also use custom Rxn types with null-safety:\n`RxInt` == not nullable\n`RxnInt` == nullable.\n\n## [3.25.6]\n\n- Added documentation in French (@kamazoun)\n- Fix logs messages (@damphat)\n- Fix plural to zero on internacionalization (@RafaRuiz)\n- Fix error when body hasn't content on GetConnect (@jasonlaw)\n- Fix typos on readme (@bashleigh)\n- Fix group updates to GetBuilder\n\n## [3.25.5]\n\n- Fix Get.isDialogOpen when two or more open dialogs are closed\n\n## [3.25.4]\n\n- Added logs and tests to unknownRoute\n\n## [3.25.3]\n\n- Fix bindStream error 'Object.noSuchMethod'.\n\n## [3.25.2]\n\n- Improved Workers system to accept a list of works\n\n## [3.25.1]\n\n- Improved the log system to display the tag used in the controller that was created.\n\n## [3.25.0] - Big update\n\n- Added [reload] and [reloadAll] methods to reload your Controller to original values\n- Added [FullLifeCycleController] - A GetxController capable of observing all the life cycles of your application. FullLifeCycleController has the life cycles:\n  - onInit: called when the controller enters the application's memory\n  - onReady: called after onInit, when build method from widget relationed to controller is done.\n  - onClose: called when controller is deleted from memory.\n  - onPaused: called when the application is not currently visible to the user, and running in the background.\n  - onInactive: called when the application is in an inactive state and is not receiving user input, when the user receives a call, for example\n  - onResumed: The application is now visible and in the foreground\n  - onDetached: The application is still hosted on a flutter engine but is detached from any host views.\n  - didChangeMetrics: called when the window size is changed\n- Added SuperController, a complete life circle controller with StateMixin\n- Improve Iterable Rx Api. Now, you can to use dart List, Map and Set as reactive, like: List<String> names = <String>['juan', 'pedro', 'maria'].obs;\n- Added assign and assignAll extensions to default dart List\n- Added parameters options from Get.toNamed, Get.offNamed, and Get.offAllNamed (@enghitalo)\n- Improve Rx disposal logic to completely prevent memory leaks\n- Improve Capitalize methods from GetUtils (@eduardoflorence)\n- Prevent a close snackbar from close a Screen with double tap (@eduardoflorence)\n- Includes GetLifeCycleBase mixin on delete/dispose (@saviogrossi)\n- Added internacionalization example to sample app (@rodriguesJeff)\n- Added headers to Graphql query and mutation(@asalvi0)\n- Added translation with parameter extension (@CpdnCristiano)\n- Added Get.parameter access to Middleware (@eduardoflorence)\n- Fix RxBool typo (@emanuelmutschlechner)\n- Added Filter to GetBuilder\n- Added debouce to GetBuilder update\n- Added ability to insert an Enum, class, or type of an object as a GetBuilder's Id\n- Improve upload time from GetConnect\n- Create minified version to DartPad(@roipeker)\n- Suggested to use `Get.to(() => Page())` instead of `Get.to(Page())`.\n- Added more status codes to GetConnect (@romavic)\n- Fix and improve docs: @unacorbatanegra, @lsm, @nivisi, @ThinkDigitalSoftware, @martwozniak, @UsamaElgendy, @@DominusKelvin, @jintak0401, @goondeal\n\n## [3.24.0]\n\n- GetWidget has been completely redesigned.\n  Throughout its lifetime, GetWidget has always been mentioned in the documentation as \"something you shouldn't use unless you're sure you need it\", and it had a very small use case. A short time ago we realized that it could have some unexpected behaviors, when compared to GetView, so we decided to rebuild it from scratch, creating a really useful widget for the ecosystem.\n  Objectively, GetWidget is now a Widget that caches the controller and protects children from their parents' reconstructions. This means that if you have a ListView or gridview, you can add items to it without the child (being a GetWidget) being rebuilt. The api is now more concise, as you can use Get.put / Get.lazyput for global dependencies, and Get.create with GetWidget for ephemeral dependencies, or when you need several identical controllers for the same widget, eliminating the need for tags for most cases.\n\n- Workers now have error handlers, so if an error occurs in your stream, you can recover it from your workers.\n\n- `isTrue` and `isFalse` setters were added to [RxBool], this will make the code more readable, and will mitigate the use of \".value\" in Booleans.\n\n- [Patch] method was added in GetConnect.\n\n- Native methods for RxString (trim, contains, startWith, etc.) have been added.\n- Standard constructors for RxList and RxMap have been added (RxList.generate, RxList.from, Map.of, Map.from, etc).\n\n- Added \"onEmpty\" status in StateMixin (@alizera)\n\n- Added query and mutation methods of graphql for getconnect.\n- Added body string for content-type application/x-www-form-urlencoded on GetConnect (@eduardoflorence)\n\n## [3.23.1]\n\n- Fix allowSelfSigned on Flutter web\n\n## [3.23.0]\n\n- Add GetResponsive (@SchabanBo)\n- Update tests, fix predicate for offNamedUntil (@vbuberen)\n- Added Urdu Version for Pakistani Developers (@UsamaSarwar)\n- Handle for List field with native datatype on GetConnect(@jasonlaw)\n- Added WillPopScope to defaultDialog (@rakeshlanjewar)\n- Fix optional query params not attach on createUri from GetConnect (@reinaldowebdev)\n- Effective Get.testMode from navigator on tests (@eduardoflorence)\n- Fix Navigator 2.0 on GetMaterialApp and CupertinoMaterialApp (@SchabanBo)\n- Added Middlewares with initial Routes (@SchabanBo)\n- Improve PT-br Docs (@eduardoflorence)\n- Added the allowSelfSigned parameter to GetSocket(@eduardoflorence)\n- Added Indonesian version to Indonesian Developers (@pratamatama)\n\n## [3.22.2]\n\n- Fix overlayEntries is null on Master/Dev branch of Flutter\n\n## [3.22.1]\n\n- Improve: auto jsonDecode occurs only if response.header.contentType is \"application/json\"\n- Improve and fix requests types (@eduardoflorence)\n- Fix HeaderValue variables with same name (@haidang93)\n\n## [3.22.0]\n\n- Added: more multipart options. Now you can send as multipart:\n\nFile:\n'file':MultipartFile(File('./images/avatar.png'), filename: 'avatar.png'),\n\nString path:\n'file':MultipartFile('./images/avatar.png', filename: 'avatar.png'),\n\nOr bytes (Flutter web work only with bytes):\n'file':MultipartFile(File('file').readAsBytesSync(), filename: 'avatar.png'),\n\n- Added: Upload Progress to MultipartRequest\n- Added support to List<MultipartFile> (@jasonlaw)\n\n## [3.21.3]\n\n- Improve multipart file and defaultDecoder on GetConnect\n\n## [3.21.2]\n\n- Fix GetConnect.request returning a PUT request\n\n## [3.21.1]\n\n- Allow null body to POST method on GetConnect\n\n## [3.21.0] - Big update\n\n- This update attaches two nice features developed by (@SchabanBo): _GetPage Children_ And _GetMiddleware_\n  In previous versions, to create child pages, you should do something like:\n\n```dart\nGetPage(\n  name: '/home',\n  page: () => HomeView(),\n  binding: HomeBinding(),\n),\nGetPage(\n  name: '/home/products',\n  page: () => ProductsView(),\n  binding: ProductsBinding(),\n),\nGetPage(\n  name: '/home/products/electronics',\n  page: () => ElectronicsView(),\n  binding: ElectronicsBinding(),\n),\n```\n\nAlthough the feature works well, it could be improved in several ways:\n1- If you had many pages, the page file could become huge and difficult to read. Besides, it was difficult to know which page was the daughter of which module.\n2- It was not possible to delegate the function of naming routes to a subroutine file.\nWith this update, it is possible to create a declarative structure, very similar to the Flutter widget tree for your route, which might look like this:\n\n```dart\nGetPage(\n      name: '/home',\n      page: () => HomeView(),\n      binding: HomeBinding(),\n      children: [\n        GetPage(\n            name: '/products',\n            page: () => ProductsView(),\n            binding: ProductsBinding(),\n            children: [\n              GetPage(\n                 name: '/electronics',\n                 page: () => ElectronicsView(),\n                 binding: ElectronicsBinding(),\n              ),\n            ],\n          ),\n      ],\n  );\n```\n\nThus, when accessing the url: '/home/products/electronics'\nOr use Get.toNamed('/home/products/electronics') it will go directly to the page [ElectronicsView], because the child pages, automatically inherit the name of the ancestral page, so _with any small change on any father in the tree all children will be updated._ If you change [/products] to [/accessories], you don't nesse update on all child links.\n\nHowever, the most powerful feature of this version is _GetMiddlewares_.\nThe GetPage has now new property that takes a list of GetMiddleWare than can perform actions and run them in the specific order.\n\n### Priority\n\nThe Order of the Middlewares to run can pe set by the priority in the GetMiddleware.\n\n```dart\nfinal middlewares = [\n  GetMiddleware(priority: 2),\n  GetMiddleware(priority: 5),\n  GetMiddleware(priority: 4),\n  GetMiddleware(priority: -8),\n];\n```\n\nthose middlewares will be run in this order **-8 => 2 => 4 => 5**\n\n### Redirect\n\nThis 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.\n\n```dart\nGetPage redirect( ) {\n  final authService = Get.find<AuthService>();\n  return authService.authed.value ? null : RouteSettings(name: '/login')\n}\n```\n\n### onPageCalled\n\nThis function will be called when this Page is called before anything created\nyou can use it to change something about the page or give it new page\n\n```dart\nGetPage onPageCalled(GetPage page) {\n  final authService = Get.find<AuthService>();\n  return page.copyWith(title: 'Welcome ${authService.UserName}');\n}\n```\n\n### OnBindingsStart\n\nThis function will be called right before the Bindings are initialize.\nHere you can change Bindings for this page.\n\n```dart\nList<Bindings> onBindingsStart(List<Bindings> bindings) {\n  final authService = Get.find<AuthService>();\n  if (authService.isAdmin) {\n    bindings.add(AdminBinding());\n  }\n  return bindings;\n}\n```\n\n### OnPageBuildStart\n\nThis function will be called right after the Bindings are initialize.\nHere you can do something after that you created the bindings and before creating the page widget.\n\n```dart\nGetPageBuilder onPageBuildStart(GetPageBuilder page) {\n  print('bindings are ready');\n  return page;\n}\n```\n\n### OnPageBuilt\n\nThis 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.\n\n### OnPageDispose\n\nThis function will be called right after disposing all the related objects (Controllers, views, ...) of the page.\n\n## [3.20.1]\n\n- Fix wrong reference with unnamed routes and added more tests\n\n## [3.20.0] - Big update\n\n- Added GetConnect.\n\n* GetConnect is an easy way to communicate from your back to your front. With it you can:\n* Communicate through websockets\n* Send messages and events via websockets.\n* Listen to messages and events via websockets.\n* Make http requests (GET, PUT, POST, DELETE).\n* Add request modifiers (like attaching a token to each request made).\n* Add answer modifiers (how to change a value field whenever the answer arrives)\n* Add an authenticator, if the answer is 401, you can configure the renewal of your JWT, for example, and then it will again make the http request.\n* Set the number of attempts for the authenticator\n* Define a baseUrl for all requests\n* Define a standard encoder for your Model.\n* Note1: You will never need to use jsonEncoder. It will always be called automatically with each request. If you define an encoder for your model, it will return the instance of your model class ALREADY FILLED with server data.\n* Note2: all requests are safety, you do not need to insert try / catch in requests. It will always return a response. In case of an error code, Response.hasError will return true. The error code will always be returned, unless the error was a connection error, which will be returned Response.hasError, but with error code null.\n* These are relatively new features, and also inserted in separate containers. You don't have to use it if you don't want to. As it is relatively new, some functions, such as specific http methods, may be missing.\n\n- Translation to Korean (@rws08)\n- Fix Overlays state (@eduardoflorence)\n- Update chinese docs (@jonahzheng)\n- Added context.isDarkMode to context extensions\n\n## [3.17.1]\n\n- Allow list.assignAll, map.assignAll and set.assignAll operate with null values\n\n## [3.17.0]\n\n- Added GetCupertinoApp\n- Added initial suport to navigator 2.0\n\n## [3.16.2]\n\n- Clean RxList, RxMap and RxSet implementation\n- Now when declaring an `RxList()`, it will be started empty. If you want to start a null RxList, you must use `RxList(null)`.\n  Improved GetStream to receive the same parameters as the StreamController, such as `onListen`, `onPause`, `onResume` and `onCancel`.\n- Improve docs\n\n## [3.16.1]\n\n- Fix compilation error on master\n\n## [3.16.0]\n\n- Documentation translated into Russian language. (@Renat Fakhrutdinov, @Doaxan and @BatttA)\n- Added error message callback for StateMixin (@eduardoflorence)\n- Fix incorrect Get.reference when pop route (@4mb1t)\n- Added Uppercase/Capital letter on GetUtils (@AleFachini)\n- Redraw the Streams api to use GetStream instead of StreamControllers. Why this change?\n  Dart provides a Streams API that is really rich. However, asynchronous streams add extra latency to ensure that events are delivered in the exact order.\n  It is not yet known whether this latency has any performance impact in mobile applications, and probably not, however, as GetX is also a server-side framework, we need to have the lowest latency at all, since our base is shared.\n  Dart also has a Synchronous Streams api that has very low latency, however, it is not suitable for use in state management for two reasons:\n  1- Synchronous Streams can only have one listen (see the issue opened by Hixie on dart lang for reference: https://github.com/dart-lang/sdk/issues/22240).\n  This means that we cannot use this api for more than one listener, which is the basis of global state management, where we aim to change the state of more than one location. You can test this with this simple snippet:\n\n```dart\nvoid main() {\n  var controller = StreamController(sync: true);\n  var stream = controller.stream;\n  stream.listen((data) {\n    print('$data');\n    if (data == 'test4') controller.add('test5');\n  });\n\n  print('test1');\n  controller.add('test2');\n  stream.listen((event) {}); // second listen throws a exception\n  print('test3');\n  controller.add('test4');\n  print('test6');\n  controller.add('test7');\n  print(\"test8\");\n}\n```\n\n2- Even with a single listener, the dart's Synchronous Streams api cannot deliver events in the exact order. We plan to work on a PR in the future at dart-lang to address this. So if we remove the line above that causes the exception, we will have the following output in the log:\n\n```dart\nvoid main() {\n  var controller = StreamController(sync: true);\n  var stream = controller.stream;\n  stream.listen((data) {\n    print('$data');\n    if (data == 'test4') controller.add('test5');\n  });\n\n  print('test1');\n  controller.add('test2');\n  // stream.listen((event) {}); // second listen throws a exception\n  print('test3');\n  controller.add('test4');\n  print('test6');\n  controller.add('test7');\n  print(\"test8\");\n}\n///////////////////// log:\ntest1\ntest2\ntest3\ntest4\ntest6\ntest8\ntest5\n\n```\n\nAs we can see, test 4 skips to test 6, which skips to test 8, which skips to test 5. Note that test 7 didn't even appear in the log.\n\nHowever, if we work with GetStream, everything works as expected:\n\n```dart\nvoid main() {\n  var controller = GetStream();\n  var stream = controller.stream;\n  stream.listen((data) {\n    print('$data');\n    if (data == 'test4') controller.add('test5');\n  });\n\n  print('test1');\n  controller.add('test2');\n  // stream.listen((event) {}); // second listen throws a exception\n  print('test3');\n  controller.add('test4');\n  print('test6');\n  controller.add('test7');\n  print(\"test8\");\n}\n///////////////////// log:\ntest1\ntest2\ntest3\ntest4\ntest5\ntest6\ntest7\ntest8\n\n```\n\nThe dart documentation is clear that this api should be used with caution, and in view of these tests, we were sure that it is not stable enough to be used as the core of our state management, nor of the websockets notifications and get_server requests.\n\nClarification about the controversy over benchmarks:\nIn a version prior to changeLog, we talked about the 9000% difference in performance between Streams, and GetStreams that ended up causing a lot of controversy in the community.\nInitially, we would like to clarify that this does not mean that you will have mobile applications 9000% faster. Only that one of our main resources, showed itself with a high rate of requests, 9000% faster than using traditional streams. In a real world scenario, you will hardly have so many simultaneous requests.\nSkia renders frames on new devices at up to 120fps. This means that if you have a 10 second animation, you will have 1200 reconstructions. Unless you are working with animations, or something that requires rendering at the skia boundary, you won't need that much power. So this does not mean that we are revolutionizing the mobile world, only that we have created an alternative to Stream Sincronas, which works as expected, and which has satisfactory performance for low latency resources. The benchmarks are real, but that does not mean that you will have mobile applications 9000% faster, but that you have a new feature that performs at this level to use.\nFor reference only, the benchmark can be found ([HERE](https://github.com/jonataslaw/getx/blob/master/test/benchmarks/benckmark_test.dart))\n\nIn short: asynchronous streams from dart work perfectly, but add a latency that we want to remove on Get_server.\nSynchronous dart streams have unexpected behaviors, cannot have more than 1 listener and do not deliver events in the correct order, which completely prevents their use in mobile state managements, since you run the risk of displaying data on the wrong screen, since the last event will not always be the last event entered by the sink.\nThe 9000% figures are real, however, they refer to the gross performance between Streams and GetStreams. This does not mean that this number will impact your applications, because you are unlikely to use all of that power.\n\n## [3.15.0] - Big update\n\n- **Improve Performance**: We made modifications to make GetBuilder even faster. We have improved the structure behind it so that listeners are notified faster. Perhaps in version 4.0 everything will be based on this new structure, but maintaining the power and compatibility with streams. If you want to know how much Getx is faster than pure streams or ChangeNotifier (even after the last update using LinkedList), you can create run the repository tests at: (https://github.com/jonataslaw/getx/blob/master/test/benchmarks/benckmark_test.dart)\n- **Added StateMixin**\n  StateMixin allows you to change the state of the controller, and display a loading, an error message, or a widget you want with 0 boilerplate. This makes things like API/Rest communication or websocket absurdly simple, and it's a real revolution in how state management has behaved so far.\n  You no longer need to have a ternary in your code, and you don't need a widget like FutureBuilder, StreamBuilder or even Obx/GetBuilder to encompass your Visibility. This will change with the way you manage the state of your controllers, decrease your boilerplate absurdly, and give you more security in your code.\n- **Added GetNotifier**\n  GetNotifier is a super and powerful ValueNotifier, which in addition to having the life cycle of the controllers, is extremely fast, and can manage a single state, as a simplified immutable state management solution.\n  In theory, the only difference between it and GetxController is the possibility of setting an initial value in the constructor's super (exactly as ValueNotifier does). If the initial value is null, use GetxController. If you need a starting value, GetNotifier can be more useful and have less boilerplate, but both serve the same purpose: to decouple your visualization layer from your presentation logic.\n- Other Fixes and improvements:\n  - Fixed GetxController is closed twice when smartManagement.full is turn on\n  - Fixed phone number validation\n  - Fixed some inconsistencies in GetWidget and the life cycle of controllers\n  - It made controller testing completely safe with navigation.\n  - Improve docs (@eduardoflorence)\n  - Improve security types on routes (@unacorbatanegra)\n  - Improve code structure with less duplicate code: (@kranfix)\n  - Fix named route erroring when route does not exist (@FiercestT)\n\n## [3.13.2]\n\n- Reunification of the package.\n  During the 2 week period, we try to keep this package as a compilation of smaller packages. We were successful in separating, getx is well decoupled and it was only necessary to send the internal folders as packages to pub.dev, however, it became very complicated to contribute to the package. This is because it was necessary to clone the repository, replace all pubspec packages with local paths, and after modification, return the original paths to do the PR. With that, the frequency of updates, which was about 4 to 5 days, became almost 2 weeks, and this is not legal for a community as active as Getx, which uses this package precisely in addition to being modern and performance, be constantly improving. This led contributors to the conclusion that getx works best together.\n  Additional packages will continue to be maintained, and will have the same base as the main package, however, development will take place in the full and main package, and as the addition of new features or bug fixes arrives, we will migrate to the individual packages . Getx reached the mark of 50 contributors today, more than 1500 likes in the pub, and will continue to make development easy.\n\n## [3.13.1]\n\n- Remove spaces whitespaces from dart files\n-\n\n## [3.13.0]\n\n- Fix typos on code and docs (@wbemanuel and @Goddchen)\n- Improve: typedef to GetBuilder and Getx widgets\n- Improve behaviour of null route on lastest flutter version (@FiercestT)\n- Fix onReady called twice on smartManagement.onlyBuilders\n- Fix onClose called twice when GetBuilder is used\n- Fix default customTransitions, and defaultDuration be ignored on unnamedRoutes\n- Transition.native use default Flutter transitions\n- Added Get.testMode to use contextless elements on unit tests\n- Added Get.appUpdate and improve Get.forceAppUpdate\n\n## [3.12.1]\n\n- Remove spaces whitespaces from dart files\n\n## [3.12.0]\n\n- Added BottomSheet Duration && Export SingleGetTickerProvider (@unacorbatanegra)\n- Improve docs from dependencies management (@ngxingyu)\n- Fix unknownRoute with null Custom Transition (@marcosfons)\n- Optimize capitalize method (@zl910627)\n- Added Chinese documentation (@idootop)\n- Added TextDirection property on GetMaterialApp to improve RTL layout (@justkawal)\n- Remove unnecessary files on git (@nipodemos)\n- Fix tags on Get.create() and GetWidget() (@roipeker)\n- Update mockito dependency on getTests\n- Added GetStatelessWidget, a StatelessWidget base to GetWidget with lifecycle control of controllers. Note: It's a base class, you don't need change to use it or change your GetView, GetWidget StatelessWidget to It.\n\n## [3.11.1]\n\n- Fix docs\n\n## [3.11.0]\n\n- Refactor structure from scratch to split GetX completely into separate packages. When using the main package (get) you will have everything working perfectly together. However, if you only want one of the resources, you can use the packages separately.\n- Improve Rx types\n- Added RTL support\n- Added GetTests, a set of tools to help you create unit tests using Getx\n- RAM consumption improved by dividing resources into smaller components, preventing related classes that are unnecessary from being loaded\n- Fix example app (missing activity) (@Grohden)\n- Added Get.create() lifecycle (@roipeker)\n- Added section Contribution videos and articles in Readme (@stefandevo)\n- fix isNullOrBlank extension\n- Added all operators overload (@grohden)\n- Fixes subscription for Rx::bindStream (@roipeker)\n- Added Ability to use tags with GetX widgets (@na2axl)\n- Change Arguments from Object to dynamic (@roipeker)\n- Added Persistent bottomsheet (@mohak852)\n- Improve extensions tests (@Nipodemos)\n- Refactor Route Observer (@grohden)\n- Added print extensions (@unacorbatanegra)\n- Update PT-br Readme (@eduardoflorence)\n- Fix analyzer crash (@eduardoflorence)\n- Fix for switch types usages in GetUtils (@grohden)\n- Improvement: RxList, RxSet and RxMap null check in the constructor (@Hitsu91)\n- Improve readme example (@dafinoer)\n\n## [3.10.2]\n\n- Fixed the use of tags with lazyPut and added Ability to overwrite \"tag\" in GetView and GetWidget.\n\n## [3.10.1]\n\n- Fix analyzer\n\n## [3.10.0]\n\nGetx 3.10 released with CLI and Get Server.\n\n- Added: analyser + effective dart (@Grohden)\n- Added TextStyle to generalDialog title and message (@roipeker)\n- renamed and added defaults transition duration and types in \"GetInterface\" (@roipeker)\n- added missing parameters in Get.to/Get.offAll (@roipeker)\n- added optional transitionDuration and transitionCurve to Get.dialog() (@roipeker)\n- Changed HashMap<int,GetStateUpdate> to HashSet<GetStateUpdate> and allow update IDs groups on GetBuilder (@roipeker)\n- Added a internal VoidCallback in GetStateUpdaterMixin::getUpdate (@roipeker)\n- Added Curve property to routes (@roipeker)\n- Improve docs, code cleanup, new GetStateUpdaterMixin and GetStateUpdate in favour of StateSetter on GetxController, GetBuilder, SimpleBuilder. (@roipeker)\n- Added RxBool.toggle() as an easy shortcut for switching true/false values. (@roipeker)\n- Added \\_RxImp.nil() to easily set the value to null (@roipeker)\n- Added missing docs to Rx classes. (@roipeker)\n- Added Get.delete(force:false) to Get extensions (@roipeker)\n- Added Docs and comments (@nipodemos)\n- Added docs to PT-br and fix typos (@eduardoflorence)\n- Cleanup route code (@justkawal)\n- Extension to facilitate insert widgets inside a CustomScrollView (@alexkharech)\n- Fix docs .obs examples (@kai-oswald)\n- Added tag capability to GetView\n- Improve code separation of RouteManagement and Internacionalization\n\n## [3.8.0]\n\n- Added: Snackbar Status: Open, Opening, Closing and Closed\n  example:\n\n```dart\n Get.snackbar('title', 'message', snackbarStatus: (status) {\n                  if (status == SnackbarStatus.CLOSED) {\n                    // made anything\n                  }\n                });\n```\n\n## [3.7.0]\n\n- Added: RxSet. Sets can now also be reactive.\n- Added isDesktop/isMobile (@roipeker)\n- Improve GetPlatform: It is now possible to know which device the user is using if GetPlatform.isWeb is true.\n  context.responsiveValue used device orientation based on web and non-web applications. Now it checks if it is a desktop application (web or desktop application) to do the responsiveness calculation. (@roipeker)\n- Change: The documentation previously stated that Iterables should not access the \".value\" property.\n  However, many users did not pay attention to this fact, and ended up generating unnecessary issues and bugs in their application.\n  In this version, we focus on code security. Now \".value\" is protected, so it cannot be accessed externally by Lists, Maps or Sets.\n- Change: Observable lists are now Dart Lists.\n  There is no difference in your use:\n  `RxList list = [].obs;`\n  And you use\n  `List list = [].obs;`\n- Change: You do not need to access the \".value\" property of primitives.\n  For Strings you need interpolation.\n  For num, int, double, you will have the normal operators, and use it as dart types.\n  This way, `.value` can be used exclusively in ModelClasses.\n  Example:\n\n```dart\nvar name = \"Jonny\" .obs;\n// usage:\nText (\"$name\");\n\nvar count = 0.obs;\n// usage:\nincrement() => count ++;\nText(\"$count\");\n```\n\nThus: List, Map, Set, num, int, double and String, as of this release, will no longer use the .value property.\n\nNOTE:\nThe changes were not break changes, however, you may have missed the details of the documentation, so if you faced the message: \"The member 'value' can only be used within instance members of subclasses of 'rx_list.dart' \"you just need to remove the\" .value \"property from your list, and everything will work as planned.\nThe same goes for Maps and Sets.\n\n## [3.6.2]\n\n- Fix more formatting issues\n\n## [3.6.1]\n\n- Fix formatting issues\n\n## [3.6.0]\n\n- Added RxSet\n- Change default logger to developer.log (@jorgegaticav)\n- Added BindingsBuilder, ValueBuilder, and ObxValue (@roipeker)\n- Fix fallback locale not working if missing country code (@thaihuynhxyz)\n- Fix validation of email \".com.br\"\n\n## [3.5.1]\n\n- Remove unnecessary whitespaces\n\n## [3.5.0]\n\n- Added logwritter (@stefandevo)\n- Added responsiveValue (@juanjoseleca)\n- Fixed ghost url for snackbar, bottomsheets, and dialogs and unnamed navigation.\n\n## [3.4.6]\n\n- Fix TextField dispose throw on last Flutter hotfix\n\n## [3.4.5]\n\n- Fix typo on RxList.remove that could cause type errors.\n- Remove initialization console print\n\n## [3.4.4]\n\n- Fix exception 'isInit called null' when tags are used in conjunction with dependencies. (@djade007)\n- Fix typos (@tiagocpeixoto)\n\n## [3.4.3]\n\n- Fix onInit fired only first time\n- Fix language callback(@lundin)\n- Fix docs (@nipodemos)\n\n## [3.4.2]\n\n- Fix individual imports\n\n## [3.4.1]\n\n- Structure organization, and improvements.\n\n## [3.4.0]\n\n- Added '[everAll]' Worker: Listen a List of '.obx'\n- Added Workers dispose\n- Fix transition.noTransition\n- Fix TextField and VideoPlayController dispose before transition animation\n\n## [3.3.0]\n\n- Fix extensions (@stefandevo)\n- Added CPF to utils options (@kauemurakami)\n- Added fenix mode to Get.lazyPut.\n  Use `Get.lazyPut<Controller>(()=> Controller(), fenix:true)` to have a controller that after being destroyed, has the ability to be recreated in case someone needs it. This is a function that already exists in smartManagement.keepFactory which is now also possible in full mode.\n- Fix native transition on android\n\n## [3.2.2]\n\n- Improve transitions and refactor route system\n\n## [3.2.1]\n\n- Prevent black blackground on cupertino fullscreenDialog\n\n## [3.2.0]\n\n- Improve GetBuilder ram usage\n- Added method update to Rx\n  Now you no longer need to make an entire class reactive to get an element update from it, you can simply call the update method of its instance, like this:\n\n```dart\nclass User{\n  User(this.name = '', this.age = 0);\n  String name;\n  int age;\n}\n\nfinal user = User().obs;\n\nObx(()=> Text(\"Name ${user.value.name}: Age: ${user.value.age}\"))\n\n// To update:\nuser.update((user){\nuser.name = 'Jonny';\nuser.age = 18;\n});\n```\n\nNow is also possible to access a value without using the \".value\". Just open and close parentheses.\nIn the previous example, you could do:\n\n```dart\nuser().name; // before: user.value.name\n```\n\nAnd it is also possible to set a value without using the value, inserting the value directly into the variable.\n\n```dart\nuser(User('João', 35)); // before: user.value = User('João', 35)\n```\n\nAdded fenix mode to Get.lazyPut.\n\n## [3.1.4]\n\n- Update readme banner\n\n## [3.1.3]\n\n- Activate unknownRoute on version 3\n- Go back transitions.size and transitions.cupertino\n\n## [3.1.2]\n\n- Expose GetInstance\n\n## [3.1.1]\n\n- Improvement .obs methods\n\n## [3.1.0]\n\n- Added extensions to GetUtils and fix typo on GetUtils.isEmail (@stefandevo)\n- Added .gitignore file (@hdeyana)\n\n## [3.0.1]\n\n- Breaking changes on Rx api and GetController and RxController were merged, and now you only have the 'GetxController'\n- Refactor routing system. Now you can add custom transitions and more\n- Improved the use of dynamic routes, you can now define two different pages according to your arguments.\n- Added GetView widget\n- Added internacionalization\n- Added validations\n- Added Get queqe\n- Added GetStorage (with separated package)\n- Minor bug fixes.\n\n## [2.14.0]\n\n- Added getPages API.\n- Deprecated namedPages\n- Fix default transition\n- Added Duration on Get.offAll(@kluverua)\n\n## [2.13.1]\n\n- Added sort to ListX\n- Prepared the framework for version 3\n\n## [2.13.0]\n\n- Added Get.focusScope\n\n## [2.13.0]\n\n- Update docs\n- Fix Bindings list on GetPageRoute\n\n## [2.12.5]\n\n- Update readme\n\n## [2.12.4]\n\n- Prevent exceptions on onReady with nullables\n\n## [2.12.3]\n\n- Fix List lenght == null\n\n## [2.12.2]\n\n- Fix Workers\n\n## [2.12.1]\n\n- Added: onReady on Controllers LifeCycle\n- Added: Observable maps\n- Refactor: observable variables that now consume even less RAM.\n\n## [2.11.3]\n\n- Type parameters and added docs\n\n## [2.11.2]\n\n- Added docs\n- Improvement performance of Obx\n\n## [2.11.1]\n\n- Fixed: oninit calling only once.\n\n## [2.11.0]\n\n- Added Permissions:\n  You can now revoke permissions to SmartManagement so that it cannot delete a particular controller.\n  Add to Get.put (Controller(), permanent: true); to make it indelible.\n  Get.lazyPut() will not receive this resource. Initially he had it, but we saw in internal tests that it could cause problems with the bindings API. Bindings were created to initialize and delete an instance, if it were allowed to make a controller started with lazyPut permanent, copies of that Controller would be created every time Binding was called. For the safety of users, especially new users who could easily do this, it was decided that this feature will only be present in Get.put.\n- Improve: Now a controller's life cycle has no connection with the View life cycle. It is no longer called internally in an \"initState\", it is now called when the Controller enters memory. This means that now onInit will always be called, regardless of where you started your dependency.\n- removed: this property of the update() method has been permanently removed.\n\n## [2.10.3]\n\n- GetBuilder refactor. 11% reduction in RAM consumption and 2% in CPU consumption for the sample application. (using as base Flutter for linux desktop).\n\n- The \"this\" property of the \"update\" method has been deprecated and will be removed in the next update. Please don't use it anymore. Just use \"update()\" now.\n\n## [2.10.2]\n\n- Fix Get.generalDialog default options\n\n## [2.10.1]\n\n- Fix broken links on pub\n- Fix List empty error\n\n## [2.10.0]\n\n- Added SmartManagement, your application's memory is managed intelligently like never before!\n- Added Obx, a widget that knows when to rebuild a child, without needing any type.\n- Added MixinBuilder - If you need to use GetBuilder in conjunction with GetX, use GetxController with this widget, and the changes will occur either using update (this) or changing some reactive variable. Use only if necessary, for better RAM consumption, prefer widgets in that order:\n  Obx => GetX => GetBuilder => MixinBuilder.\n  Obx is the lightest of all, and MixinBuilder is a mix of the other 3, whenever possible, use the specific widget.\n- Refactor: StateManager of Get.\n- Changed: full List API refactor, now value is no longer needed.\n- Added Workers: You can hear changes to a variable and trigger custom callbacks.\n- Added Bindings API docs.\n- Added Portuguese language to readme(@Nipodemos)\n\n# [2.7.1]\n\n- Improve list to set and get methods\n\n## [2.7.0]\n\n- Added obx, a simple state interceptor.\n- Improve Bindings, ListX, and\n- fix docs typos e broken code (@ghprod)\n\n## [2.6.3]\n\n- Flutter currently has a problem on some devices where using showModalBottomSheet() can cause TextFields to be hidden behind the keyboard (https://github.com/flutter/flutter/issues/18564) this issue is closed, even users reporting that the problem still occurs.\n  The problem happens casually, as well as the problem of the snackbar on the iPhone SE 2, and checking the code, I realized that a padding with MediaQuery.of(context).viewInsets.bottom is missing inside the bottomSheet to make it work correctly, since it does not have any constraint with the keyboard.\n  For stability, I decided not to use the standard Flutter bottomSheet, which contains many bugs, mainly related to keyboard padding, and the lack of respect for topBar's safeArea, and to use a proprietary bottomSheet implementation that is more stable. The Flutter dialog has no problem, so it will be used as the basis for Get.dialog. The bottomSheet will be based on the Flutter bottomSheet Raw API (\\_ModalBottomSheetRoute), applying bug fixes.\n- Added Get.isSnackbarOpen tests\n\n## [2.6.2]\n\n- Refactor Bindings API\n\n## [2.6.1]\n\n- Expose Bindings API\n\n## [2.6.0]\n\n- Added bindings.\n  You can now add bindings from your controllers to your routes, to prepare GetBuilder or GetX to create a dependency already declared in a Binding class. This feature is in an experimental phase, and will not be documented until the end of the tests.\n\n## [2.5.10]\n\n- Removed remnants of previousArgs on routeObserver.\n  This feature had been deprecated in previous updates, and was removed in version 2.5.8. Some remaining references on the routeObserver were causing exceptions in version 2.5.9, and were removed completely in version 2.5.10.\n\n## [2.5.9]\n\n- Fix Get.find with named instance\n\n## [2.5.8]\n\n- Added docs\n- Added tests(@chimon2000)\n\n## [2.5.7]\n\n- Fix Get.generalDialog optionals\n- Added GetX onInit support\n\n## [2.5.6]\n\n- GetBuilder refactor to work with lazyPut.\n  Now you can list your controllers in advance with Get.lazyPut, and only when it is called for the first time will it be relocated in memory.\n- Fix english typos(@gumbarros)\n\n## [2.5.5]\n\n- Fix arguments broken by new methods\n\n## [2.5.4]\n\n- Refactor methods\n\n## [2.5.3]\n\n- Fix snackbar padding on iPhone SE 2.\n- Added themes docs\n- Added ThemeMode (@RodBr)\n\n## [2.5.2]\n\n- Fix: key not found when Get.key is used with no MaterialApp\n\n## [2.5.1]\n\n- Improve - GetBuilder uses 18% less ram on more of 20 controllers.\n\n## [2.5.0]\n\n- Added List.obs\n- Now you can transform any class on obs\n\n## [2.4.0]\n\n- Added GetX, state manager rxDart based.\n- Fix error on add for non global controllers\n\n## [2.3.2]\n\n- Fix close method called on not root GetBuilder\n\n## [2.3.1]\n\n- Auto close stream inside close method\n- Added docs\n\n## [2.3.0]\n\n- Added interface to GetX support\n\n## [2.2.8]\n\n- Added api to platform brightness\n\n## [2.2.7]\n\n- Fix typos\n\n## [2.2.6]\n\n- Fix cancel button on defaultDialog don't appear when widget implementation usage\n\n## [2.2.5]\n\n- Refator defaultDialog\n\n## [2.2.4]\n\n- Clean code\n- Fix Get.LazyPut\n\n## [2.2.3]\n\n- Remove defaultDialog type\n\n## [2.2.2]\n\n- Fix GetRoute not found\n\n## [2.2.1]\n\n- Improve lazyPut and fix tag to lazyput(@rochadaniel)\n\n## [2.2.0]\n\n- Added: Ability to choose or delay a widget's state change according to its ID.\n- Added: Ability to fire triggers when loading materialApp.\n- Added: Ability to change theme dynamically.\n- Added: Ability to rebuild the entire app with one command.\n- Added: Ability to trigger events on the MaterialApp.\n- Added: Get.lazyPut (lazy loading of dependencies).\n- Added: Get.creator - a factory of dependencies .\n- Added: Capability of define abstract class on dependencies.\n\n## [2.1.2]\n\n- Get.defaultDialog refactor\n\n## [2.1.1]\n\n- fix typo\n\n## [2.1.0]\n\n- Added Get.rawSnackbar\n- Added instantInit config to snackbars\n- Refactor Get Instance Manager\n- Improved performance and bug fix to Get State Manager\n- Improved performance of GetRoute on namedRoutes\n- Hotfix on namedRoutes\n\n## [2.0.10]\n\n- Bump new Flutter version\n- Added Get.generalDialog\n\n## [2.0.6]\n\n- Fix typo on readme\n\n## [2.0.5]\n\n- Changing the bottomsheet API to comply with the documentation.\n\n## [2.0.4]\n\n- Fix type not found in some versions of Flutter stable\n\n## [2.0.3]\n\n- Update Docs\n\n## [2.0.2]\n\n- Update GetObserver\n\n## [2.0.1]\n\n- Fix docs and typos\n\n## [2.0.0]\n\n- Added easy state manager\n- Change dialog API\n- Added GetMaterialApp\n- Added new experimental APIs\n- Improve Observer\n- Added default duration on Transitions\n- Added new routeNamed sistem\n- Added Global stateManager config\n- Improve Get instance manager\n- Added routingCallback\n- Added closeOverlays to Get.back\n- Added dynamic urls\n- Cleaner code\n- Improve lib performance\n- Many others minor APIs added\n\n## [1.20.1]\n\n- Improve: Get.finds\n\n## [1.20.0]\n\n- Added Get Instance Manager\n  Get.put / Get.find / Get.delete\n\n## [1.19.1]\n\n- Fix default transitions for namedRoutes\n\n## [1.19.0]\n\n- Added nested navigators\n\n## [1.18.0]\n\n- Added SafeArea to bottomsheets\n- Added docs\n\n## [1.17.0]\n\n- Added experimental APIs\n\n## [1.16.1]\n\n- Improve: GetObserver\n\n## [1.16.0-dev]\n\n- Added Get config\n- Added logEnable\n- Added Default transition\n- Added default popGesture behaviour\n- Added overlayContext\n- Fix Duration transition\n\n## [1.14.1-dev]\n\n- Fix ternary on new dart version\n\n## [1.14.0-dev]\n\n- Added compatibility with Flutter 1.17.1\n- Added back popGesture to iOS (default) and Android (optional)\n- Improve performance\n- Decrease lib size to 94.9kb (25.4k after compiled on release)\n\n## [1.13.1-dev]\n\n- Fix back function\n\n## [1.13.0-dev]\n\n- Plugin refactor\n- Added GetPlatform\n\n## [1.12.0-dev]\n\n-Compatibility with Dev branch\n\n## [1.11.4]\n\n- Refactor code of library\n\n## [1.11.3]\n\n-Added docs\n\n## [1.11.2]\n\n-Fix flutter web platform and added GetPlatform\n\n## [1.11.1]\n\n-Improve swipe to back on iOS devices\n\n## [1.11.0]\n\n-Added experimental GetCupertino\n\n## [1.10.5]\n\n-Added setKey to improve modular compatibility\n-Added ability to define transition duration directly when calling the new route.\n\n## [1.10.4]\n\n-Improve Get.offAll() - predicate now is optional\n\n## [1.10.3]\n\n-Improve default color from dialogs\n\n## [1.10.2]\n\n-Improve snackbar text color\n-Added background color to snackbar (@claudneysessa)\n\n## [1.10.1]\n\n-Backdrop improvement\n\n## [1.10.0]\n\n-Added backdrop\n\n## [1.9.2]\n\n-Added docs to GetObserver\n\n## [1.9.1]\n\n-Fix typo on snackbar route\n\n## [1.9.0]\n\n-Added: Navigator observer\n-Added: Get.args to named routes\n-Improve snackbar performance\n\n## [1.8.1]\n\n-Fix new snackbar features\n\n## [1.8.0]\n\n-Add Get.close method.\n-Add many Snackbars features\n\n## [1.7.4]\n\n-Fix dialog child error\n\n## [1.7.3]\n\n-Added transitions docs\n\n## [1.7.2]\n\n-Fix bottomsheet on macos\n\n## [1.7.1]\n\n-Fix docs\n\n## [1.7.0]\n\n- Improve geral performance. Get.to Wrap now consumes even less RAM and CPU. In an application with 20 screens, it obtained 82% less RAM usage compared to the traditional method Navigator.push and had a CPU normalization of 23% in a Moto z2, against 64% CPU usage in Navigator.push with MaterialPageRoute. Test it for yourself!\n- Added BottomSheet with no context\n- Added modern Blur Snackbar\n- Added customs transitions\n- Improve dialogs performance\n\n## [1.6.4]\n\n- Improve performance.\n\n## [1.6.3]\n\n- Clean code.\n\n## [1.6.2]\n\n- Fix bugs on blurred Snackbars\n\n## [1.6.1]\n\n- Add docs and improve performance\n\n## [1.6.0]\n\n- Add support to snackbars\n\n## [1.5.0+1]\n\n- Add color and opacity to dialogs\n\n## [1.5.0]\n\n- Add support to dialogs\n\n## [1.4.0+7]\n\n- Add more documentation\n\n## [1.4.0+6]\n\n- Improve performance and bug fix\n\n## [1.4.0]\n\n- Added Get.removeRoute // ability to remove one route.\n  Get.until // back repeatedly until the predicate returns true.\n  Get.offUntil // go to next route and remove all the previous routes until the predicate returns true.\n  Get.offNamedUntil // go to next named route and remove all the previous routes until the predicate returns true.\n\n## [1.3.4]\n\n- Improve performance\n\n## [1.3.3]\n\n- Fix Get.back arguments\n\n## [1.3.2]\n\n- Improve performance\n\n## [1.3.1]\n\n- Update docs\n\n## [1.3.0]\n\n- Update docs, readme, and add full support to flutter_web\n\n## [1.2.1]\n\n- Fix bug currentState = null\n\n## [1.2.0]\n\n- Add routes navigation with no context\n\n## [1.1.0]\n\n- Add support to named routes\n\n## [1.0.3]\n\n- Improve Performance\n\n## [1.0.2]\n\n- Add examples\n\n## [1.0.1]\n\n- Doc changes\n\n## [1.0.0]\n\n- initial release\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2019 Jonny Borges\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "README-ar.md",
    "content": "![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png)\n\n[![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)\n[![popularity](https://badges.bar/get/popularity)](https://pub.dev/packages/sentry/score)\n[![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)\n[![pub points](https://badges.bar/get/pub%20points)](https://pub.dev/packages/get/score)\n![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)\n[![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart)\n[![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N)\n[![Get on Slack](https://img.shields.io/badge/slack-join-orange.svg)](https://communityinviter.com/apps/getxworkspace/getx)\n[![Telegram](https://img.shields.io/badge/chat-on%20Telegram-blue.svg)](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g)\n<a href=\"https://github.com/Solido/awesome-flutter\">\n<img alt=\"Awesome Flutter\" src=\"https://img.shields.io/badge/Awesome-Flutter-blue.svg?longCache=true&style=flat-square\" />\n</a>\n<a href=\"https://www.buymeacoffee.com/jonataslaw\" target=\"_blank\"><img src=\"https://i.imgur.com/aV6DDA7.png\" alt=\"Buy Me A Coffee\" style=\"height: 41px !important;width: 174px !important; box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;\" > </a>\n\n![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/getx.png)\n\n<div align=\"center\">\n\n**Languages:**\n\n[![English](https://img.shields.io/badge/Language-English-blueviolet?style=for-the-badge)](README.md)\n[![Vietnamese](https://img.shields.io/badge/Language-Vietnamese-blueviolet?style=for-the-badge)](README-vi.md)\n[![Indonesian](https://img.shields.io/badge/Language-Indonesian-blueviolet?style=for-the-badge)](README.id-ID.md)\n[![Urdu](https://img.shields.io/badge/Language-Urdu-blueviolet?style=for-the-badge)](README.ur-PK.md)\n[![Chinese](https://img.shields.io/badge/Language-Chinese-blueviolet?style=for-the-badge)](README.zh-cn.md)\n[![Portuguese](https://img.shields.io/badge/Language-Portuguese-blueviolet?style=for-the-badge)](README.pt-br.md)\n[![Spanish](https://img.shields.io/badge/Language-Spanish-blueviolet?style=for-the-badge)](README-es.md)\n[![Russian](https://img.shields.io/badge/Language-Russian-blueviolet?style=for-the-badge)](README.ru.md)\n[![Polish](https://img.shields.io/badge/Language-Polish-blueviolet?style=for-the-badge)](README.pl.md)\n[![Korean](https://img.shields.io/badge/Language-Korean-blueviolet?style=for-the-badge)](README.ko-kr.md)\n[![French](https://img.shields.io/badge/Language-French-blueviolet?style=for-the-badge)](README-fr.md)\n[![العربيه](https://img.shields.io/badge/Language-arabic-blueviolet?style=for-the-badge)](README-ar.md)\n\n</div>\n<div dir=\"rtl\">\n\n- [عن المكتبة](#عن-المكتبة)\n- [التركيب](#التركيب)\n- [بناء تطبيق العداد 🔢](#بناء-تطبيق-العداد-)\n- [The Three pillars](#the-three-pillars)\n  - [State management](#state-management)\n    - [Reactive State Manager](#reactive-state-manager)\n    - [More details about state management](#more-details-about-state-management)\n  - [Route management](#route-management)\n    - [More details about route management](#more-details-about-route-management)\n  - [Dependency management](#dependency-management)\n    - [More details about dependency management](#more-details-about-dependency-management)\n- [Utils](#utils)\n  - [Internationalization](#internationalization)\n    - [Translations](#translations)\n      - [Using translations](#using-translations)\n      - [Using translation with singular and plural](#using-translation-with-singular-and-plural)\n      - [Using translation with parameters](#using-translation-with-parameters)\n    - [Locales](#locales)\n      - [Change locale](#change-locale)\n      - [System locale](#system-locale)\n  - [Change Theme](#change-theme)\n  - [GetConnect](#getconnect)\n    - [Default configuration](#default-configuration)\n    - [Custom configuration](#custom-configuration)\n  - [GetPage Middleware](#getpage-middleware)\n    - [Priority](#priority)\n    - [Redirect](#redirect)\n    - [onPageCalled](#onpagecalled)\n    - [OnBindingsStart](#onbindingsstart)\n    - [OnPageBuildStart](#onpagebuildstart)\n    - [OnPageBuilt](#onpagebuilt)\n    - [OnPageDispose](#onpagedispose)\n  - [Other Advanced APIs](#other-advanced-apis)\n    - [Optional Global Settings and Manual configurations](#optional-global-settings-and-manual-configurations)\n    - [Local State Widgets](#local-state-widgets)\n      - [ValueBuilder](#valuebuilder)\n      - [ObxValue](#obxvalue)\n  - [Useful tips](#useful-tips)\n  - [StateMixin](#statemixin)\n      - [GetView](#getview)\n      - [GetResponsiveView](#getresponsiveview)\n        - [How to use it](#how-to-use-it)\n      - [GetWidget](#getwidget)\n      - [GetxService](#getxservice)\n    - [Tests](#tests)\n      - [Tips](#tips)\n        - [Mockito or mocktail](#mockito-or-mocktail)\n        - [Using Get.reset()](#using-getreset)\n        - [Get.testMode](#gettestmode)\n- [Breaking changes from 2.0](#breaking-changes-from-20)\n- [Why Getx?](#why-getx)\n- [Community](#community)\n  - [Community channels](#community-channels)\n  - [How to contribute](#how-to-contribute)\n  - [Articles and videos](#articles-and-videos)\n\n# عن المكتبة\n\n- `GetX` مكتبه خفيفه وقوية لفلاتر , توفر المكتبه السرعه العاليه في التحكم في الحاله , نظام حقن `Ddependency injection` ذكي , والتحكم في التنقل بين الصفحات بسرعه وسهوله\n\n- `GetX`\n- تعتمد علي 3 نقاط اساسية . **الانتاجية والسرعه والتنظيم**\n\n  - **السرعه:** `GetX` تركز علي السرعه واقل استخدام للموارد,`GetX` لا تستخدم `Streams` او `ChangeNotifier`.\n\n  - **الانتاجية:** `GetX` تستخدم طريقه سهله ومريحة في كتابة الكود , لا يهم ماذا تريد انت تبني , يوجد دائما طريقه اسهل لبناء باستخدام `GetX` , ستوفر ساعات من العمل وتوفر لك اعلي سرعه يمكن الوصل لها في تطبيقاتك عموما , يجب ان يهتم المطور بالتخلص من الموارد الغير مستخدمه من الذاكرة , مع `GetX` هذا غير ضروري لانه يتم التخلص من الموارد الغير مستخدمه من الذاكره تلقائيا, اذا اردت تركهم دائما في الذاكرة يمكنك ذلك لكن يجب عليك ان تستخدم `permanent: true` بالاضافه الي توفير الوقت تم تقليل امكانية ترك الموارد في الذاكره بدون التخلص منها , يتم حقن الموارد `lazy` افتراضيا\n\n  - **التنظيم:** `GetX` تسمح لك بفصل الـ `view` عن الـ `presentation logic` و `business logic` باكامل,\n    بالنسبة للحقن `dependency injection` و التنقل بين الشاشات لا تحتاج فيهم `context` للتنقل بين الصفحات , ولا تحتاك `context` للوصول للموارد عن طريق widget tree, لذلك يتم الفصل بالكامل بين `presentation logic` و `business logic` لا تحتاج لحقن ال `Controllers/Models/Blocs`\n    داخل شجره العناصر `Widget Tree` خلال `MultiProvider`s.\n    لان , `GetX` تستخدم نظام حقن خاص بها ويمكنك من فصل الـ `DI` عن الوجهات بالكامل .\n\n- مع `Getx` تعرف ايه يكون الكود الخاص ب كل جزء في التطبيق , تساعدك في كتابة كود نظيف , بالاضافه الي سهوله التطوير مستقبلا , وهذا يمكنك من مشاركه الاجزاء `modules` امر صعب ليصبح سهل جدا .\n  `BLOC` كان نقطه البداية لهذا الامر وتظيم الكود بهذه الطريقه في فلاتر , عن طريق فصل كود البزنس عن الواجهات , `GetX` هي التطور لذلك الامر , وذلك عن طريق الاضافه الي ذلك فصل حقن الموارد وفصل التنقل بين الشاشات ايضا , وطبقه البيانات بالكامل ايضا , تعلم اين يكون كل شي في المشروع\n\n- `Getx` توفر لك السهوله في بناء المشروع والاستقرار كلما كبر حجم المشروع واقصي سرعه ممكن , توفر لك ايضا نظام كامل يعمل في تجانس تام , سهل للمبتدئين , ومنظم للخبراء , امن , مستقر , ومحدث باستمرار ويوفر لك موجموعه من الادوات لتسهل عليك\n\n- `GetX` ليست ضخمه , تمتلك المكتبة العديد من المميزات تجعلك تبدا في البرمجه بدون القلق عن اي شي كل ميزه منهم منقسمه عن الاخري ولا يبداو الا عندما تستخدمهم , اذا استخدمت جزء التحكم في الحاله فقط لن يتم استخدام جزء التنقل بين الشاشات في تطبيقك الا `Compiled` والعكس صحيح ! .\n\n-`Getx` لديها نظام شامل , ومجتمع كبير , وعداد كبير من المطورين , وسوف يتم تحديثها باستمرار , تعمل المكتبة علي كل الانظمه بنفس الكود دون تغيير `Android`, `iOS`, `Web`, `Mac`, `Linux`, `Windows` حتي علي الخادم يمكنك استخدام `Getx` لبناء تطبيقات الويب\n**[Get Server](https://github.com/jonataslaw/get_server)**.\n\n**بالاضافه الي ذلك يمكن محاكاه الامر اكثر في فلاتر والخادم عن طريق [Get CLI](https://github.com/jonataslaw/get_cli)**.\n\n**وللمزيد من الانتاجية يمكنك استخدام اضافه للـ**\n\n- [فيجوال ستوديو كود](https://marketplace.visualstudio.com/items?itemName=get-snippets.get-snippets)\n- [اندرويد استوديو و انتلج](https://plugins.jetbrains.com/plugin/14975-getx-snippets)\n\n# التركيب\n\nاستخدم المكتبة في ملف `pubspec.yaml`\n\n<div dir=\"ltr\" >\n\n```yaml\ndependencies:\n  get:\n```\n\n</div>\nاستدعي المكتبة في الملفات الي ستستخدمها\n<div dir=\"ltr\" >\n\n```dart\nimport 'package:get/get.dart';\n```\n\n</div>\n\n# بناء تطبيق العداد 🔢\n\nتطبيق العداد الذي يتم انشاء مع كل مشروع جديد يتعدي ال 100 سطر (بالتعليقات) ولكي اريك مدي قوه `GetX`\nساوضح لك كيفيه بناء التطبيق مع تغير قيمه العداد مع كل ضغطه زر والتقل بين الشاشات ومشاركه الحاله كل ذلك بطريقه منذمه وفصل تام لكود البزنس عن الواجهات فقط ب 26 سطر من ضمنهم التعليقات 🔥\n\n- الخطوه الاولي :\n  اكتب `Get` امام `MaterialApp` لتصبح `GetMaterialApp`\n\n<div dir=\"ltr\" >\n\n```dart\nvoid main() => runApp(GetMaterialApp(home: Home()));\n```\n\n</div>\n\n- ملحوظه : هذا لا يعتبر تعديل علي `MaterialApp` لان , `GetMaterialApp` عباره عن عنصر معد مسبقا ويستخدم `MaterialApp` تحت الغطاء , يمكن تغير الاعدادات يدوين لكن هذا غير ضروري لان ``سيقوم بعمل المسارات و حقن العناصر والترجمه وكل شي تحتاجه ولكن اذا كنت تنوي لاستخدام المكتبة فقط للتحكم في الحاله`State managment`فهذه الخطوه غير ضرورية تكون هذه الخطوه ضرورية عندما تريد التنقل بين الشاشات او عرض`snackbars`والترجمه و اي شي يعتمد علي`context`وتقوم`getx` بتوفيره\n\n- الخطوه الثانية\n  قم بكتابة الكود داخل `class` وكتابة المتغيرات والدوال , يمكنك جعل المتغير قابلع لاعاده بناء الواجها عند تغير قيمته باستخدام ال `getter` `.obs` .\n\n<div dir=\"ltr\" >\n\n```dart\nclass Controller extends GetxController{\n  var count = 0.obs;\n  increment() => count++;\n}\n```\n\n</div>\n\n- الخطوه الثالثه\nابني الواجهه واستخدم `StatelessWidget` لتوفير الموارد , مع `Getx` يمكنك الاستغناء عن `StatefulWidget`.\n<div dir=\"ltr\" >\n\n```dart\nclass Home extends StatelessWidget {\n\n  @override\n  Widget build(context) {\n\n    // Instantiate your class using Get.put() to make it available for all \"child\" routes there.\n    final  c = Get.put(Controller());\n\n    return Scaffold(\n      // Use Obx(()=> to update Text() whenever count is changed.\n      appBar: AppBar(title: Obx(() => Text(\"Clicks: ${c.count}\"))),\n\n      // Replace the 8 lines Navigator.push by a simple Get.to(). You don't need context\n      body: Center(child: ElevatedButton(\n              child: Text(\"Go to Other\"), onPressed: () => Get.to(Other()))),\n      floatingActionButton:\n          FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment));\n  }\n}\n\nclass Other extends StatelessWidget {\n  // You can ask Get to find a Controller that is being used by another page and redirect you to it.\n  final Controller c = Get.find();\n\n  @override\n  Widget build(context){\n     // Access the updated count variable\n     return Scaffold(body: Center(child: Text(\"${c.count}\")));\n  }\n}\n```\n\n</div>\n\nResult:\n\n![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/counter-app-gif.gif)\n\nThis is a simple project but it already makes clear how powerful Get is. As your project grows, this difference will become more significant.\n\nGet was designed to work with teams, but it makes the job of an individual developer simple.\n\nImprove 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!\n\n# The Three pillars\n\n## State management\n\nGet has two different state managers: the simple state manager (we'll call it GetBuilder) and the reactive state manager (GetX/Obx)\n\n### Reactive State Manager\n\nReactive programming can alienate many people because it is said to be complicated. GetX turns reactive programming into something quite simple:\n\n- You won't need to create StreamControllers.\n- You won't need to create a StreamBuilder for each variable\n- You will not need to create a class for each state.\n- You will not need to create a get for an initial value.\n- You will not need to use code generators\n\nReactive programming with Get is as easy as using setState.\n\nLet's imagine that you have a name variable and want that every time you change it, all widgets that use it are automatically changed.\n\nThis is your count variable:\n\n```dart\nvar name = 'Jonatas Borges';\n```\n\nTo make it observable, you just need to add \".obs\" to the end of it:\n\n```dart\nvar name = 'Jonatas Borges'.obs;\n```\n\nAnd in the UI, when you want to show that value and update the screen whenever the values changes, simply do this:\n\n```dart\nObx(() => Text(\"${controller.name}\"));\n```\n\nThat's all. It's _that_ simple.\n\n### More details about state management\n\n**See an more in-depth explanation of state management [here](./documentation/en_US/state_management.md). There you will see more examples and also the difference between the simple state manager and the reactive state manager**\n\nYou will get a good idea of GetX power.\n\n## Route management\n\nIf you are going to use routes/snackbars/dialogs/bottomsheets without context, GetX is excellent for you too, just see it:\n\nAdd \"Get\" before your MaterialApp, turning it into GetMaterialApp\n\n```dart\nGetMaterialApp( // Before: MaterialApp(\n  home: MyHome(),\n)\n```\n\nNavigate to a new screen:\n\n```dart\n\nGet.to(NextScreen());\n```\n\nNavigate to new screen with name. See more details on named routes [here](./documentation/en_US/route_management.md#navigation-with-named-routes)\n\n```dart\n\nGet.toNamed('/details');\n```\n\nTo close snackbars, dialogs, bottomsheets, or anything you would normally close with Navigator.pop(context);\n\n```dart\nGet.back();\n```\n\nTo go to the next screen and no option to go back to the previous screen (for use in SplashScreens, login screens, etc.)\n\n```dart\nGet.off(NextScreen());\n```\n\nTo go to the next screen and cancel all previous routes (useful in shopping carts, polls, and tests)\n\n```dart\nGet.offAll(NextScreen());\n```\n\nNoticed 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.\n\n### More details about route management\n\n**Get works with named routes and also offers lower-level control over your routes! There is in-depth documentation [here](./documentation/en_US/route_management.md)**\n\n## Dependency management\n\nGet 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:\n\n```dart\nController controller = Get.put(Controller()); // Rather Controller controller = Controller();\n```\n\n- 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.\n\nInstead 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.\nSo you can use your controller (or class Bloc) normally\n\n**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\n\n```dart\ncontroller.fetchApi();\n```\n\nImagine 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:\n\n```dart\nController controller = Get.find();\n//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.\n```\n\nAnd then you will be able to recover your controller data that was obtained back there:\n\n```dart\nText(controller.textFromApi);\n```\n\n### More details about dependency management\n\n**See a more in-depth explanation of dependency management [here](./documentation/en_US/dependency_management.md)**\n\n# Utils\n\n## Internationalization\n\n### Translations\n\nTranslations are kept as a simple key-value dictionary map.\nTo add custom translations, create a class and extend `Translations`.\n\n```dart\nimport 'package:get/get.dart';\n\nclass Messages extends Translations {\n  @override\n  Map<String, Map<String, String>> get keys => {\n        'en_US': {\n          'hello': 'Hello World',\n        },\n        'de_DE': {\n          'hello': 'Hallo Welt',\n        }\n      };\n}\n```\n\n#### Using translations\n\nJust append `.tr` to the specified key and it will be translated, using the current value of `Get.locale` and `Get.fallbackLocale`.\n\n```dart\nText('title'.tr);\n```\n\n#### Using translation with singular and plural\n\n```dart\nvar products = [];\nText('singularKey'.trPlural('pluralKey', products.length, Args));\n```\n\n#### Using translation with parameters\n\n```dart\nimport 'package:get/get.dart';\n\n\nMap<String, Map<String, String>> get keys => {\n    'en_US': {\n        'logged_in': 'logged in as @name with email @email',\n    },\n    'es_ES': {\n       'logged_in': 'iniciado sesión como @name con e-mail @email',\n    }\n};\n\nText('logged_in'.trParams({\n  'name': 'Jhon',\n  'email': 'jhon@example.com'\n  }));\n```\n\n### Locales\n\nPass parameters to `GetMaterialApp` to define the locale and translations.\n\n```dart\nreturn GetMaterialApp(\n    translations: Messages(), // your translations\n    locale: Locale('en', 'US'), // translations will be displayed in that locale\n    fallbackLocale: Locale('en', 'UK'), // specify the fallback locale in case an invalid locale is selected.\n);\n```\n\n#### Change locale\n\nCall `Get.updateLocale(locale)` to update the locale. Translations then automatically use the new locale.\n\n```dart\nvar locale = Locale('en', 'US');\nGet.updateLocale(locale);\n```\n\n#### System locale\n\nTo read the system locale, you could use `Get.deviceLocale`.\n\n```dart\nreturn GetMaterialApp(\n    locale: Get.deviceLocale,\n);\n```\n\n## Change Theme\n\nPlease 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™**.\n\nYou can create your custom theme and simply add it within `Get.changeTheme` without any boilerplate for that:\n\n```dart\nGet.changeTheme(ThemeData.light());\n```\n\nIf you want to create something like a button that changes the Theme in `onTap`, you can combine two **GetX™** APIs for that:\n\n- The api that checks if the dark `Theme` is being used.\n- And the `Theme` Change API, you can just put this within an `onPressed`:\n\n```dart\nGet.changeTheme(Get.isDarkMode? ThemeData.light(): ThemeData.dark());\n```\n\nWhen `.darkmode` is activated, it will switch to the _light theme_, and when the _light theme_ becomes active, it will change to _dark theme_.\n\n## GetConnect\n\nGetConnect is an easy way to communicate from your back to your front with http or websockets\n\n### Default configuration\n\nYou can simply extend GetConnect and use the GET/POST/PUT/DELETE/SOCKET methods to communicate with your Rest API or websockets.\n\n```dart\nclass UserProvider extends GetConnect {\n  // Get request\n  Future<Response> getUser(int id) => get('http://youapi/users/$id');\n  // Post request\n  Future<Response> postUser(Map data) => post('http://youapi/users', body: data);\n  // Post request with File\n  Future<Response<CasesModel>> postCases(List<int> image) {\n    final form = FormData({\n      'file': MultipartFile(image, filename: 'avatar.png'),\n      'otherFile': MultipartFile(image, filename: 'cover.png'),\n    });\n    return post('http://youapi/users/upload', form);\n  }\n\n  GetSocket userMessages() {\n    return socket('https://yourapi/users/socket');\n  }\n}\n```\n\n### Custom configuration\n\nGetConnect 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.\n\n```dart\nclass HomeProvider extends GetConnect {\n  @override\n  void onInit() {\n    // All request will pass to jsonEncode so CasesModel.fromJson()\n    httpClient.defaultDecoder = CasesModel.fromJson;\n    httpClient.baseUrl = 'https://api.covid19api.com';\n    // baseUrl = 'https://api.covid19api.com'; // It define baseUrl to\n    // Http and websockets if used with no [httpClient] instance\n\n    // It's will attach 'apikey' property on header from all requests\n    httpClient.addRequestModifier((request) {\n      request.headers['apikey'] = '12345678';\n      return request;\n    });\n\n    // Even if the server sends data from the country \"Brazil\",\n    // it will never be displayed to users, because you remove\n    // that data from the response, even before the response is delivered\n    httpClient.addResponseModifier<CasesModel>((request, response) {\n      CasesModel model = response.body;\n      if (model.countries.contains('Brazil')) {\n        model.countries.remove('Brazilll');\n      }\n    });\n\n    httpClient.addAuthenticator((request) async {\n      final response = await get(\"http://yourapi/token\");\n      final token = response.body['token'];\n      // Set the header\n      request.headers['Authorization'] = \"$token\";\n      return request;\n    });\n\n    //Autenticator will be called 3 times if HttpStatus is\n    //HttpStatus.unauthorized\n    httpClient.maxAuthRetries = 3;\n  }\n\n  @override\n  Future<Response<CasesModel>> getCases(String path) => get(path);\n}\n```\n\n## GetPage Middleware\n\nThe GetPage has now new property that takes a list of GetMiddleWare and run them in the specific order.\n\n**Note**: When GetPage has a Middlewares, all the children of this page will have the same middlewares automatically.\n\n### Priority\n\nThe Order of the Middlewares to run can be set by the priority in the GetMiddleware.\n\n```dart\nfinal middlewares = [\n  GetMiddleware(priority: 2),\n  GetMiddleware(priority: 5),\n  GetMiddleware(priority: 4),\n  GetMiddleware(priority: -8),\n];\n```\n\nthose middlewares will be run in this order **-8 => 2 => 4 => 5**\n\n### Redirect\n\nThis 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.\n\n```dart\nRouteSettings redirect(String route) {\n  final authService = Get.find<AuthService>();\n  return authService.authed.value ? null : RouteSettings(name: '/login')\n}\n```\n\n### onPageCalled\n\nThis function will be called when this Page is called before anything created\nyou can use it to change something about the page or give it new page\n\n```dart\nGetPage onPageCalled(GetPage page) {\n  final authService = Get.find<AuthService>();\n  return page.copyWith(title: 'Welcome ${authService.UserName}');\n}\n```\n\n### OnBindingsStart\n\nThis function will be called right before the Bindings are initialize.\nHere you can change Bindings for this page.\n\n```dart\nList<Bindings> onBindingsStart(List<Bindings> bindings) {\n  final authService = Get.find<AuthService>();\n  if (authService.isAdmin) {\n    bindings.add(AdminBinding());\n  }\n  return bindings;\n}\n```\n\n### OnPageBuildStart\n\nThis function will be called right after the Bindings are initialize.\nHere you can do something after that you created the bindings and before creating the page widget.\n\n```dart\nGetPageBuilder onPageBuildStart(GetPageBuilder page) {\n  print('bindings are ready');\n  return page;\n}\n```\n\n### OnPageBuilt\n\nThis 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.\n\n### OnPageDispose\n\nThis function will be called right after disposing all the related objects (Controllers, views, ...) of the page.\n\n## Other Advanced APIs\n\n```dart\n// give the current args from currentScreen\nGet.arguments\n\n// give name of previous route\nGet.previousRoute\n\n// give the raw route to access for example, rawRoute.isFirst()\nGet.rawRoute\n\n// give access to Routing API from GetObserver\nGet.routing\n\n// check if snackbar is open\nGet.isSnackbarOpen\n\n// check if dialog is open\nGet.isDialogOpen\n\n// check if bottomsheet is open\nGet.isBottomSheetOpen\n\n// remove one route.\nGet.removeRoute()\n\n// back repeatedly until the predicate returns true.\nGet.until()\n\n// go to next route and remove all the previous routes until the predicate returns true.\nGet.offUntil()\n\n// go to next named route and remove all the previous routes until the predicate returns true.\nGet.offNamedUntil()\n\n//Check in what platform the app is running\nGetPlatform.isAndroid\nGetPlatform.isIOS\nGetPlatform.isMacOS\nGetPlatform.isWindows\nGetPlatform.isLinux\nGetPlatform.isFuchsia\n\n//Check the device type\nGetPlatform.isMobile\nGetPlatform.isDesktop\n//All platforms are supported independently in web!\n//You can tell if you are running inside a browser\n//on Windows, iOS, OSX, Android, etc.\nGetPlatform.isWeb\n\n\n// Equivalent to : MediaQuery.of(context).size.height,\n// but immutable.\nGet.height\nGet.width\n\n// Gives the current context of the Navigator.\nGet.context\n\n// Gives the context of the snackbar/dialog/bottomsheet in the foreground, anywhere in your code.\nGet.contextOverlay\n\n// Note: the following methods are extensions on context. Since you\n// have access to context in any place of your UI, you can use it anywhere in the UI code\n\n// If you need a changeable height/width (like Desktop or browser windows that can be scaled) you will need to use context.\ncontext.width\ncontext.height\n\n// Gives you the power to define half the screen, a third of it and so on.\n// Useful for responsive applications.\n// param dividedBy (double) optional - default: 1\n// param reducedBy (double) optional - default: 0\ncontext.heightTransformer()\ncontext.widthTransformer()\n\n/// Similar to MediaQuery.of(context).size\ncontext.mediaQuerySize()\n\n/// Similar to MediaQuery.of(context).padding\ncontext.mediaQueryPadding()\n\n/// Similar to MediaQuery.of(context).viewPadding\ncontext.mediaQueryViewPadding()\n\n/// Similar to MediaQuery.of(context).viewInsets;\ncontext.mediaQueryViewInsets()\n\n/// Similar to MediaQuery.of(context).orientation;\ncontext.orientation()\n\n/// Check if device is on landscape mode\ncontext.isLandscape()\n\n/// Check if device is on portrait mode\ncontext.isPortrait()\n\n/// Similar to MediaQuery.of(context).devicePixelRatio;\ncontext.devicePixelRatio()\n\n/// Similar to MediaQuery.of(context).textScaleFactor;\ncontext.textScaleFactor()\n\n/// Get the shortestSide from screen\ncontext.mediaQueryShortestSide()\n\n/// True if width be larger than 800\ncontext.showNavbar()\n\n/// True if the shortestSide is smaller than 600p\ncontext.isPhone()\n\n/// True if the shortestSide is largest than 600p\ncontext.isSmallTablet()\n\n/// True if the shortestSide is largest than 720p\ncontext.isLargeTablet()\n\n/// True if the current device is Tablet\ncontext.isTablet()\n\n/// Returns a value<T> according to the screen size\n/// can give value for:\n/// watch: if the shortestSide is smaller than 300\n/// mobile: if the shortestSide is smaller than 600\n/// tablet: if the shortestSide is smaller than 1200\n/// desktop: if width is largest than 1200\ncontext.responsiveValue<T>()\n```\n\n### Optional Global Settings and Manual configurations\n\nGetMaterialApp configures everything for you, but if you want to configure Get manually.\n\n```dart\nMaterialApp(\n  navigatorKey: Get.key,\n  navigatorObservers: [GetObserver()],\n);\n```\n\nYou will also be able to use your own Middleware within `GetObserver`, this will not influence anything.\n\n```dart\nMaterialApp(\n  navigatorKey: Get.key,\n  navigatorObservers: [\n    GetObserver(MiddleWare.observer) // Here\n  ],\n);\n```\n\nYou can create _Global Settings_ for `Get`. Just add `Get.config` to your code before pushing any route.\nOr do it directly in your `GetMaterialApp`\n\n```dart\nGetMaterialApp(\n  enableLog: true,\n  defaultTransition: Transition.fade,\n  opaqueRoute: Get.isOpaqueRouteDefault,\n  popGesture: Get.isPopGestureEnable,\n  transitionDuration: Get.defaultDurationTransition,\n  defaultGlobalState: Get.defaultGlobalState,\n);\n\nGet.config(\n  enableLog = true,\n  defaultPopGesture = true,\n  defaultTransition = Transitions.cupertino\n)\n```\n\nYou can optionally redirect all the logging messages from `Get`.\nIf you want to use your own, favourite logging package,\nand want to capture the logs there:\n\n```dart\nGetMaterialApp(\n  enableLog: true,\n  logWriterCallback: localLogWriter,\n);\n\nvoid localLogWriter(String text, {bool isError = false}) {\n  // pass the message to your favourite logging package here\n  // please note that even if enableLog: false log messages will be pushed in this callback\n  // you get check the flag if you want through GetConfig.isLogEnable\n}\n\n```\n\n### Local State Widgets\n\nThese Widgets allows you to manage a single value, and keep the state ephemeral and locally.\nWe have flavours for Reactive and Simple.\nFor instance, you might use them to toggle obscureText in a `TextField`, maybe create a custom\nExpandable Panel, or maybe modify the current index in `BottomNavigationBar` while changing the content\nof the body in a `Scaffold`.\n\n#### ValueBuilder\n\nA simplification of `StatefulWidget` that works with a `.setState` callback that takes the updated value.\n\n```dart\nValueBuilder<bool>(\n  initialValue: false,\n  builder: (value, updateFn) => Switch(\n    value: value,\n    onChanged: updateFn, // same signature! you could use ( newValue ) => updateFn( newValue )\n  ),\n  // if you need to call something outside the builder method.\n  onUpdate: (value) => print(\"Value updated: $value\"),\n  onDispose: () => print(\"Widget unmounted\"),\n),\n```\n\n#### ObxValue\n\nSimilar to [`ValueBuilder`](#valuebuilder), but this is the Reactive version, you pass a Rx instance (remember the magical .obs?) and\nupdates automatically... isn't it awesome?\n\n```dart\nObxValue((data) => Switch(\n        value: data.value,\n        onChanged: data, // Rx has a _callable_ function! You could use (flag) => data.value = flag,\n    ),\n    false.obs,\n),\n```\n\n## Useful tips\n\n`.obs`ervables (also known as _Rx_ Types) have a wide variety of internal methods and operators.\n\n> Is very common to _believe_ that a property with `.obs` **IS** the actual value... but make no mistake!\n> We avoid the Type declaration of the variable, because Dart's compiler is smart enough, and the code\n> looks cleaner, but:\n\n```dart\nvar message = 'Hello world'.obs;\nprint( 'Message \"$message\" has Type ${message.runtimeType}');\n```\n\nEven if `message` _prints_ the actual String value, the Type is **RxString**!\n\nSo, you can't do `message.substring( 0, 4 )`.\nYou have to access the real `value` inside the _observable_:\nThe most \"used way\" is `.value`, but, did you know that you can also use...\n\n```dart\nfinal name = 'GetX'.obs;\n// only \"updates\" the stream, if the value is different from the current one.\nname.value = 'Hey';\n\n// All Rx properties are \"callable\" and returns the new value.\n// but this approach does not accepts `null`, the UI will not rebuild.\nname('Hello');\n\n// is like a getter, prints 'Hello'.\nname() ;\n\n/// numbers:\n\nfinal count = 0.obs;\n\n// You can use all non mutable operations from num primitives!\ncount + 1;\n\n// Watch out! this is only valid if `count` is not final, but var\ncount += 1;\n\n// You can also compare against values:\ncount > 2;\n\n/// booleans:\n\nfinal flag = false.obs;\n\n// switches the value between true/false\nflag.toggle();\n\n\n/// all types:\n\n// Sets the `value` to null.\nflag.nil();\n\n// All toString(), toJson() operations are passed down to the `value`\nprint( count ); // calls `toString()` inside  for RxInt\n\nfinal abc = [0,1,2].obs;\n// Converts the value to a json Array, prints RxList\n// Json is supported by all Rx types!\nprint('json: ${jsonEncode(abc)}, type: ${abc.runtimeType}');\n\n// RxMap, RxList and RxSet are special Rx types, that extends their native types.\n// but you can work with a List as a regular list, although is reactive!\nabc.add(12); // pushes 12 to the list, and UPDATES the stream.\nabc[3]; // like Lists, reads the index 3.\n\n\n// equality works with the Rx and the value, but hashCode is always taken from the value\nfinal number = 12.obs;\nprint( number == 12 ); // prints > true\n\n/// Custom Rx Models:\n\n// toJson(), toString() are deferred to the child, so you can implement override on them, and print() the observable directly.\n\nclass User {\n    String name, last;\n    int age;\n    User({this.name, this.last, this.age});\n\n    @override\n    String toString() => '$name $last, $age years old';\n}\n\nfinal user = User(name: 'John', last: 'Doe', age: 33).obs;\n\n// `user` is \"reactive\", but the properties inside ARE NOT!\n// So, if we change some variable inside of it...\nuser.value.name = 'Roi';\n// The widget will not rebuild!,\n// `Rx` don't have any clue when you change something inside user.\n// So, for custom classes, we need to manually \"notify\" the change.\nuser.refresh();\n\n// or we can use the `update()` method!\nuser.update((value){\n  value.name='Roi';\n});\n\nprint( user );\n```\n\n## StateMixin\n\nAnother way to handle your `UI` state is use the `StateMixin<T>` .\nTo implement it, use the `with` to add the `StateMixin<T>`\nto your controller which allows a T model.\n\n```dart\nclass Controller extends GetController with StateMixin<User>{}\n```\n\nThe `change()` method change the State whenever we want.\nJust pass the data and the status in this way:\n\n```dart\nchange(data, status: RxStatus.success());\n```\n\nRxStatus allow these status:\n\n```dart\nRxStatus.loading();\nRxStatus.success();\nRxStatus.empty();\nRxStatus.error('message');\n```\n\nTo represent it in the UI, use:\n\n```dart\nclass OtherClass extends GetView<Controller> {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n\n      body: controller.obx(\n        (state)=>Text(state.name),\n\n        // here you can put your custom loading indicator, but\n        // by default would be Center(child:CircularProgressIndicator())\n        onLoading: CustomLoadingIndicator(),\n        onEmpty: Text('No data found'),\n\n        // here also you can set your own error widget, but by\n        // default will be an Center(child:Text(error))\n        onError: (error)=>Text(error),\n      ),\n    );\n}\n```\n\n#### GetView\n\nI love this Widget, is so simple, yet, so useful!\n\nIs a `const Stateless` Widget that has a getter `controller` for a registered `Controller`, that's all.\n\n```dart\n class AwesomeController extends GetController {\n   final String title = 'My Awesome View';\n }\n\n  // ALWAYS remember to pass the `Type` you used to register your controller!\n class AwesomeView extends GetView<AwesomeController> {\n   @override\n   Widget build(BuildContext context) {\n     return Container(\n       padding: EdgeInsets.all(20),\n       child: Text(controller.title), // just call `controller.something`\n     );\n   }\n }\n```\n\n#### GetResponsiveView\n\nExtend this widget to build responsive view.\nthis widget contains the `screen` property that have all\ninformation about the screen size and type.\n\n##### How to use it\n\nYou have two options to build it.\n\n- with `builder` method you return the widget to build.\n- with methods `desktop`, `tablet`,`phone`, `watch`. the specific\n  method will be built when the screen type matches the method\n  when the screen is [ScreenType.Tablet] the `tablet` method\n  will be exuded and so on.\n  **Note:** If you use this method please set the property `alwaysUseBuilder` to `false`\n\nWith `settings` property you can set the width limit for the screen types.\n\n![example](https://github.com/SchabanBo/get_page_example/blob/master/docs/Example.gif?raw=true)\nCode to this screen\n[code](https://github.com/SchabanBo/get_page_example/blob/master/lib/pages/responsive_example/responsive_view.dart)\n\n#### GetWidget\n\nMost people have no idea about this Widget, or totally confuse the usage of it.\nThe use case is very rare, but very specific: It `caches` a Controller.\nBecause of the _cache_, can't be a `const Stateless`.\n\n> So, when do you need to \"cache\" a Controller?\n\nIf you use, another \"not so common\" feature of **GetX**: `Get.create()`.\n\n`Get.create(()=>Controller())` will generate a new `Controller` each time you call\n`Get.find<Controller>()`,\n\nThat's where `GetWidget` shines... as you can use it, for example,\nto keep a list of Todo items. So, if the widget gets \"rebuilt\", it will keep the same controller instance.\n\n#### GetxService\n\nThis class is like a `GetxController`, it shares the same lifecycle ( `onInit()`, `onReady()`, `onClose()`).\nBut has no \"logic\" inside of it. It just notifies **GetX** Dependency Injection system, that this subclass\n**can not** be removed from memory.\n\nSo is super useful to keep your \"Services\" always reachable and active with `Get.find()`. Like:\n`ApiService`, `StorageService`, `CacheService`.\n\n```dart\nFuture<void> main() async {\n  await initServices(); /// AWAIT SERVICES INITIALIZATION.\n  runApp(SomeApp());\n}\n\n/// Is a smart move to make your Services intiialize before you run the Flutter app.\n/// as you can control the execution flow (maybe you need to load some Theme configuration,\n/// apiKey, language defined by the User... so load SettingService before running ApiService.\n/// so GetMaterialApp() doesnt have to rebuild, and takes the values directly.\nvoid initServices() async {\n  print('starting services ...');\n  /// Here is where you put get_storage, hive, shared_pref initialization.\n  /// or moor connection, or whatever that's async.\n  await Get.putAsync(() => DbService().init());\n  await Get.putAsync(SettingsService()).init();\n  print('All services started...');\n}\n\nclass DbService extends GetxService {\n  Future<DbService> init() async {\n    print('$runtimeType delays 2 sec');\n    await 2.delay();\n    print('$runtimeType ready!');\n    return this;\n  }\n}\n\nclass SettingsService extends GetxService {\n  void init() async {\n    print('$runtimeType delays 1 sec');\n    await 1.delay();\n    print('$runtimeType ready!');\n  }\n}\n\n```\n\nThe only way to actually delete a `GetxService`, is with `Get.reset()` which is like a\n\"Hot Reboot\" of your app. So remember, if you need absolute persistence of a class instance during the\nlifetime of your app, use `GetxService`.\n\n### Tests\n\nYou can test your controllers like any other class, including their lifecycles:\n\n```dart\nclass Controller extends GetxController {\n  @override\n  void onInit() {\n    super.onInit();\n    //Change value to name2\n    name.value = 'name2';\n  }\n\n  @override\n  void onClose() {\n    name.value = '';\n    super.onClose();\n  }\n\n  final name = 'name1'.obs;\n\n  void changeName() => name.value = 'name3';\n}\n\nvoid main() {\n  test('''\nTest the state of the reactive variable \"name\" across all of its lifecycles''',\n      () {\n    /// You can test the controller without the lifecycle,\n    /// but it's not recommended unless you're not using\n    ///  GetX dependency injection\n    final controller = Controller();\n    expect(controller.name.value, 'name1');\n\n    /// If you are using it, you can test everything,\n    /// including the state of the application after each lifecycle.\n    Get.put(controller); // onInit was called\n    expect(controller.name.value, 'name2');\n\n    /// Test your functions\n    controller.changeName();\n    expect(controller.name.value, 'name3');\n\n    /// onClose was called\n    Get.delete<Controller>();\n\n    expect(controller.name.value, '');\n  });\n}\n```\n\n#### Tips\n\n##### Mockito or mocktail\n\nIf you need to mock your GetxController/GetxService, you should extend GetxController, and mixin it with Mock, that way\n\n```dart\nclass NotificationServiceMock extends GetxService with Mock implements NotificationService {}\n```\n\n##### Using Get.reset()\n\nIf 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.\n\n##### Get.testMode\n\nif you are using your navigation in your controllers, use `Get.testMode = true` at the beginning of your main.\n\n# Breaking changes from 2.0\n\n1- Rx types:\n\n| Before  | After      |\n| ------- | ---------- |\n| StringX | `RxString` |\n| IntX    | `RxInt`    |\n| MapX    | `RxMap`    |\n| ListX   | `RxList`   |\n| NumX    | `RxNum`    |\n| DoubleX | `RxDouble` |\n\nRxController 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.\n\n2- NamedRoutes\nBefore:\n\n```dart\nGetMaterialApp(\n  namedRoutes: {\n    '/': GetRoute(page: Home()),\n  }\n)\n```\n\nNow:\n\n```dart\nGetMaterialApp(\n  getPages: [\n    GetPage(name: '/', page: () => Home()),\n  ]\n)\n```\n\nWhy this change?\nOften, 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.\nInserting 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:\n\n```dart\n\nGetStorage box = GetStorage();\n\nGetMaterialApp(\n  getPages: [\n    GetPage(name: '/', page:(){\n      return box.hasData('token') ? Home() : Login();\n    })\n  ]\n)\n```\n\n# Why Getx?\n\n1- 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.\n\n2- 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.\n\n3- 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.\n\n4- 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.\nIf 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.\n\nThis library will always be updated and implementing new features. Feel free to offer PRs and contribute to them.\n\n# Community\n\n## Community channels\n\nGetX 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.\n\n| **Slack**                                                                                                                   | **Discord**                                                                                                                 | **Telegram**                                                                                                          |\n| :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------- |\n| [![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) |\n\n## How to contribute\n\n_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._\n\n- Helping to translate the readme into other languages.\n- Adding documentation to the readme (a lot of Get's functions haven't been documented yet).\n- Write articles or make videos teaching how to use Get (they will be inserted in the Readme and in the future in our Wiki).\n- Offering PRs for code/tests.\n- Including new functions.\n\nAny contribution is welcome!\n\n## Articles and videos\n\n- [Flutter Getx EcoSystem package for arabic people](https://www.youtube.com/playlist?list=PLV1fXIAyjeuZ6M8m56zajMUwu4uE3-SL0) - Tutorial by [Pesa Coder](https://github.com/UsamaElgendy).\n- [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).\n- [Complete GetX™ Navigation](https://www.youtube.com/watch?v=RaqPIoJSTtI) - Route management video by Amateur Coder.\n- [Complete GetX State Management](https://www.youtube.com/watch?v=CNpXbeI_slw) - State management video by Amateur Coder.\n- [GetX™ Other Features](https://youtu.be/ttQtlX_Q0eU) - Utils, storage, bindings and other features video by Amateur Coder.\n- [Firestore User with GetX | Todo App](https://www.youtube.com/watch?v=BiV0DcXgk58) - Video by Amateur Coder.\n- [Firebase Auth with GetX | Todo App](https://www.youtube.com/watch?v=-H-T_BSgfOE) - Video by Amateur Coder.\n- [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).\n- [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).\n- [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.\n- [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.\n- [GetX Flutter Firebase Auth Example](https://medium.com/@jeffmcmorris/getx-flutter-firebase-auth-example-b383c1dd1de2) - Article by Jeff McMorris.\n- [Flutter State Management with GetX – Complete App](https://www.appwithflutter.com/flutter-state-management-with-getx/) - by App With Flutter.\n- [Flutter Routing with Animation using Get Package](https://www.appwithflutter.com/flutter-routing-using-get-package/) - by App With Flutter.\n- [A minimal example on dartpad](https://dartpad.dev/2b3d0d6f9d4e312c5fdbefc414c1727e?) - by [Roi Peker](https://github.com/roipeker)\n\n</div>\n"
  },
  {
    "path": "README-bn.md",
    "content": "![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png)\n\n[![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)\n[![popularity](https://img.shields.io/pub/popularity/get?logo=dart)](https://pub.dev/packages/get/score)\n[![likes](https://img.shields.io/pub/likes/get?logo=dart)](https://pub.dev/packages/get/score)\n[![pub points](https://img.shields.io/pub/points/sentry?logo=dart)](https://pub.dev/packages/get/score)\n![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)\n[![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart)\n[![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N)\n[![Get on Slack](https://img.shields.io/badge/slack-join-orange.svg)](https://communityinviter.com/apps/getxworkspace/getx)\n[![Telegram](https://img.shields.io/badge/chat-on%20Telegram-blue.svg)](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g)\n<a href=\"https://github.com/Solido/awesome-flutter\">\n<img alt=\"Awesome Flutter\" src=\"https://img.shields.io/badge/Awesome-Flutter-blue.svg?longCache=true&style=flat-square\" />\n</a>\n<a href=\"https://www.buymeacoffee.com/jonataslaw\" target=\"_blank\"><img src=\"https://i.imgur.com/aV6DDA7.png\" alt=\"Buy Me A Coffee\" style=\"height: 41px !important;width: 174px !important; box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;\" > </a>\n\n![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/getx.png)\n\n\n- [Get সম্পর্কে](#about-get)\n- [ইনস্টল](#installing)\n- [GetX দিয়ে কাউন্টার অ্যাপ](#counter-app-with-getx)\n- [GetX এর তিনটি স্তম্ভ](#the-three-pillars)\n  - [স্টেট ব্যবস্থাপনা](#state-management)\n    - [প্রতিক্রিয়াশীল স্টেট ম্যানেজার](#reactive-state-manager)\n    - [স্টেট ব্যবস্থাপনা সম্পর্কে আরো বিস্তারিত](#more-details-about-state-management)\n  - [রুট ব্যবস্থাপনা](#route-management)\n    - [রুট ব্যবস্থাপনা সম্পর্কে আরো বিস্তারিত](#more-details-about-route-management)\n  - [ডিপেনডেন্সি ব্যবস্থাপনা](#dependency-management)\n    - [ডিপেনডেন্সি ব্যবস্থাপনা সম্পর্কে আরো বিস্তারিত](#more-details-about-dependency-management)\n- [ইউটিলিটি](#utils)\n  - [আন্তর্জাতিকীকরণ](#internationalization)\n    - [অনুবাদ](#translations)\n      - [অনুবাদের ব্যবহার](#using-translations)\n    - [লোকেল](#locales)\n      - [লোকেল পরিবর্তন করুন](#change-locale)\n      - [লোকেল পদ্ধতি](#system-locale)\n  - [থিম পরিবর্তন করুন](#change-theme)\n  - [গেট কানেক্ট](#getconnect)\n    - [ডিফল্ট কনফিগারেশন](#default-configuration)\n    - [কাস্টম কনফিগারেশন](#custom-configuration)\n  - [গেট পেজ মিডিলওয়্যার](#getpage-middleware)\n    - [অগ্রাধিকার](#priority)\n    - [পুনঃনির্দেশ](#redirect)\n    - [অন-পেজ কলড](#onpagecalled)\n    - [অন-বাইন্ডিং স্টার্ট](#onbindingsstart)\n    - [অন-পেজ বিল্ড স্টার্ট](#onpagebuildstart)\n    - [অন-পেজ বিল্ড](#onpagebuilt)\n    - [অন-পেজ ডিসপোজ](#onpagedispose)\n  - [অন্যান্য এপিআই সমূহ](#other-advanced-apis)\n    - [ঐচ্ছিক গ্লোবাল সেটিংস এবং ম্যানুয়াল কনফিগারেশন](#optional-global-settings-and-manual-configurations)\n    - [লোকাল স্টেট উইজেট](#local-state-widgets)\n      - [ভ্যালু বিল্ডার](#valuebuilder)\n      - [অব এক্স ভ্যালু](#obxvalue)\n  - [প্রয়োজনীয় পরামর্শ](#useful-tips)\n    - [গেট ভিউ](#getview)\n    - [গেট রেস্পন্সিভ ভিউ](#getresponsiveview)\n      - [কিভাবে এটি ব্যবহার করতে হয়](#how-to-use-it)\n    - [গেট উইজেট](#getwidget)\n    - [গেট এক্স সার্ভিস](#getxservice)\n- [2.0 থেকে পরিবর্তন](#breaking-changes-from-20)\n\n# Get সম্পর্কে\n\n- GetX হল ফ্লটারের জন্য একটি লাইটওয়েট এবং শক্তিশালী সমাধান। এটি দ্রুত এবং ব্যবহারিকভাবে উচ্চ-পারফরম্যান্স স্টেট ব্যবস্থাপনা, বুদ্ধিমান ডিপেনডেন্সি ইনজেকশন এবং রুট ব্যবস্থাপনাকে একত্রিত করে।\n\n- GetX এর ৩টি মৌলিক নীতি রয়েছে: **উৎপাদনশীলতা, কর্মক্ষমতা এবং সংগঠন**। এর মানে হল যে এইগুলি লাইব্রেরির সমস্ত রিসোর্স এর জন্য অগ্রাধিকার।\n\n  - **কর্মক্ষমতা:** GetX কর্মক্ষমতা এবং রিসোর্স এর ন্যূনতম ব্যবহারের উপর ফোকাস করে। এটি স্ট্রিম বা চেঞ্জনোটিফায়ার ব্যবহার করে না।\n\n  - **উৎপাদনশীলতা:** GetX একটি সহজ এবং মনোরম সিনট্যাক্স ব্যবহার করে। আপনি যা করতে চান না কেন, Getx এর সাথে সর্বদা একটি সহজ উপায় রয়েছে। এটি ডেভেলপমেন্ট এর সময় সাশ্রয় করবে এবং এটি আপনার অ্যাপ্লিকেশনটি সরবরাহ করতে পারে এমন সর্বাধিক কর্মক্ষমতা সরবরাহ করবে।\n\n  - **সংগঠন:** GetX ভিউ, প্রেজেন্টেশন লজিক, বিজনেস লজিক, ডিপেন্ডেন্সি ইনজেকশন এবং নেভিগেশনের মোট ডিকপলিং করার অনুমতি দেয়। রুটগুলির মধ্যে নেভিগেট করার জন্য আপনার কনটেক্সট (context) প্রয়োজন নেই, তাই আপনাকে এর জন্য উইজেট ট্রি (ভিজ্যুয়ালাইজেশন) এর উপর নির্ভরশীল হতে হবে না। \n\n- GetX এর একটি বিশাল ইকো সিস্টেম, একটি বৃহত সম্প্রদায়, প্রচুর সংখ্যক সহযোগী রয়েছে এবং যতক্ষণ ফ্লাটার বিদ্যমান থাকবে ততক্ষণ রক্ষণাবেক্ষণ করা হবে। গেটএক্স অ্যান্ড্রয়েড, আইওএস, ওয়েব, ম্যাক, লিনাক্স, উইন্ডোজ এবং আপনার সার্ভারে একই কোড দিয়ে চলতে সক্ষম। **[গেট সার্ভার (Get Server)](https://github.com/jonataslaw/get_server) দিয়ে আপনার ফ্রন্টএন্ডে তৈরি কোডটি পুনরায় সম্পূর্ণরূপে ব্যাকএন্ডে ব্যবহার করা সম্ভব।**\n\n**এছাড়াও সম্পূর্ণ ডেভেলপমেন্ট প্রক্রিয়া সার্ভারে এবং ফ্রন্টএন্ডে [Get CLI](https://github.com/jonataslaw/get_cli) এর মাধ্যমে স্বয়ংক্রিয়ভাবে করা যেতে পারে**।\n\n**এছাড়াও আপনার উত্পাদনশীলতা আরও বাড়াতে, আমাদের রয়েছে [VSCode extension](https://marketplace.visualstudio.com/items?itemName=get-snippets.get-snippets) এবং [Android Studio/Intellij extension](https://plugins.jetbrains.com/plugin/14975-getx-snippets)**।\n\n# ইনস্টল\n\nআপনার pubspec.yaml ফাইলে get যোগ করুন:\n\n```yaml\ndependencies:\n  get:\n```\n\nযে ফাইল এ ব্যবহার করবেন সেখানে ইম্পোর্ট করুন:\n\n```dart\nimport 'package:get/get.dart';\n```\n\n# GetX দিয়ে কাউন্টার অ্যাপ\n\nFlutter-এ নতুন ডিফল্ট তৈরি করা \"কাউন্টার\" প্রজেক্টে 100 টিরও বেশি লাইন রয়েছে (মন্তব্য সহ)। Get ব্যবহার করে এটি মাত্র ২৬ লাইনে করা সম্ভব (মন্তব্য সহ)।\n\n- ধাপ 1:\n  আপনার MaterialApp এর আগে \"Get\" যোগ করুন, এটিকে GetMaterialApp এ পরিণত করুন\n\n```dart\nvoid main() => runApp(GetMaterialApp(home: Home()));\n```\n\n- নোট: এটি ফ্লটারের MaterialApp পরিবর্তন করে না, GetMaterialApp একটি পরিবর্তিত MaterialApp নয়, এটি শুধুমাত্র একটি পূর্ব-কনফিগার করা উইজেট, যেটিতে একটি চাইল্ড হিসাবে ডিফল্ট MaterialApp আছে। আপনি এটি ম্যানুয়ালি কনফিগার করতে পারেন, তবে এটি অবশ্যই প্রয়োজনীয় নয়। GetMaterialApp রুট তৈরি করবে, সেগুলিকে ইনজেকশন দেবে, অনুবাদগুলি ইনজেকশন করবে, রুট নেভিগেশনের জন্য আপনার প্রয়োজনীয় সমস্ত কিছু ইনজেক্ট করবে। আপনি যদি শুধুমাত্র স্টেট ব্যবস্থাপনা বা ডিপেন্ডেন্সি ব্যবস্থাপনার জন্য Get ব্যবহার করেন, তাহলে GetMaterialApp ব্যবহার করার প্রয়োজন নেই। GetMaterialApp রুট, স্ন্যাকবার, আন্তর্জাতিকীকরণ, বটমশিট, ডায়ালগ এবং রুট সম্পর্কিত উচ্চ-স্তরের এপিএস এবং প্রসঙ্গ অনুপস্থিতির জন্য প্রয়োজনীয়।\n- নোট-²: আপনি যদি রুট ম্যানেজমেন্ট ব্যবহার করেন তবেই এই ধাপটি প্রয়োজনীয় (`Get.to()`, `Get.back()` এবং অন্যান্য)। আপনি যদি এটি ব্যবহার না করেন তবে ধাপ-1 করার দরকার নেই\n\n- ধাপ 2:\n  আপনার বিজনেস লজিক ক্লাস তৈরি করুন এবং এর ভিতরে সমস্ত ভেরিয়েবল, পদ্ধতি এবং কন্ট্রোলার রাখুন।\n  আপনি একটি সাধারণ \".obs\" ব্যবহার করে যেকোনো পরিবর্তনশীলকে পর্যবেক্ষণযোগ্য করতে পারেন।\n\n```dart\nclass Controller extends GetxController{\n  var count = 0.obs;\n  increment() => count++;\n}\n```\n\n- ধাপ 3:\n  আপনার ভিউ তৈরি করুন, স্টেটলেস উইজেট ব্যবহার করুন এবং কিছু র‌্যাম সেভ করুন, Get এর সাথে আপনাকে হয়তো আর StatefulWidget ব্যবহার করার প্রয়োজন হবে না।\n\n```dart\nclass Home extends StatelessWidget {\n\n  @override\n  Widget build(context) {\n\n    // Instantiate your class using Get.put() to make it available for all \"child\" routes there.\n    final Controller c = Get.put(Controller());\n\n    return Scaffold(\n      // Use Obx(()=> to update Text() whenever count is changed.\n      appBar: AppBar(title: Obx(() => Text(\"Clicks: ${c.count}\"))),\n\n      // Replace the 8 lines Navigator.push by a simple Get.to(). You don't need context\n      body: Center(child: ElevatedButton(\n              child: Text(\"Go to Other\"), onPressed: () => Get.to(Other()))),\n      floatingActionButton:\n          FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment));\n  }\n}\n\nclass Other extends StatelessWidget {\n  // You can ask Get to find a Controller that is being used by another page and redirect you to it.\n  final Controller c = Get.find();\n\n  @override\n  Widget build(context){\n     // Access the updated count variable\n     return Scaffold(body: Center(child: Text(\"${c.count}\")));\n  }\n}\n```\n\n# GetX এর তিনটি স্তম্ভ\n\n## স্টেট ব্যবস্থাপনা\n\nGet দুই ভিন্ন স্টেট ম্যানেজার আছে: সাধারণ স্টেট ম্যানেজার (আমরা একে GetBuilder বলব) and প্রতিক্রিয়াশীল স্টেট ম্যানেজার (GetX/Obx)\n\n### প্রতিক্রিয়াশীল স্টেট ম্যানেজার\n\nপ্রতিক্রিয়াশীল প্রোগ্রামিং অনেক লোককে উদাসীন করতে পারে কারণ এটি জটিল। GetX প্রতিক্রিয়াশীল প্রোগ্রামিংকে বেশ সহজে পরিণত করে:\n\n- আপনাকে StreamControllers তৈরি করতে হবে না।\n- আপনাকে প্রতিটি ভেরিয়েবলের জন্য একটি StreamBuilder তৈরি করতে হবে না।\n- আপনাকে প্রতিটি স্টেটের জন্য একটি ক্লাস তৈরি করতে হবে না।\n- আপনাকে initial value এর জন্য get তৈরি করতে হবে না।\n- আপনাকে কোড জেনারেটর ব্যবহার করতে হবে না।\n\nGet এর সাথে প্রতিক্রিয়াশীল প্রোগ্রামিং setState ব্যবহার করার মতোই সহজ।\n\nকল্পনা করুন যে আপনার একটি নাম ভ্যারিয়েবল আছে এবং আপনি চান যে প্রতিবার আপনি এটি পরিবর্তন করবেন, এটি ব্যবহার করে এমন সমস্ত উইজেট স্বয়ংক্রিয়ভাবে পরিবর্তন করতে পারবেন।\n\nমনে করুন এটি আপনার নাম ভ্যারিয়েবল:\n\n```dart\nvar name = 'Ashiqur Rahman Alif';\n```\n\nএটিকে observable করতে, আপনাকে এটির শেষে \".obs\" যোগ করতে হবে:\n\n```dart\nvar name = 'Ashiqur Rahman Alif'.obs;\n```\n\nএবং UI-তে যখন আপনি সেই নামটি দেখাতে চান এবং যখনই মান পরিবর্তন হয় তখন স্ক্রীনটি আপডেট করতে চান, কেবল এটি করুন:\n\n```dart\nObx(() => Text(\"${controller.name}\"));\n```\n\nএখানেই শেষ। এটা এমনই সহজ।\n\n### স্টেট ব্যবস্থাপনা সম্পর্কে আরো বিস্তারিত\n\n**স্টেট পরিচালনার আরও ব্যাখ্যা দেখুন [এখানে](./documentation/en_US/state_management.md)। সেখানে আপনি আরও উদাহরণ দেখতে পাবেন এবং সাধারণ স্টেট ব্যবস্থাপক এবং প্রতিক্রিয়াশীল স্টেট ব্যবস্থাপকের মধ্যে পার্থক্যও দেখতে পাবেন**\n\nGetX পাওয়ার সম্পর্কে ভালো ধারণা পাবেন।\n\n## রুট ব্যবস্থাপনা\n\nআপনি যদি context ছাড়াই রুট/স্ন্যাকবার/ডায়ালগ/বটমশীট ব্যবহার করতে চান, GetX আপনার জন্য, এটি দেখুন:\n\nআপনার MaterialApp এর আগে \"Get\" যোগ করুন, এটিকে GetMaterialApp এ পরিণত করুন\n\n```dart\nGetMaterialApp( // Before: MaterialApp(\n  home: MyHome(),\n)\n```\n\nএকটি নতুন স্ক্রিনে নেভিগেট করুন:\n\n```dart\n\nGet.to(NextScreen());\n```\n\nনাম সহ নতুন স্ক্রিনে নেভিগেট করুন। নামযুক্ত রুট সম্পর্কিত আরও বিস্তারিত বিবরণ দেখুন [এখানে](./documentation/en_US/route_management.md#navigation-with-named-routes)\n\n```dart\n\nGet.toNamed('/details');\n```\n\nস্ন্যাকবার, ডায়ালগ, বটমশীট, বা যেকোনো কিছু বন্ধ করতে আপনি Navigator.pop(context) এর পরিবর্তে ব্যবহার করুন:\n\n```dart\nGet.back();\n```\n\nপরবর্তী স্ক্রিনে যাওয়ার পর আগের স্ক্রিনে ফিরে যাওয়া বন্ধ করুন (স্প্ল্যাশস্ক্রিন, লগইন স্ক্রিন ইত্যাদিতে ব্যবহারের জন্য)\n\n```dart\nGet.off(NextScreen());\n```\n\nপরবর্তী স্ক্রিনে যেতে এবং আগের সমস্ত রুট বাতিল করতে (শপিং কার্ট, পোল  ইত্যাদিতে ব্যবহারের জন্য)\n\n```dart\nGet.offAll(NextScreen());\n```\n\nলক্ষ্য করেছেন যে এই জিনিসগুলির কোনটি করার জন্য আপনাকে context ব্যবহার করতে হবে না? এটি Get রুট ম্যানেজমেন্ট ব্যবহার করার সবচেয়ে বড় সুবিধাগুলির মধ্যে একটি। এটির সাহায্যে, আপনি চিন্তা ছাড়াই আপনার controller class এর মধ্যে থেকে এই সমস্ত পদ্ধতিগুলি চালাতে পারেন।\n\n### রুট ব্যবস্থাপনা সম্পর্কে আরো বিস্তারিত\n\n**রুট ব্যবস্থাপনা সম্পর্কে আরো বিস্তারিত ডকুমেন্টেশন আছে [এখানে](./documentation/en_US/route_management.md)**\n\n## ডিপেনডেন্সি ব্যবস্থাপনা\n\nGet এর একটি সহজ এবং শক্তিশালী ডিপেনডেন্সি পরিচালক রয়েছে যা আপনাকে কোনও Provider context বা inheritedWidget ছাড়াই, মাত্র 1 লাইনের কোডের মাধ্যমে আপনার ব্লক বা কন্ট্রোলারের মতো একই class রিট্রিভ করতে দেয়:\n\n```dart\nController controller = Get.put(Controller()); // Rather Controller controller = Controller();\n```\n\n- দ্রষ্টব্য: আপনি যদি Get's State Manager ব্যবহার করেন, তাহলে bindings API-এ আরও মনোযোগ দিন, যা আপনার কন্ট্রোলারের সাথে আপনার ভিউকে সংযোগ করা সহজ করে তুলবে।\n\nআপনি যে ক্লাসটি ব্যবহার করছেন তার মধ্যে আপনার ক্লাসকে ইনস্ট্যান্টিয়েট করার পরিবর্তে Get ইনস্ট্যান্সের মধ্যে ইনস্ট্যান্টিয়েট করুন, যা এটিকে আপনার অ্যাপ জুড়ে উপলব্ধ করবে।\nতখন আপনি স্বাভাবিকভাবে আপনার controller (বা class Bloc) ব্যবহার করতে পারবেন।\n\n**টিপ:** Get ডিপেন্ডেন্সি ম্যানেজমেন্ট প্যাকেজের অন্যান্য অংশ থেকে ডিকপল করা হয়েছে, উদাহরণ স্বরূপ, আপনার অ্যাপ ইতিমধ্যেই একটি স্টেট ম্যানেজার ব্যবহার করে (যেকোনোটি হতে পারে, এটা কোন ব্যাপার না), তবে আপনার পুনরায় সব লেখার দরকার নেই, আপনি কোনও সমস্যা ছাড়াই এই ডিপেন্ডেন্সি ইনজেকশনটি ব্যবহার করতে পারেন।\n\n```dart\ncontroller.fetchApi();\n```\n\nকল্পনা করুন যে আপনি অসংখ্য রুটে নেভিগেট করেছেন, এবং আপনার controller এর পিছনে ফেলে আসা ডেটার প্রয়োজন, আপনার প্রোভাইডার বা Get_it এর সাথে মিলিত একটি স্টেট ম্যানেজারের প্রয়োজন হবে, তাই না? Get এর সাথে তা প্রয়োজন নেই। আপনাকে শুধু আপনার controller এর জন্য \"find\" জিজ্ঞাসা করতে হবে, আপনার কোনো অতিরিক্ত ডিপেন্ডেন্সি প্রয়োজন নেই:\n\n```dart\nController controller = Get.find();\n//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.\n```\n\nএবং তারপরে আপনি আপনার নিয়ামক ডেটা পুনরুদ্ধার করতে সক্ষম হবেন যা সেখানে ফিরে প্রাপ্ত হয়েছিল:\n\n```dart\nText(controller.textFromApi);\n```\n\n### ডিপেনডেন্সি ব্যবস্থাপনা সম্পর্কে আরো বিস্তারিত\n\n**ডিপেনডেন্সি ব্যবস্থাপনা সম্পর্কে আরো বিস্তারিত ব্যাখ্যা দেখুন [এখানে](./documentation/en_US/dependency_management.md)**\n\n# ইউটিলিটি\n\n## আন্তর্জাতিকীকরণ\n\n### অনুবাদ\n\nঅনুবাদগুলি একটি সাধারণ কী-মানের অভিধান মানচিত্র হিসাবে রাখা হয়।\nTo add custom translations, create a class and extend `Translations`.\nকাস্টম অনুবাদ যোগ করতে, একটি class তৈরি করুন এবং `Translations` এ extends করুন।\n\n```dart\nimport 'package:get/get.dart';\n\nclass Messages extends Translations {\n  @override\n  Map<String, Map<String, String>> get keys => {\n        'en_US': {\n          'hello': 'Hello World',\n        },\n        'de_DE': {\n          'hello': 'Hallo Welt',\n        }\n      };\n}\n```\n\n#### অনুবাদের ব্যবহার\n\nশুধুমাত্র নির্দিষ্ট key তে `.tr` যোগ করুন এবং এটি অনুবাদ করা হবে, `Get.locale` এবং `Get.fallbackLocale` এর বর্তমান মান ব্যবহার করে।\n\n```dart\nText('title'.tr);\n```\n\n#### একবচন এবং বহুবচন সহ অনুবাদ ব্যবহার\n\n```dart\nvar products = [];\nText('singularKey'.trPlural('pluralKey', products.length, Args));\n```\n\n#### প্যারামিটার সহ অনুবাদ ব্যবহার\n\n```dart\nimport 'package:get/get.dart';\n\n\nMap<String, Map<String, String>> get keys => {\n    'en_US': {\n        'logged_in': 'logged in as @name with email @email',\n    },\n    'es_ES': {\n       'logged_in': 'iniciado sesión como @name con e-mail @email',\n    }\n};\n\nText('logged_in'.trParams({\n  'name': 'Jhon',\n  'email': 'jhon@example.com'\n  }));\n```\n\n### লোকেল\n\nলোকেল এবং অনুবাদ সংজ্ঞায়িত করতে `GetMaterialApp`-এ প্যারামিটার পাস করুন।\n\n```dart\nreturn GetMaterialApp(\n    translations: Messages(), // your translations\n    locale: Locale('en', 'US'), // translations will be displayed in that locale\n    fallbackLocale: Locale('en', 'UK'), // specify the fallback locale in case an invalid locale is selected.\n);\n```\n\n#### লোকেল পরিবর্তন করুন\n\nলোকেল আপডেট করতে `Get.updateLocale(locale)` কল করুন। অনুবাদগুলি তখন স্বয়ংক্রিয়ভাবে নতুন লোকেল ব্যবহার করে।\n\n```dart\nvar locale = Locale('en', 'US');\nGet.updateLocale(locale);\n```\n\n#### লোকেল পদ্ধতি\n\nসিস্টেম লোকেল পড়তে, আপনি `Get.deviceLocale` ব্যবহার করতে পারেন।\n\n```dart\nreturn GetMaterialApp(\n    locale: Get.deviceLocale,\n);\n```\n\n## থিম পরিবর্তন করুন\n\nPlease 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™**.\n\nYou can create your custom theme and simply add it within `Get.changeTheme` without any boilerplate for that:\n\n```dart\nGet.changeTheme(ThemeData.light());\n```\n\nIf you want to create something like a button that changes the Theme in `onTap`, you can combine two **GetX™** APIs for that:\n\n- The api that checks if the dark `Theme` is being used.\n- And the `Theme` Change API, you can just put this within an `onPressed`:\n\n```dart\nGet.changeTheme(Get.isDarkMode? ThemeData.light(): ThemeData.dark());\n```\n\nWhen `.darkmode` is activated, it will switch to the _light theme_, and when the _light theme_ becomes active, it will change to _dark theme_.\n\n## গেট কানেক্ট (GetConnect)\n\nGetConnect is an easy way to communicate from your back to your front with http or websockets\n\n### ডিফল্ট কনফিগারেশন\n\nYou can simply extend GetConnect and use the GET/POST/PUT/DELETE/SOCKET methods to communicate with your Rest API or websockets.\n\n```dart\nclass UserProvider extends GetConnect {\n  // Get request\n  Future<Response> getUser(int id) => get('http://youapi/users/$id');\n  // Post request\n  Future<Response> postUser(Map data) => post('http://youapi/users', body: data);\n  // Post request with File\n  Future<Response<CasesModel>> postCases(List<int> image) {\n    final form = FormData({\n      'file': MultipartFile(image, filename: 'avatar.png'),\n      'otherFile': MultipartFile(image, filename: 'cover.png'),\n    });\n    return post('http://youapi/users/upload', form);\n  }\n\n  GetSocket userMessages() {\n    return socket('https://yourapi/users/socket');\n  }\n}\n```\n\n### কাস্টম কনফিগারেশন\n\nGetConnect 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.\n\n```dart\nclass HomeProvider extends GetConnect {\n  @override\n  void onInit() {\n    // All request will pass to jsonEncode so CasesModel.fromJson()\n    httpClient.defaultDecoder = CasesModel.fromJson;\n    httpClient.baseUrl = 'https://api.covid19api.com';\n    // baseUrl = 'https://api.covid19api.com'; // It define baseUrl to\n    // Http and websockets if used with no [httpClient] instance\n\n    // It's will attach 'apikey' property on header from all requests\n    httpClient.addRequestModifier((request) {\n      request.headers['apikey'] = '12345678';\n      return request;\n    });\n\n    // Even if the server sends data from the country \"Brazil\",\n    // it will never be displayed to users, because you remove\n    // that data from the response, even before the response is delivered\n    httpClient.addResponseModifier<CasesModel>((request, response) {\n      CasesModel model = response.body;\n      if (model.countries.contains('Brazil')) {\n        model.countries.remove('Brazilll');\n      }\n    });\n\n    httpClient.addAuthenticator((request) async {\n      final response = await get(\"http://yourapi/token\");\n      final token = response.body['token'];\n      // Set the header\n      request.headers['Authorization'] = \"$token\";\n      return request;\n    });\n\n    //Autenticator will be called 3 times if HttpStatus is\n    //HttpStatus.unauthorized\n    httpClient.maxAuthRetries = 3;\n  }\n\n  @override\n  Future<Response<CasesModel>> getCases(String path) => get(path);\n}\n```\n\n## গেট পেজ মিডিলওয়্যার\n\nThe GetPage has now new property that takes a list of GetMiddleWare and run them in the specific order.\n\n**Note**: When GetPage has a Middlewares, all the children of this page will have the same middlewares automatically.\n\n### অগ্রাধিকার (Priority)\n\nThe Order of the Middlewares to run can be set by the priority in the GetMiddleware.\n\n```dart\nfinal middlewares = [\n  GetMiddleware(priority: 2),\n  GetMiddleware(priority: 5),\n  GetMiddleware(priority: 4),\n  GetMiddleware(priority: -8),\n];\n```\n\nthose middlewares will be run in this order **-8 => 2 => 4 => 5**\n\n### পুনঃনির্দেশ (Redirect)\n\nThis 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.\n\n```dart\nRouteSettings redirect(String route) {\n  final authService = Get.find<AuthService>();\n  return authService.authed.value ? null : RouteSettings(name: '/login')\n}\n```\n\n### অন-পেজ কলড (onPageCalled)\n\nThis function will be called when this Page is called before anything created\nyou can use it to change something about the page or give it new page\n\n```dart\nGetPage onPageCalled(GetPage page) {\n  final authService = Get.find<AuthService>();\n  return page.copyWith(title: 'Welcome ${authService.UserName}');\n}\n```\n\n### অন-বাইন্ডিং স্টার্ট (OnBindingsStart)\n\nThis function will be called right before the Bindings are initialize.\nHere you can change Bindings for this page.\n\n```dart\nList<Bindings> onBindingsStart(List<Bindings> bindings) {\n  final authService = Get.find<AuthService>();\n  if (authService.isAdmin) {\n    bindings.add(AdminBinding());\n  }\n  return bindings;\n}\n```\n\n### অন-পেজ বিল্ড স্টার্ট (OnPageBuildStart)\n\nThis function will be called right after the Bindings are initialize.\nHere you can do something after that you created the bindings and before creating the page widget.\n\n```dart\nGetPageBuilder onPageBuildStart(GetPageBuilder page) {\n  print('bindings are ready');\n  return page;\n}\n```\n\n### অন-পেজ বিল্ড (OnPageBuilt)\n\nThis 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.\n\n### অন-পেজ ডিসপোজ (OnPageDispose)\n\nThis function will be called right after disposing all the related objects (Controllers, views, ...) of the page.\n\n## অন্যান্য এপিআই সমূহ\n\n```dart\n// give the current args from currentScreen\nGet.arguments\n\n// give name of previous route\nGet.previousRoute\n\n// give the raw route to access for example, rawRoute.isFirst()\nGet.rawRoute\n\n// give access to Routing API from GetObserver\nGet.routing\n\n// check if snackbar is open\nGet.isSnackbarOpen\n\n// check if dialog is open\nGet.isDialogOpen\n\n// check if bottomsheet is open\nGet.isBottomSheetOpen\n\n// remove one route.\nGet.removeRoute()\n\n// back repeatedly until the predicate returns true.\nGet.until()\n\n// go to next route and remove all the previous routes until the predicate returns true.\nGet.offUntil()\n\n// go to next named route and remove all the previous routes until the predicate returns true.\nGet.offNamedUntil()\n\n//Check in what platform the app is running\nGetPlatform.isAndroid\nGetPlatform.isIOS\nGetPlatform.isMacOS\nGetPlatform.isWindows\nGetPlatform.isLinux\nGetPlatform.isFuchsia\n\n//Check the device type\nGetPlatform.isMobile\nGetPlatform.isDesktop\n//All platforms are supported independently in web!\n//You can tell if you are running inside a browser\n//on Windows, iOS, OSX, Android, etc.\nGetPlatform.isWeb\n\n\n// Equivalent to : MediaQuery.of(context).size.height,\n// but immutable.\nGet.height\nGet.width\n\n// Gives the current context of the Navigator.\nGet.context\n\n// Gives the context of the snackbar/dialog/bottomsheet in the foreground, anywhere in your code.\nGet.contextOverlay\n\n// Note: the following methods are extensions on context. Since you\n// have access to context in any place of your UI, you can use it anywhere in the UI code\n\n// If you need a changeable height/width (like Desktop or browser windows that can be scaled) you will need to use context.\ncontext.width\ncontext.height\n\n// Gives you the power to define half the screen, a third of it and so on.\n// Useful for responsive applications.\n// param dividedBy (double) optional - default: 1\n// param reducedBy (double) optional - default: 0\ncontext.heightTransformer()\ncontext.widthTransformer()\n\n/// Similar to MediaQuery.of(context).size\ncontext.mediaQuerySize()\n\n/// Similar to MediaQuery.of(context).padding\ncontext.mediaQueryPadding()\n\n/// Similar to MediaQuery.of(context).viewPadding\ncontext.mediaQueryViewPadding()\n\n/// Similar to MediaQuery.of(context).viewInsets;\ncontext.mediaQueryViewInsets()\n\n/// Similar to MediaQuery.of(context).orientation;\ncontext.orientation()\n\n/// Check if device is on landscape mode\ncontext.isLandscape()\n\n/// Check if device is on portrait mode\ncontext.isPortrait()\n\n/// Similar to MediaQuery.of(context).devicePixelRatio;\ncontext.devicePixelRatio()\n\n/// Similar to MediaQuery.of(context).textScaleFactor;\ncontext.textScaleFactor()\n\n/// Get the shortestSide from screen\ncontext.mediaQueryShortestSide()\n\n/// True if width be larger than 800\ncontext.showNavbar()\n\n/// True if the shortestSide is smaller than 600p\ncontext.isPhone()\n\n/// True if the shortestSide is largest than 600p\ncontext.isSmallTablet()\n\n/// True if the shortestSide is largest than 720p\ncontext.isLargeTablet()\n\n/// True if the current device is Tablet\ncontext.isTablet()\n\n/// Returns a value<T> according to the screen size\n/// can give value for:\n/// watch: if the shortestSide is smaller than 300\n/// mobile: if the shortestSide is smaller than 600\n/// tablet: if the shortestSide is smaller than 1200\n/// desktop: if width is largest than 1200\ncontext.responsiveValue<T>()\n```\n\n### ঐচ্ছিক গ্লোবাল সেটিংস এবং ম্যানুয়াল কনফিগারেশন\n\nGetMaterialApp configures everything for you, but if you want to configure Get manually.\n\n```dart\nMaterialApp(\n  navigatorKey: Get.key,\n  navigatorObservers: [GetObserver()],\n);\n```\n\nYou will also be able to use your own Middleware within `GetObserver`, this will not influence anything.\n\n```dart\nMaterialApp(\n  navigatorKey: Get.key,\n  navigatorObservers: [\n    GetObserver(MiddleWare.observer) // Here\n  ],\n);\n```\n\nYou can create _Global Settings_ for `Get`. Just add `Get.config` to your code before pushing any route.\nOr do it directly in your `GetMaterialApp`\n\n```dart\nGetMaterialApp(\n  enableLog: true,\n  defaultTransition: Transition.fade,\n  opaqueRoute: Get.isOpaqueRouteDefault,\n  popGesture: Get.isPopGestureEnable,\n  transitionDuration: Get.defaultDurationTransition,\n  defaultGlobalState: Get.defaultGlobalState,\n);\n\nGet.config(\n  enableLog = true,\n  defaultPopGesture = true,\n  defaultTransition = Transitions.cupertino\n)\n```\n\nYou can optionally redirect all the logging messages from `Get`.\nIf you want to use your own, favourite logging package,\nand want to capture the logs there:\n\n```dart\nGetMaterialApp(\n  enableLog: true,\n  logWriterCallback: localLogWriter,\n);\n\nvoid localLogWriter(String text, {bool isError = false}) {\n  // pass the message to your favourite logging package here\n  // please note that even if enableLog: false log messages will be pushed in this callback\n  // you get check the flag if you want through GetConfig.isLogEnable\n}\n\n```\n\n### লোকাল স্টেট উইজেট\n\nThese Widgets allows you to manage a single value, and keep the state ephemeral and locally.\nWe have flavours for Reactive and Simple.\nFor instance, you might use them to toggle obscureText in a `TextField`, maybe create a custom\nExpandable Panel, or maybe modify the current index in `BottomNavigationBar` while changing the content\nof the body in a `Scaffold`.\n\n#### ভ্যালু বিল্ডার (ValueBuilder)\n\nA simplification of `StatefulWidget` that works with a `.setState` callback that takes the updated value.\n\n```dart\nValueBuilder<bool>(\n  initialValue: false,\n  builder: (value, updateFn) => Switch(\n    value: value,\n    onChanged: updateFn, // same signature! you could use ( newValue ) => updateFn( newValue )\n  ),\n  // if you need to call something outside the builder method.\n  onUpdate: (value) => print(\"Value updated: $value\"),\n  onDispose: () => print(\"Widget unmounted\"),\n),\n```\n\n#### অবএক্সভ্যালু (ObxValue)\n\nSimilar to [`ValueBuilder`](#valuebuilder), but this is the Reactive version, you pass a Rx instance (remember the magical .obs?) and\nupdates automatically... isn't it awesome?\n\n```dart\nObxValue((data) => Switch(\n        value: data.value,\n        onChanged: data, // Rx has a _callable_ function! You could use (flag) => data.value = flag,\n    ),\n    false.obs,\n),\n```\n\n## প্রয়োজনীয় পরামর্শ\n\n`.obs`ervables (also known as _Rx_ Types) have a wide variety of internal methods and operators.\n\n> Is very common to _believe_ that a property with `.obs` **IS** the actual value... but make no mistake!\n> We avoid the Type declaration of the variable, because Dart's compiler is smart enough, and the code\n> looks cleaner, but:\n\n```dart\nvar message = 'Hello world'.obs;\nprint( 'Message \"$message\" has Type ${message.runtimeType}');\n```\n\nEven if `message` _prints_ the actual String value, the Type is **RxString**!\n\nSo, you can't do `message.substring( 0, 4 )`.\nYou have to access the real `value` inside the _observable_:\nThe most \"used way\" is `.value`, but, did you know that you can also use...\n\n```dart\nfinal name = 'GetX'.obs;\n// only \"updates\" the stream, if the value is different from the current one.\nname.value = 'Hey';\n\n// All Rx properties are \"callable\" and returns the new value.\n// but this approach does not accepts `null`, the UI will not rebuild.\nname('Hello');\n\n// is like a getter, prints 'Hello'.\nname() ;\n\n/// numbers:\n\nfinal count = 0.obs;\n\n// You can use all non mutable operations from num primitives!\ncount + 1;\n\n// Watch out! this is only valid if `count` is not final, but var\ncount += 1;\n\n// You can also compare against values:\ncount > 2;\n\n/// booleans:\n\nfinal flag = false.obs;\n\n// switches the value between true/false\nflag.toggle();\n\n\n/// all types:\n\n// Sets the `value` to null.\nflag.nil();\n\n// All toString(), toJson() operations are passed down to the `value`\nprint( count ); // calls `toString()` inside  for RxInt\n\nfinal abc = [0,1,2].obs;\n// Converts the value to a json Array, prints RxList\n// Json is supported by all Rx types!\nprint('json: ${jsonEncode(abc)}, type: ${abc.runtimeType}');\n\n// RxMap, RxList and RxSet are special Rx types, that extends their native types.\n// but you can work with a List as a regular list, although is reactive!\nabc.add(12); // pushes 12 to the list, and UPDATES the stream.\nabc[3]; // like Lists, reads the index 3.\n\n\n// equality works with the Rx and the value, but hashCode is always taken from the value\nfinal number = 12.obs;\nprint( number == 12 ); // prints > true\n\n/// Custom Rx Models:\n\n// toJson(), toString() are deferred to the child, so you can implement override on them, and print() the observable directly.\n\nclass User {\n    String name, last;\n    int age;\n    User({this.name, this.last, this.age});\n\n    @override\n    String toString() => '$name $last, $age years old';\n}\n\nfinal user = User(name: 'John', last: 'Doe', age: 33).obs;\n\n// `user` is \"reactive\", but the properties inside ARE NOT!\n// So, if we change some variable inside of it...\nuser.value.name = 'Roi';\n// The widget will not rebuild!,\n// `Rx` don't have any clue when you change something inside user.\n// So, for custom classes, we need to manually \"notify\" the change.\nuser.refresh();\n\n// or we can use the `update()` method!\nuser.update((value){\n  value.name='Roi';\n});\n\nprint( user );\n```\n## StateMixin\n\nAnother way to handle your `UI` state is use the `StateMixin<T>` .\nTo implement it, use the `with` to add the `StateMixin<T>`\nto your controller which allows a T model.\n\n``` dart\nclass Controller extends GetController with StateMixin<User>{}\n```\n\nThe `change()` method change the State whenever we want.\nJust pass the data and the status in this way:\n\n```dart\nchange(data, status: RxStatus.success());\n```\n\nRxStatus allow these status:\n\n``` dart\nRxStatus.loading();\nRxStatus.success();\nRxStatus.empty();\nRxStatus.error('message');\n```\n\nTo represent it in the UI, use:\n\n```dart\nclass OtherClass extends GetView<Controller> {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n\n      body: controller.obx(\n        (state)=>Text(state.name),\n        \n        // here you can put your custom loading indicator, but\n        // by default would be Center(child:CircularProgressIndicator())\n        onLoading: CustomLoadingIndicator(),\n        onEmpty: Text('No data found'),\n\n        // here also you can set your own error widget, but by\n        // default will be an Center(child:Text(error))\n        onError: (error)=>Text(error),\n      ),\n    );\n}\n```\n\n#### গেট ভিউ (GetView)\n\nI love this Widget, is so simple, yet, so useful!\n\nIs a `const Stateless` Widget that has a getter `controller` for a registered `Controller`, that's all.\n\n```dart\n class AwesomeController extends GetController {\n   final String title = 'My Awesome View';\n }\n\n  // ALWAYS remember to pass the `Type` you used to register your controller!\n class AwesomeView extends GetView<AwesomeController> {\n   @override\n   Widget build(BuildContext context) {\n     return Container(\n       padding: EdgeInsets.all(20),\n       child: Text(controller.title), // just call `controller.something`\n     );\n   }\n }\n```\n\n#### গেট রেস্পন্সিভ ভিউ (GetResponsiveView)\n\nExtend this widget to build responsive view.\nthis widget contains the `screen` property that have all\ninformation about the screen size and type.\n\n##### কিভাবে এটি ব্যবহার করতে হয়\n\nYou have two options to build it.\n\n- with `builder` method you return the widget to build.\n- with methods `desktop`, `tablet`,`phone`, `watch`. the specific\n  method will be built when the screen type matches the method\n  when the screen is [ScreenType.Tablet] the `tablet` method\n  will be exuded and so on.\n  **Note:** If you use this method please set the property `alwaysUseBuilder` to `false`\n\nWith `settings` property you can set the width limit for the screen types.\n\n![example](https://github.com/SchabanBo/get_page_example/blob/master/docs/Example.gif?raw=true)\nCode to this screen\n[code](https://github.com/SchabanBo/get_page_example/blob/master/lib/pages/responsive_example/responsive_view.dart)\n\n#### গেট উইজেট (GetWidget)\n\nMost people have no idea about this Widget, or totally confuse the usage of it.\nThe use case is very rare, but very specific: It `caches` a Controller.\nBecause of the _cache_, can't be a `const Stateless`.\n\n> So, when do you need to \"cache\" a Controller?\n\nIf you use, another \"not so common\" feature of **GetX**: `Get.create()`.\n\n`Get.create(()=>Controller())` will generate a new `Controller` each time you call\n`Get.find<Controller>()`,\n\nThat's where `GetWidget` shines... as you can use it, for example,\nto keep a list of Todo items. So, if the widget gets \"rebuilt\", it will keep the same controller instance.\n\n#### গেট এক্স সার্ভিস (GetxService)\n\nThis class is like a `GetxController`, it shares the same lifecycle ( `onInit()`, `onReady()`, `onClose()`).\nBut has no \"logic\" inside of it. It just notifies **GetX** Dependency Injection system, that this subclass\n**can not** be removed from memory.\n\nSo is super useful to keep your \"Services\" always reachable and active with `Get.find()`. Like:\n`ApiService`, `StorageService`, `CacheService`.\n\n```dart\nFuture<void> main() async {\n  await initServices(); /// AWAIT SERVICES INITIALIZATION.\n  runApp(SomeApp());\n}\n\n/// Is a smart move to make your Services intiialize before you run the Flutter app.\n/// as you can control the execution flow (maybe you need to load some Theme configuration,\n/// apiKey, language defined by the User... so load SettingService before running ApiService.\n/// so GetMaterialApp() doesnt have to rebuild, and takes the values directly.\nvoid initServices() async {\n  print('starting services ...');\n  /// Here is where you put get_storage, hive, shared_pref initialization.\n  /// or moor connection, or whatever that's async.\n  await Get.putAsync(() => DbService().init());\n  await Get.putAsync(SettingsService()).init();\n  print('All services started...');\n}\n\nclass DbService extends GetxService {\n  Future<DbService> init() async {\n    print('$runtimeType delays 2 sec');\n    await 2.delay();\n    print('$runtimeType ready!');\n    return this;\n  }\n}\n\nclass SettingsService extends GetxService {\n  void init() async {\n    print('$runtimeType delays 1 sec');\n    await 1.delay();\n    print('$runtimeType ready!');\n  }\n}\n\n```\n\nThe only way to actually delete a `GetxService`, is with `Get.reset()` which is like a\n\"Hot Reboot\" of your app. So remember, if you need absolute persistence of a class instance during the\nlifetime of your app, use `GetxService`.\n\n\n### পরীক্ষা (Tests)\n\nYou can test your controllers like any other class, including their lifecycles:\n\n```dart\nclass Controller extends GetxController {\n  @override\n  void onInit() {\n    super.onInit();\n    //Change value to name2\n    name.value = 'name2';\n  }\n\n  @override\n  void onClose() {\n    name.value = '';\n    super.onClose();\n  }\n\n  final name = 'name1'.obs;\n\n  void changeName() => name.value = 'name3';\n}\n\nvoid main() {\n  test('''\nTest the state of the reactive variable \"name\" across all of its lifecycles''',\n      () {\n    /// You can test the controller without the lifecycle,\n    /// but it's not recommended unless you're not using\n    ///  GetX dependency injection\n    final controller = Controller();\n    expect(controller.name.value, 'name1');\n\n    /// If you are using it, you can test everything,\n    /// including the state of the application after each lifecycle.\n    Get.put(controller); // onInit was called\n    expect(controller.name.value, 'name2');\n\n    /// Test your functions\n    controller.changeName();\n    expect(controller.name.value, 'name3');\n\n    /// onClose was called\n    Get.delete<Controller>();\n\n    expect(controller.name.value, '');\n  });\n}\n```\n\n#### পরামর্শ\n\n##### Mockito or mocktail\nIf you need to mock your GetxController/GetxService, you should extend GetxController, and mixin it with Mock, that way\n\n```dart\nclass NotificationServiceMock extends GetxService with Mock implements NotificationService {}\n```\n\n##### Using Get.reset()\nIf 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.\n\n##### Get.testMode \nif you are using your navigation in your controllers, use `Get.testMode = true` at the beginning of your main.\n\n\n# 2.0 থেকে পরিবর্তন\n\n1- Rx এর প্রকারভেদ :\n\n| পূর্বে  | এখন      |\n| ------- | ---------- |\n| StringX | `RxString` |\n| IntX    | `RxInt`    |\n| MapX    | `RxMap`    |\n| ListX   | `RxList`   |\n| NumX    | `RxNum`    |\n| DoubleX | `RxDouble` |\n\nRxController এবং GetBuilder এখন একত্রিত, আপনি কোন নিয়ামক ব্যবহার করতে চান তা আর মুখস্ত করার দরকার নেই, শুধু GetxController ব্যবহার করুন, এটি সাধারণ স্টেট ব্যবস্থাপনা এবং প্রতিক্রিয়াশীল স্টেট ব্যবস্থাপনা এর জন্যও কাজ করবে।\n\n2- নেমড রুটস (NamedRoutes)\n\nআগে:\n\n```dart\nGetMaterialApp(\n  namedRoutes: {\n    '/': GetRoute(page: Home()),\n  }\n)\n```\n\nএখন:\n\n```dart\nGetMaterialApp(\n  getPages: [\n    GetPage(name: '/', page: () => Home()),\n  ]\n)\n```\n\nকেন এই পরিবর্তন? প্রায়শই, কোন পৃষ্ঠাটি প্যারামিটার বা লগইন টোকেন থেকে প্রদর্শিত হবে তা নির্ধারণ করার প্রয়োজন হতে পারে, পূর্ববর্তী পদ্ধতিটি অনমনীয় ছিল, কারণ এটি সেই অনুমতি দিতো না।\nএটি ফাংশনে পৃষ্ঠাটি ইনসার্ট করার জন্য উল্লেখযোগ্যভাবে RAM খরচ হ্রাস করেছে, যেহেতু অ্যাপটি শুরু হওয়ার পর থেকে রুটগুলি মেমরিতে বরাদ্দ করা হবে না, এটি এই ধরণের পদ্ধতিরও অনুমতি দেয়:\n\n```dart\n\nGetStorage box = GetStorage();\n\nGetMaterialApp(\n  getPages: [\n    GetPage(name: '/', page:(){\n      return box.hasData('token') ? Home() : Login();\n    })\n  ]\n)\n```\n"
  },
  {
    "path": "README-es.md",
    "content": "![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png)\n\n*Idiomas: Español (este archivo), [Vietnamita](README-vi.md), [Indonesio](README.id-ID.md), [Urdu](README.ur-PK.md), [Lengua china](README.zh-cn.md), [Inglés](README.md), [Portugués de Brasil](README.pt-br.md), [Ruso](README.ru.md), [Polaco](README.pl.md), [Coreano](README.ko-kr.md), [Francés](README-fr.md).*\n\n[![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)\n[![popularity](https://badges.bar/get/popularity)](https://pub.dev/packages/sentry/score)\n[![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)\n[![pub points](https://badges.bar/get/pub%20points)](https://pub.dev/packages/get/score)\n![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)\n[![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart)\n[![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N)\n[![Get on Slack](https://img.shields.io/badge/slack-join-orange.svg)](https://communityinviter.com/apps/getxworkspace/getx)\n[![Telegram](https://img.shields.io/badge/chat-on%20Telegram-blue.svg)](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g)\n<a href=\"https://github.com/Solido/awesome-flutter\">\n   <img alt=\"Awesome Flutter\" src=\"https://img.shields.io/badge/Awesome-Flutter-blue.svg?longCache=true&style=flat-square\" />\n</a>\n<a href=\"https://www.buymeacoffee.com/jonataslaw\" target=\"_blank\"><img src=\"https://i.imgur.com/aV6DDA7.png\" alt=\"Buy Me A Coffee\" style=\"height: 41px !important;width: 174px !important; box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;\" > </a>\n\n![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/getx.png)\n\n<h3>Lamentamos la inconsistencia en la traducción. El paquete GetX se actualiza con bastante frecuencia y es posible que las traducciones a documentos no sean tan rápidas. Entonces, para que esta documentación aún tenga todo el contenido, dejaré aquí todos los textos nuevos sin traducir (considero que es mejor tener los documentos en inglés que no tenerlos), por lo que si alguien quiere traducir, sería de gran ayuda 😁</h3>\n\n- [Sobre GetX](#sobre-getx)\n- [Instalación](#instalación)\n- [Proyecto contador con GetX](#proyecto-contador-con-getx)\n- [Los tres pilares](#los-tres-pilares)\n  - [Gestión del Estado](#gestión-del-estado)\n    - [Reactivo STATE_MANAGER](#reactivo-state_manager)\n    - [Más detalles sobre la gestión del estado.](#más-detalles-sobre-la-gestión-del-estado)\n    - [Explicación en video sobre state management](#explicación-en-video-sobre-state-management)\n  - [Gestión de Rutas](#gestión-de-rutas)\n    - [Más detalles sobre la gestión de rutas.](#más-detalles-sobre-la-gestión-de-rutas)\n    - [Explicación del video](#explicación-del-video)\n  - [Gestión de dependencias](#gestión-de-dependencias)\n    - [Más detalles sobre la gestión de dependencias.](#más-detalles-sobre-la-gestión-de-dependencias)\n- [Utilidades](#utilidades)\n  - [Cambiar de tema](#cambiar-de-tema)\n  - [Otras API avanzadas y configuraciones manuales](#otras-api-avanzadas-y-configuraciones-manuales)\n    - [Configuraciones globales opcionales](#configuraciones-globales-opcionales)\n  - [Video explanation of Other GetX Features](#video-explanation-of-other-getx-features)\n- [Cambios importantes desde 2.0](#cambios-importantes-desde-20)\n- [¿Por qué Getx?](#por-qué-getx)\n- [Comunidad](#comunidad)\n  - [Canales de la comunidad](#canales-de-la-comunidad)\n  - [Cómo contribuir](#cómo-contribuir)\n  - [Artículos y vídeos](#artículos-y-vídeos-inglés)\n\n# Sobre GetX\n\n- GetX es una solución extra ligera y potente para Flutter. Combina gestión de estádo de alto rendimiento, inyección de dependencia inteligente y gestión de rutas de forma rápida y práctica.\n\n- GetX tiene 3 principios básicos, esto significa que esta es la prioridad para todos los recursos de la biblioteca.\n  - **RENDIMIENTO:** GetX se centra en el rendimiento y el consumo mínimo de recursos. Los puntos de referencia casi siempre no son importantes en el mundo real, pero si lo desea, aquí hay un indicador de consumo.([benchmarks](https://github.com/jonataslaw/benchmarks)), donde GetX lo hace mejor que otros enfoques de gestión estatal, por ejemplo. La diferencia no es grande, pero muestra nuestra preocupación por no desperdiciar sus recursos.\n  - **PRODUCTIVIDAD:** GetX utiliza una sintaxis fácil y agradable.\n  - **ORGANIZACIÓN:** GetX permite el desacoplamiento total de la vista de la lógica de negocio.\n\n* GetX ahorrará horas de desarrollo y extraerá el máximo rendimiento que su aplicación puede ofrecer, siendo fácil para los principiantes y precisa para los expertos. Navega sin contexto, abre diálogos, snackbars o bottomsheets desde cualquier lugar de tu código, gestiona estados e inyecta dependencias de forma fácil y práctica. Get es seguro, estable, actualizado y ofrece una amplia gama de API que no están presentes en el marco predeterminado.\n\n- GetX no es bloated. Tiene una multitud de características que le permiten comenzar a programar sin preocuparse por nada, pero cada una de estas características se encuentran en contenedores separados y solo se inician después de su uso. Si solo usa State Management, solo se compilará State Management. Si solo usa rutas, no se compilará nada de la administración estatal. Puede compilar el repositorio de referencia y verá que al usar solo la administración de estado de Get, la aplicación compilada con Get se ha vuelto más pequeña que todas las demás aplicaciones que solo tienen la administración de estado de otros paquetes, porque nada que no se use se compilará en su código, y cada solución GetX fue diseñada para ser muy liviana. El mérito aquí también proviene del movimiento del árbol de Flutter, que es increíble y logra eliminar los recursos no utilizados como ningún otro marco lo hace.\n\n**GetX hace que su desarrollo sea productivo, pero ¿quiere hacerlo aún más productivo? [Agregue la extensión a su VSCode](https://marketplace.visualstudio.com/items?itemName=get-snippets.get-snippets)**\n\n# Instalación\n\nAñada la librería Get en tu archivo pubspec.yaml:\n\n```yaml\ndependencies:\n  get:\n```\n\nImporte Get en los archivos en los que se utilizará:\n\n```dart\nimport 'package:get/get.dart';\n```\n\n# Proyecto Contador con GetX\n\nVea una explicación más detallada de la administración del estado [aquí](./documentation/es_ES/state_management.md). Allí verá más ejemplos y también la diferencia entre el Gestión del Estado simple y el Gestión del Estado reactivo\n\nEl proyecto \"contador\" creado por defecto en un nuevo proyecto en Flutter tiene más de 100 líneas (con comentarios). Para mostrar el poder de GetX, demostraré cómo hacer un \"contador\" cambiando el estado con cada clic, cambiando de página y compartiendo el estado entre pantallas, todo de manera organizada, separando la vista de la lógica de negocio, SOLO 26 LÍNEAS DE CÓDIGO INCLUIDOS COMENTARIOS.\n\n- Paso 1: Agregue \"Get\" antes de su materialApp, convirtiéndolo en GetMaterialApp\n\n```dart\nvoid main() => runApp(GetMaterialApp(home: Home()));\n```\n\n**Nota**: esto no modifica el MaterialApp del Flutter, GetMaterialApp no es una MaterialApp modificado, es solo un Widget preconfigurado que tiene como child un MaterialApp por defecto. Puede configurar esto manualmente, pero definitivamente no es necesario. GetMaterialApp creará rutas, las inyectará, inyectará traducciones, inyectará todo lo que necesita para la navegación de rutas. Si usa Get solo para la gestión de estado o dependencias, no es necesario usar GetMaterialApp. GetMaterialApp es necesario para rutas, snackbars, internacionalización, bottomSheets, diálogos y APIs de alto nivel relacionadas con rutas y ausencia de contexto.\n\n**Nota²:** Este paso solo es necesario si va a usar route management (`Get.to()`, `Get.back()` y así). Si no lo va a usar, no es necesario que realice el paso 1\n\n- Paso 2: Cree su clase con la lógica de negocio colocando todas las variables, métodos y controladores dentro de ella. Puede hacer que cualquier variable sea observable usando un simple \".obs\".\n\n```dart\nclass Controller extends GetxController {\n  var count = 0.obs;\n  increment() => count.value++;\n}\n```\n\n- Paso 3: Cree su vista, use StatelessWidget y ahorre algo de RAM, con GetX ya no necesitará usar StatefulWidget.\n\n```dart\nclass Home extends StatelessWidget {\n\n  @override\n  Widget build(context) {\n\n    // Cree una instancia de su clase usando Get.put() para que esté disponible para todas las rutas \"secundarias\" allí.\n    final Controller c = Get.put(Controller());\n    \n    return Scaffold(\n      // Utilice Obx(()=> para actualizar Text() siempre que se cambie el recuento.\n      appBar: AppBar(title: Obx(() => Text(\"Clicks: \" + c.count.string))),\n\n      // Reemplace el Navigator.push de 8 líneas por un simple Get.to(). No necesitas contexto\n      body: Center(child: ElevatedButton(\n              child: Text(\"Go to Other\"), onPressed: () => Get.to(Other()))),\n      floatingActionButton:\n          FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment));\n  }\n}\n\nclass Other extends StatelessWidget {\n  // Puede pedirle a Get que busque un controlador que está siendo utilizado por otra página y le redirija a él.\n  final Controller c = Get.find();\n\n  @override\n  Widget build(context){\n     // Acceder a la variable de recuento actualizada\n     return Scaffold(body: Center(child: Text(c.count.string)));\n  }\n}\n\n```\n\nResultado:\n\n![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/counter-app-gif.gif)\n\nEste es un proyecto simple pero ya deja en claro cuán poderoso es GetX. A medida que su proyecto crezca, esta diferencia se volverá más significativa. GetX fue diseñado para trabajar con equipos, pero también simplifica el trabajo de un desarrollador individual. Mejore sus plazos, entregue todo a tiempo, sin perder rendimiento. GetX no es para todos, pero si te identificaste con esa frase, ¡GET es para ti!\n\n# Los tres pilares\n\n## Gestión del Estado\n\nActualmente hay varios State Managers para Flutter. Sin embargo, con la mayoría de ellos implica utilizar ChangeNotifier para actualizar widgets y este es un enfoque malo y muy malo para el rendimiento de aplicaciones medianas o grandes. Puede verificar en la documentación oficial de Flutter que [ChangeNotifier debe usarse con 1 o un máximo de 2 listeners](https://api.Flutter.dev/Flutter/foundation/ChangeNotifier-class.html), por lo que es prácticamente inutilizable para cualquier aplicación mediana o grande.\n\nGetX no es mejor ni peor que cualquier otro gestor de estado, pero debe analizar estos puntos, así como los puntos que se mencionan a continuación, para elegir entre usar GetX en forma pura (vanilla) o usarlo junto con otro gestor de estado.\n\nDefinitivamente, GetX no es enemigo de ningún otro gestor de estado, porque GetX es más bien un microframework, no solo un gestor de estado, y se puede usar solo o en combinación con ellos.\n\n### Reactivo STATE_MANAGER\n\nLa programación reactiva puede alienar a muchas personas porque se dice que es complicada. GetX convierte la programación reactiva en algo tan simple que puede ser aprendido y utilizado por aquellos que comenzaron en ese mismo momento en Flutter. No, no necesitará crear StreamControllers. Tampoco necesitará crear un StreamBuilder para cada variable. No necesitará crear una clase para cada estado. No necesitará crear un get para un valor inicial. La programación reactiva con GetX es tan fácil como usar setState (¡o incluso más fácil!).\n\nImaginemos que tiene una variable \"name\" y desea que cada vez que la modifique, todos los widgets que la usan cambien automáticamente.\n\nEj. esta es tu variable \"name\":\n\n```dart\nvar name = 'Jonatas Borges';\n```\n\nPara que sea observable, solo necesita agregar \".obs\" al final:\n\n```dart\nvar name = 'Jonatas Borges'.obs;\n```\n\n¿StreamBuilder? ¿initialValue? ¿builder? No, solo necesitas jugar con esta variable dentro de un widget Obx.\n\n```dart\nObx(() => Text (controller.name));\n```\n\n### Más detalles sobre la gestión del estado.\n\n**Vea una explicación más detallada de la administración del estado [aquí](./documentation/es_ES/state_management.md). Allí verá más ejemplos y también la diferencia entre el Gestión del Estado simple y el Gestión del Estado reactivo**\n\n### Explicación en video sobre state management\n\nDarwin Morocho hizo una increíble serie de videos sobre state management! Link: [Complete GetX State Management](https://www.youtube.com/watch?v=PTjj0DFK8BA&list=PLV0nOzdUS5XtParoZLgKoVwNSK9zROwuO)\n\nObtendrá una buena idea de la potencia de GetX.\n\n## Gestión de Rutas\n\nPara navegar a una nueva pantalla:\n\n```dart\nGet.to(NextScreen());\n```\n\nPara cerrar snackbars, dialogs, bottomsheets o cualquier cosa que normalmente cierre con Navigator.pop(contexto);\n\n```dart\nGet.back();\n```\n\nPara ir a la siguiente pantalla, sin opción a volver (util por ejemplo en SplashScreens, LoginScreen, etc.)\n\n```dart\nGet.off(NextScreen());\n```\n\nPara ir a la siguiente pantalla y cancelar todas las rutas anteriores (útil en carritos de compras, encuestas y exámenes)\n\n```dart\nGet.offAll(NextScreen());\n```\n\nPara navegar a la siguiente ruta y recibir o actualizar datos tan pronto como se regrese de ella:\n\n```dart\nvar data = await Get.to(Payment());\n```\n\n### Más detalles sobre la gestión de rutas.\n\n**Vea una explicación más detallada de la Gestión de Rutas [aquí](./documentation/es_ES/route_management.md).**\n\n### Explicación del video\n\nAmateur Coder hizo un excelente video que cubre route management con Get! aquí esta el link: [Complete Getx Navigation](https://www.youtube.com/watch?v=RaqPIoJSTtI)\n\n## Gestión de dependencias\n\n- Nota: si está utilizando el gestor de estado de GetX, no tiene que preocuparse por esto, solo lea para obtener información, pero preste más atención a la API de bindings, que hará todo esto automáticamente por usted.\n\n¿Ya estás utilizando GetX y quieres que tu proyecto sea lo más ágil posible? GetX tiene un gestor de dependencias simple y poderoso que le permite recuperar la misma clase que su BLoC o Controller con solo una líneas de código, sin contexto de Provider, sin inheritedWidget:\n\n```dart\nController controller = Get.put(Controller()); // Rather Controller controller = Controller();\n```\n\nEn lugar de crear una instancia de su clase dentro de la clase que está utilizando, la está creando dentro de la instancia GetX, que la hará disponible en toda su aplicación. Entonces puede usar su Controller (o BLoC) normalmente.\n\n```dart\ncontroller.fetchApi();\n```\n\nImagine que ha navegado a través de numerosas rutas y necesita datos que quedaron en su controlador, necesitaría un gestor de estado combinado con Provider o Get_it, ¿correcto? No con GetX. Solo necesita pedirle a GetX que \"encuentre\" su controlador, no necesita dependencias adicionales:\n\n```dart\nController controller = Get.find();\n//Sí, parece que es magia, Get encontrará su controlador y se lo entregará. Puede tener 1 millón de controladores instanciados, Get siempre le dará el controlador correcto.\n```\n\nY luego podrá recuperar los datos de su controlador que se obtuvieron allí:\n\n```dart\nText(controller.textFromApi);\n```\n\n¿Buscando lazy loading? Puede declarar todos sus controladores, y se llamará solo cuando alguien lo necesite. Puedes hacer esto con:\n\n```dart\nGet.lazyPut<Service>(()=> ApiMock());\n/// ApiMock solo se llamará cuando alguien use Get.find<Service> por primera vez\n```\n\n### Más detalles sobre la gestión de dependencias.\n\n**Vea una explicación más detallada de la Gestión de dependencias [aquí](./documentation/es_ES/dependency_management.md).**\n\n# Utilidades\n\n## Cambiar de tema\n\nNo utilice ningún widget de nivel superior que GetMaterialApp para actualizarlo. Esto puede activar claves duplicadas. Mucha gente está acostumbrada al enfoque prehistórico de crear un widget \"ThemeProvider\" solo para cambiar el tema de su aplicación, y esto definitivamente NO es necesario con GetX.\n\nPuede crear su tema personalizado y simplemente agregarlo dentro de Get.changeTheme sin ningún boilerplate para eso:\n\n```dart\nGet.changeTheme(ThemeData.light());\n```\n\nSi desea crear algo así como un botón que cambia el tema con onTap, puede combinar dos APIs GetX para eso, la API que verifica si se está utilizando el tema oscuro y la API de cambio de tema, simplemente puede poner esto dentro de un onPressed:\n\n```dart\nGet.changeTheme(Get.isDarkMode? ThemeData.light(): ThemeData.dark());\n```\n\nCuando el modo oscuro está activado, cambiará al tema claro, y cuando el tema claro esté activado, cambiará a oscuro.\n\nSi quieres saber en profundidad cómo cambiar el tema, puedes seguir este tutorial en Medium que incluso enseña la persistencia del tema usando GetX:\n\n- [Temas dinámicos en 3 líneas usando GetX](https://medium.com/swlh/flutter-dynamic-themes-in-3-lines-c3b375f292e3) - Tutorial de [Rod Brown](https://github.com/RodBr).\n\n## Otras API avanzadas y configuraciones manuales\n\nGetMaterialApp configura todo para usted, pero si desea configurar GetX manualmente utilizando APIs avanzadas.\n\n```dart\nMaterialApp(\n  navigatorKey: Get.key,\n  navigatorObservers: [GetObserver()],\n);\n```\n\nTambién podrá usar su propio Middleware dentro de GetObserver, esto no influirá en nada.\n\n```dart\nMaterialApp(\n  navigatorKey: Get.key,\n  navigatorObservers: [GetObserver(MiddleWare.observer)], // Here\n);\n```\n\n```dart\n// dar los argumentos actuales de currentScreen\nGet.arguments\n\n// dar el nombre de la ruta anterior\nGet.previousRoute\n\n// dar la ruta sin procesar para acceder, por ejemplo, rawRoute.isFirst()\nGet.rawRoute\n\n// dar acceso a Routing API desde GetObserver\nGet.routing\n\n// comprobar si la cafetería está abierta\nGet.isSnackbarOpen\n\n// comprobar si el diálogo está abierto\nGet.isDialogOpen\n\n// comprobar si  bottomsheet está abierto\nGet.isBottomSheetOpen\n\n// eliminar una ruta.\nGet.removeRoute()\n\n// volver repetidamente hasta que predicate devuelva verdadero.\nGet.until()\n\n//ir a la siguiente ruta y eliminar todas las rutas anteriores hasta que predicate devuelva verdadero.\nGet.offUntil()\n\n// ir a la siguiente ruta con nombre y eliminar todas las rutas anteriores hasta que predicate devuelve verdadero.\nGet.offNamedUntil()\n\n//Verifique en qué plataforma se ejecuta la aplicación\nGetPlatform.isAndroid\nGetPlatform.isIOS\nGetPlatform.isWeb\n\n// Equivalente al método: MediaQuery.of(context).size.height, pero son inmutables.\nGet.height\nGet.width\n\n// Da el contexto de la pantalla en primer plano en cualquier parte de su código.\nGet.context\n\n// Da el contexto de la barra de bocadillos / diálogo / hoja inferior en primer plano en cualquier parte de su código.\nGet.contextOverlay\n\n// Note: los siguientes métodos son extensiones de context. Desde que tu\n// tiene acceso al contexto en cualquier lugar de su interfaz de usuario, puede usarlo en cualquier lugar del código de la interfaz de usuario\n\n// Si necesita un cambiable height/width (como las ventanas del navegador que se pueden escalar) necesitará usar context.\ncontext.width\ncontext.height\n\n\n\n// le da el poder de definir la mitad de la pantalla ahora, un tercio y así sucesivamente.\n// Útil para aplicaciones receptivas.\n// param dividedBy (double) optional - default: 1\n// param reducedBy (double) optional - default: 0\ncontext.heightTransformer()\ncontext.widthTransformer()\n\n/// Similar a MediaQuery.of(context).size\ncontext.mediaQuerySize()\n\n/// similar a MediaQuery.of(context).padding\ncontext.mediaQueryPadding()\n\n/// similar a MediaQuery.of(context).viewPadding\ncontext.mediaQueryViewPadding()\n\n/// similar a MediaQuery.of(context).viewInsets;\ncontext.mediaQueryViewInsets()\n\n/// similar a MediaQuery.of(context).orientation;\ncontext.orientation()\n\n/// comprobar si el dispositivo esta en landscape mode\ncontext.isLandscape()\n\n/// comprobar si el dispositivo esta en portrait mode\ncontext.isPortrait()\n\n/// similar a MediaQuery.of(context).devicePixelRatio;\ncontext.devicePixelRatio()\n\n/// similar a MediaQuery.of(context).textScaleFactor;\ncontext.textScaleFactor()\n\n/// obtener el lado más corto de la pantalla\ncontext.mediaQueryShortestSide()\n\n/// Verdadero si el ancho es mayor que 800\ncontext.showNavbar()\n\n/// Verdadero si el lado más corto es menor que 600p\ncontext.isPhone()\n\n/// Verdadero si el lado más corto es más grande que 600p\ncontext.isSmallTablet()\n\n/// Verdadero si el lado más corto es mayor que 720p\ncontext.isLargeTablet()\n\n/// Verdadero si el dispositivo actual es una tableta\ncontext.isTablet()\n```\n\n### Configuraciones globales opcionales\n\nPuede crear configuraciones globales para GetX. Simplemente agregue Get.config a su código antes de insertar cualquier ruta o hágalo directamente en su GetMaterialApp\n\n```dart\nGetMaterialApp(\n  enableLog: true,\n  defaultTransition: Transition.fade,\n  opaqueRoute: Get.isOpaqueRouteDefault,\n  popGesture: Get.isPopGestureEnable,\n  transitionDuration: Get.defaultDurationTransition,\n  defaultGlobalState: Get.defaultGlobalState,\n);\n\nGet.config(\n  enableLog = true,\n  defaultPopGesture = true,\n  defaultTransition = Transitions.cupertino\n)\n```\n\nOpcionalmente, puede redirigir todos los mensajes de registro de Get. Si desea utilizar su propio paquete de registro favorito y desea capturar los registros allí.\n\n```dart\nGetMaterialApp(\n  enableLog: true,\n  logWriterCallback: localLogWriter,\n);\n\nvoid localLogWriter(String text, {bool isError = false}) {\n // pase el mensaje a su paquete de registro favorito aquí\n  //Nota: incluso si los mensajes de registro están desactivados\n  // con el comando \"enableLog: false\", los mensajes seguirán pasando por aquí\n  // Debe verificar esta configuración manualmente aquí si desea respetarla\n}\n\n```\n\n## Video explanation of Other GetX Features\n\nAmateur Coder hizo un video asombroso sobre utilidades, almacenamiento, enlaces y otras características! Link: [GetX Other Features](https://youtu.be/ttQtlX_Q0eU)\n\n# Cambios importantes desde 2.0\n\n1- Rx types:\n\n| Antes   | Ahora      |\n| ------- | ---------- |\n| StringX | `RxString` |\n| IntX    | `RxInt`    |\n| MapX    | `RxMap`    |\n| ListX   | `RxList`   |\n| NumX    | `RxNum`    |\n| DoubleX | `RxDouble` |\n\nRxController y GetBuilder ahora se han fusionado, ya no necesita memorizar qué controlador desea usar, solo use GetXController, funcionará para gestión de estádo simple y también para reactivo.\n\n2- Rutas Nombradas\n\nAntes:\n\n```dart\nGetMaterialApp(\n  namedRoutes: {\n    '/': GetRoute(page: Home()),\n  }\n)\n```\n\nAhora:\n\n```dart\nGetMaterialApp(\n  getPages: [\n    GetPage(name: '/', page: () => Home()),\n  ]\n)\n```\n\n¿Por qué este cambio?\n\nA 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.\n\nInsertar la página en una función ha reducido significativamente el consumo de RAM, ya que las rutas no se asignarán en la memoria desde que se inició la aplicación, y también permitió hacer este tipo de enfoque:\n\n```dart\nGetStorage box = GetStorage();\n\nGetMaterialApp(\n  getPages: [\n    GetPage(name: '/', page:(){\n      return box.hasData('token') ? Home() : Login();\n    })\n  ]\n)\n```\n\n# ¿Por qué Getx?\n\n1- Después de una actualización de Flutter, muchos paquetes suelen romperse. A veces se producen errores de compilación, errores de los que aún no hay respuestas y el desarrollador necesita saber el origen del error, poder rastrear, y solo entonces intentar abrir un issue en el repositorio correspondiente, para finalmente ver su problema resuelto. Getx centraliza los principales recursos para el desarrollo (gestión de estado, dependencia y rutas), lo que le permite agregar un único paquete a su pubspec y comenzar a trabajar. Después de una actualización de Flutter, lo único que debe hacer es actualizar la dependencia Get y ponerse a trabajar. Get también resuelve problemas de compatibilidad. ¿Cuántas veces una versión de un paquete no es compatible con la versión de otro, porque una usa una dependencia en una versión y la otra en otra? Tampoco es una preocupación usando Get, ya que todo estará en el mismo paquete y será totalmente compatible.\n\n2- Flutter es fácil, Flutter es increíble, pero todavía tiene algo repetitivo que puede ser no deseado para la mayoría de los desarrolladores, como `Navigator.of(context).push (context, builder [...]`. Get simplifica el desarrollo. En lugar de escribir 8 líneas de código para simplemente llamar a una ruta, simplemente puede hacerlo: `Get.to(Home())` y listo, irá a la página siguiente. Algo doloroso de hacer con Flutter actualmente, mientras que con GetX es estúpidamente simple. Gestionar estados en Flutter y dependencias también es algo que genera mucho debate, ya que hay cientos de patrones en el pub. Pero no hay nada tan fácil como agregar un \".obs\" al final de su variable, y colocar su widget dentro de un Obx, y eso es todo, todas las actualizaciones de esa variable se actualizarán automáticamente en la pantalla.\n\n3- Facilidad sin preocuparse por el rendimiento. El rendimiento de Flutter ya es sorprendente, pero imagine que usa un gestor de estado y un localizador para distribuir sus clases de bloc/stores/controllers/ etc. Tendrá que llamar manualmente a la exclusión de esa dependencia cuando no la necesite. Pero, ¿alguna vez pensó en simplemente usar el controlador, y cuando ya no sea necesario, simplemente se elimine de la memoria? Eso es lo que hace GetX. Con SmartManagement, todo lo que no se está utilizando se elimina de la memoria, y no debería tener que preocuparse por nada más que la programación. Se le garantiza el consumo mínimo de recursos, sin siquiera haber creado una lógica para esto.\n\n4- Desacoplamiento real. Es posible que haya escuchado la idea de \"separar la vista de la lógica de negocio\". Esta no es una peculiaridad de BLoC, MVC, MVVM, cualquier otro estándar en el mercado tiene este concepto. Sin embargo, a menudo se puede mitigar en Flutter debido al uso del contexto.\nSi necesita contexto para encontrar un InheritedWidget, lo necesita en la vista o pasado por parámetro. En particular, encuentro esta solución muy fea, y para trabajar en equipo siempre tendremos una dependencia de la lógica de negocios de la vista. Getx no es ortodoxo con el enfoque estándar, y aunque no prohíbe completamente el uso de StatefulWidgets, InitState, etc., siempre tiene un enfoque similar que puede ser más limpio. Los controladores tienen ciclos de vida, y cuando necesita hacer una solicitud API REST, por ejemplo, no depende de nada en la vista. Puede usar onInit para iniciar la llamada http, y cuando lleguen los datos, se rellenarán las variables. Como GetX es completamente reactivo (realmente, y funciona bajo streams), una vez que se llenan los elementos, todos los widgets que usan esa variable se actualizarán automáticamente en la vista. Esto permite que las personas con experiencia en IU trabajen solo con widgets y no tengan que enviar nada a la lógica de negocios que no sean eventos de usuario (como hacer clic en un botón), mientras que las personas que trabajan con lógica de negocios podrán crearla y probarla por separado.\n\nEsta librería siempre se actualizará e implementará nuevas características. Siéntase libre de ofrecer PRs y contribuir a ellas.\n\n# Comunidad\n\n## Canales de la comunidad\n\nGetX tiene una comunidad muy activa e implicada. Si tiene dudas, o necesita cualquier tipo de asistencia sobre el uso de este framework, no dude en unirse a nuestr, tu duda será resuelta lo antes posible. Este repositorio es de uso exclusivo para abrir issues, pero siéntase libre de unirse a la Comunidad de GetX.\n\n\n| **Slack (🇬🇧)**                                                                                                                   | **Discord (🇬🇧 y 🇵🇹)**                                                                                                                 | **Telegram (🇵🇹)**                                                                                                          |\n| :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------- |\n| [![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) |\n\n\n# Cómo contribuir\n\n_¿Quieres contribuir al proyecto? Estaremos orgullosos de destacarte como uno de nuestros colaboradores. Aquí hay algunos puntos en los que puede contribuir y hacer que GetX (y Flutter) sea aún mejor._\n\n- Ayudando a traducir el archivo Léame a otros idiomas.\n\n- Agregar documentación al archivo Léame (ni siquiera la mitad de las funciones de GetX han sido documentadas todavía).\n\n- Escriba artículos o haga videos que enseñen cómo usar GetX (se insertarán en el archivo Léame y en el futuro en nuestro Wiki).\n\n- Ofreciendo PRs para código/pruebas.\n\n- Incluyendo nuevas funciones.\n\n¡Cualquier contribución es bienvenida!\n\n## Artículos y vídeos (inglés)\n\n- [Flutter Getx EcoSystem package for arabic people](https://www.youtube.com/playlist?list=PLV1fXIAyjeuZ6M8m56zajMUwu4uE3-SL0) - Tutorial by [Pesa Coder](https://github.com/UsamaElgendy).\n- [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).\n- [Complete GetX™ Navigation](https://www.youtube.com/watch?v=RaqPIoJSTtI) - Route management video by Amateur Coder.\n- [Complete GetX State Management](https://www.youtube.com/watch?v=CNpXbeI_slw) - State management video by Amateur Coder.\n- [GetX™ Other Features](https://youtu.be/ttQtlX_Q0eU) - Utils, storage, bindings and other features video by Amateur Coder.\n- [Firestore User with GetX | Todo App](https://www.youtube.com/watch?v=BiV0DcXgk58) - Video by Amateur Coder.\n- [Firebase Auth with GetX | Todo App](https://www.youtube.com/watch?v=-H-T_BSgfOE) - Video by Amateur Coder.\n- [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).\n- [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).\n- [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.\n- [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.\n- [GetX Flutter Firebase Auth Example](https://medium.com/@jeffmcmorris/getx-flutter-firebase-auth-example-b383c1dd1de2) - Article by Jeff McMorris.\n- [Flutter State Management with GetX – Complete App](https://www.appwithflutter.com/flutter-state-management-with-getx/) - by App With Flutter.\n- [Flutter Routing with Animation using Get Package](https://www.appwithflutter.com/flutter-routing-using-get-package/) - by App With Flutter.\n- [A minimal example on dartpad](https://dartpad.dev/2b3d0d6f9d4e312c5fdbefc414c1727e?) - by [Roi Peker](https://github.com/roipeker)\n"
  },
  {
    "path": "README-fr.md",
    "content": "![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png)\n\n**Langues: Français (Ce fichier), [Anglais](README.md), [Vietnamien](README-vi.md), [Indonésien](README.id-ID.md), [Urdu](README.ur-PK.md), [Chinois](README.zh-cn.md), [Portuguais du Brésil](README.pt-br.md), [Espagnol](README-es.md), [Russe](README.ru.md), [Polonais](README.pl.md), [Koréen](README.ko-kr.md).**\n\n[![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)\n[![popularity](https://badges.bar/get/popularity)](https://pub.dev/packages/sentry/score)\n[![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)\n[![pub points](https://badges.bar/get/pub%20points)](https://pub.dev/packages/get/score)\n![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)\n[![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart)\n[![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N)\n[![Get on Slack](https://img.shields.io/badge/slack-join-orange.svg)](https://communityinviter.com/apps/getxworkspace/getx)\n[![Telegram](https://img.shields.io/badge/chat-on%20Telegram-blue.svg)](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g)\n<a href=\"https://github.com/Solido/awesome-flutter\">\n<img alt=\"Awesome Flutter\" src=\"https://img.shields.io/badge/Awesome-Flutter-blue.svg?longCache=true&style=flat-square\" />\n</a>\n<a href=\"https://www.buymeacoffee.com/jonataslaw\" target=\"_blank\"><img src=\"https://i.imgur.com/aV6DDA7.png\" alt=\"Achetez moi un cafe\" style=\"height: 41px !important;width: 174px !important; box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;\" > </a>\n\n![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/getx.png)\n\n- [A Propos de Get](#a-propos-de-get)\n- [Installation](#installation)\n- [L'application 'Counter' avec GetX](#application-counter-avec-getx)\n- [Les trois pilliers](#les-trois-pilliers)\n  - [Gestion d'état (State management)](#gestion-d-etat)\n    - [Gestionnaire d'état réactif (Reactive State Manager)](#gestionnaire-d-etat-reactif)\n    - [Plus de détails sur la gestion d'état](#plus-de-details-sur-la-gestion-d-etat)\n  - [Gestion de route](#gestion-de-route)\n    - [Plus de détails sur la gestion de route](#plus-de-details-sur-la-gestion-de-route)\n  - [Gestion des dépendances](#gestion-des-dependances)\n    - [Plus de détails sur la gestion des dépendances](#plus-de-details-sur-la-gestion-des-dependances)\n- [Utils](#utils)\n  - [Internationalization](#internationalization)\n    - [Traductions](#traductions)\n      - [Utiliser les traductions](#utiliser-les-traductions)\n    - [Locales](#locales)\n      - [Changer la locale](#changer-la-locale)\n      - [Locale du Système](#locale-du-systeme)\n  - [Changer le Thème](#changer-le-theme)\n  - [GetConnect](#getconnect)\n    - [Configuration par défaut](#configuration-par-defaut)\n    - [Configuration personnalisée](#configuration-personnalisee)\n  - [Middleware GetPage](#middleware-getpage)\n    - [Priority](#priority)\n    - [Redirect](#redirect)\n    - [onPageCalled](#onpagecalled)\n    - [OnBindingsStart](#onbindingsstart)\n    - [OnPageBuildStart](#onpagebuildstart)\n    - [OnPageBuilt](#onpagebuilt)\n    - [OnPageDispose](#onpagedispose)\n  - [Autres APIs](#autres-apis)\n    - [Paramètres globaux et configurations manuelles facultatifs](#parametres-globaux-et-configurations-manuelles-facultatifs)\n    - [State Widgets Locaux](#state-widgets-locaux)\n      - [ValueBuilder](#valuebuilder)\n      - [ObxValue](#obxvalue)\n  - [Conseils utiles](#conseils-utiles)\n    - [GetView](#getview)\n    - [GetResponsiveView](#getresponsiveview)\n      - [Guide d'utilisation](#guide-d-utilisation)\n    - [GetWidget](#getwidget)\n    - [GetxService](#getxservice)\n- [Changements par rapport à 2.0](#changements-par-rapport-a-20)\n- [Pourquoi Getx?](#pourquoi-getx)\n- [Communité](#communite)\n  - [Chaînes communautaires](#chaines-communautaires)\n  - [Comment contribuer](#comment-contribuer)\n  - [Articles et videos](#articles-et-videos)\n\n# A Propos de Get\n\n- GetX est une solution extra-légère et puissante pour Flutter. Il combine une gestion d'état (state management) de haute performance, une injection de dépendances (dependency injection) intelligente et une gestion de route (route management) rapide et pratique.\n\n- GetX a 3 principes de base. Cela signifie que ces principes sont les priorités pour toutes les ressources de la bibliothèque GetX: **PRODUCTIVITÉ, PERFORMANCE ET ORGANIZATION.**\n\n  - **PERFORMANCE:** GetX se concentre sur la performance et la consommation minimale de ressources. GetX n'utilise ni Streams ni ChangeNotifier.\n\n  - **PRODUCTIVITÉ:** GetX utilise une syntaxe simple et agréable. Peu importe ce que vous voulez faire, il existe toujours un moyen plus simple avec GetX. Cela économisera des heures de développement et fournira les performances maximales que votre application peut offrir.\n\n    En règle générale, le développeur doit s'occuper lui-même de la suppression des contrôleurs de la mémoire. Avec GetX, cela n'est pas nécessaire car les ressources sont, par défaut, supprimées de la mémoire lorsqu'elles ne sont pas utilisées. Si vous souhaitez les conserver en mémoire, vous devez déclarer explicitement \"permanent: true\" comme paramètre lors de la création de la ressource. De cette façon, en plus de gagner du temps, vous risquez moins d'avoir des ressources inutiles dans la mémoire. L'initialisation des ressources est également 'lazy' par défaut (i.e. se fait seulement lorsque la ressource est nécessaire).\n\n  - **ORGANIZATION:** GetX permet le découplage total de la Vue (View), de la Logique de Présentation (Presentation Logic), de la Business Logic, de l'injection de dépendances (Dependency Injection) et de la Navigation. Vous n'avez pas besoin de contexte pour naviguer entre les routes, vous n'êtes donc pas dépendant de la hiérarchisation des widgets (visualisation) pour cela. Vous n'avez pas besoin de 'context' pour accéder à vos contrôleurs/blocs via un inheritedWidget, vous dissociez donc complètement votre logique de présentation (Vue) et votre Business logic de votre couche de visualisation. Vous n'avez pas besoin d'injecter vos classes Controlleûrs / Modèles / Blocs le long de la hiérarchie de Widgets via `MultiProvider`. Pour cela, GetX utilise sa propre fonction d'injection de dépendances (DI), découplant complètement la DI de sa Vue.\n\n    Avec GetX, vous savez où trouver chaque module de votre application, avec un code propre par défaut. En plus de rendre la maintenance facile, cela rend le partage de modules quelque chose qui jusque-là dans Flutter était impensable, quelque chose de totalement possible.\n    BLoC était un point de départ pour organiser le code dans Flutter, il sépare la Business logic de la visualisation. GetX en est une évolution naturelle, séparant non seulement la Business logic mais aussi la logique de présentation. L'injection de dépendances et les routes sont également découplées, et la couche de données est séparée du tout. Vous savez où tout se trouve, et tout cela d'une manière plus facile que de construire un 'Hello World''.\n    GetX est le moyen le plus simple, pratique et évolutif de créer des applications hautes performances avec le SDK Flutter. Il possède un vaste écosystème qui fonctionne parfaitement, c'est facile pour les débutants et 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.\n\n- GetX possède une multitude de fonctionnalités qui vous permettent de démarrer la programmation sans vous soucier de quoi que ce soit, mais chacune de ces fonctionnalités se trouve dans des conteneurs séparés et ne démarre qu'après utilisation. Si vous n'utilisez que la gestion des états (State Management), seule la gestion des états sera compilée. Si vous n'utilisez que des routes, rien de la gestion d'état ne sera compilé.\n\n- GetX a un énorme écosystème, une grande communauté, un grand nombre de collaborateurs, et sera maintenu tant que Flutter existera. GetX est également capable de fonctionner avec le même code sur Android, iOS, Web, Mac, Linux, Windows et sur votre serveur. Il est possible de réutiliser entièrement votre code créé sur le frontend et le backend avec Get Server.\n  **Il est possible d'entièrement réutiliser votre code écrit sur le frontend, pour le backend avec [Get Server](https://github.com/jonataslaw/get_server)**.\n\n**De plus, l'ensemble du processus de développement peut être complètement automatisé, à la fois sur le serveur et sur le front-end avec [Get CLI](https://github.com/jonataslaw/get_cli)**.\n\n**De plus, pour augmenter encore 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)**\n\n# Installation\n\nAjoutez Get à votre fichier pubspec.yaml:\n\n```yaml\ndependencies:\n  get:\n```\n\nImportez Get dans les fichiers dans lesquels il doit être utilisé:\n\n```dart\nimport 'package:get/get.dart';\n```\n\n# Application Counter avec Getx\n\nLe projet \"Counter\" créé par défaut sur chaque nouveau projet Flutter comporte plus de 100 lignes (avec commentaires). Pour montrer la puissance de Get, je vais vous montrer comment faire un \"compteur\" changeant d'état à chaque clic, naviguer entre les pages et partager l'état entre les écrans, le tout de manière organisée, en séparant la Business logic de la Vue, en SEULEMENT 26 LIGNES DE CODE INCLUANT LES COMMENTAIRES.\n\n- Step 1:\n  Ajoutez \"Get\" avant MaterialApp, pour le transformer en GetMaterialApp\n\n```dart\nvoid main() => runApp(GetMaterialApp(home: Home()));\n```\n\n- Note: cela ne modifie pas le MaterialApp de Flutter, GetMaterialApp n'est pas un MaterialApp modifié, il s'agit simplement d'un widget préconfiguré, qui a le MaterialApp par défaut comme enfant (child: ). Vous pouvez le configurer manuellement, mais ce n'est certainement pas nécessaire. GetMaterialApp créera des routes, les injectera, injectera les traductions, injectera tout ce dont vous avez besoin pour la navigation de routes. Si vous utilisez Get uniquement pour la gestion de l'état (State management) ou la gestion des dépendances (DI), il n'est pas nécessaire d'utiliser GetMaterialApp. GetMaterialApp est nécessaire pour les routes, les 'snackbars', l'internationalisation, les 'bottomSheets', les dialogues et les API de haut niveau liés aux routes et à l'absence de 'context'.\n\n- Note²: Cette étape n'est nécessaire que si vous allez utiliser la gestion de routes (Get.to(), Get.back(), etc). Si vous ne l'utiliserez pas, il n'est pas nécessaire de faire l'étape 1.\n\n- Step 2:\n  Créez votre classe de Business logic et placez-y toutes les variables, méthodes et contrôleurs.\n  Vous pouvez rendre toute variable observable en utilisant un simple \".obs\".\n\n```dart\nclass Controller extends GetxController{\n  var count = 0.obs;\n  increment() => count++;\n}\n```\n\n- Step 3:\n  Créez votre Vue, utilisez StatelessWidget et économisez de la RAM, avec Get, vous n'aurez peut-être plus besoin d'utiliser StatefulWidget.\n\n```dart\nclass Home extends StatelessWidget {\n\n  @override\n  Widget build(context) {\n\n    // Instanciez votre classe en utilisant Get.put() pour le rendre disponible pour tous les routes \"descendantes\".\n    final Controller c = Get.put(Controller());\n\n    return Scaffold(\n      // Utilisez Obx(()=> pour mettre à jour Text() chaque fois que count est changé.\n      appBar: AppBar(title: Obx(() => Text(\"Clicks: ${c.count}\"))),\n\n      // Remplacez les 8 lignes Navigator.push par un simple Get.to(). Vous n'avez pas besoin de 'context'\n      body: Center(child: ElevatedButton(\n              child: Text(\"Go to Other\"), onPressed: () => Get.to(Other()))),\n      floatingActionButton:\n          FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment));\n  }\n}\n\nclass Other extends StatelessWidget {\n  // Vous pouvez demander à Get de trouver un contrôleur utilisé par une autre page et de vous y rediriger.\n  final Controller c = Get.find();\n\n  @override\n  Widget build(context){\n     // Accéder à la variable 'count' qui est mise à jour\n     return Scaffold(body: Center(child: Text(\"${c.count}\")));\n  }\n}\n```\n\nRésultat:\n\n![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/counter-app-gif.gif)\n\nC'est un projet simple mais il montre déjà à quel point Get est puissant. Au fur et à mesure que votre projet se développe, cette différence deviendra plus significative.\n\nGet a été conçu pour fonctionner avec des équipes, mais il simplifie le travail d'un développeur individuel.\n\nAméliorez vos délais, livrez tout à temps sans perte de performances. Get n'est pas pour tout le monde, mais si vous vous êtes identifié à cette phrase, Get est fait pour vous!\n\n# Les trois pilliers\n\n## Gestion d Etat\n\nGet a deux gestionnaires d'état différents: le gestionnaire d'état simple (nous l'appellerons GetBuilder) et le gestionnaire d'état réactif (GetX / Obx).\n\n### Gestionnaire d Etat Reactif\n\nLa programmation réactive peut aliéner de nombreuses personnes car on dit qu'elle est compliquée. GetX fait de la programmation réactive quelque chose d'assez simple:\n\n- Vous n'aurez pas besoin de créer des StreamControllers.\n- Vous n'aurez pas besoin de créer un StreamBuilder pour chaque variable\n- Vous n'aurez pas besoin de créer une classe pour chaque état.\n- Vous n'aurez pas besoin de créer un 'get' pour une valeur initiale.\n- Vous n'aurez pas besoin d'utiliser des générateurs de code\n\nLa programmation réactive avec Get est aussi simple que d'utiliser setState.\n\nImaginons que vous ayez une variable 'name' et que vous souhaitiez que chaque fois que vous la modifiez, tous les widgets qui l'utilisent soient automatiquement modifiés.\n\nVoici votre variable:\n\n```dart\nvar name = 'Jonatas Borges';\n```\n\nPour la rendre observable, il vous suffit d'ajouter \".obs\" à la fin:\n\n```dart\nvar name = 'Jonatas Borges'.obs;\n```\n\nEt dans l'interface utilisateur, lorsque vous souhaitez afficher cette valeur et mettre à jour l'écran chaque fois qu'elle change, faites simplement:\n\n```dart\nObx(() => Text(\"${controller.name}\"));\n```\n\nC'est _tout_. Si simple que ca.\n\n### Plus de details sur la gestion d Etat\n\n**Lire une explication plus approfondie de la gestion d'état [ici](./documentation/fr_FR/state_management.md). Là-bas, vous verrez plus d'exemples surtout pour la différence entre le gestionnaire d'état simple et le gestionnaire d'état réactif.**\n\nVous pourrez vous faire une meilleure idée de la puissance de GetX.\n\n## Gestion de route\n\nSi vous envisagez d'utiliser des routes/snackbars/dialogs/bottomsheets sans 'context', GetX est également excellent pour vous, voyez par vous-même:\n\nAjoutez \"Get\" avant votre MaterialApp, en le transformant en GetMaterialApp\n\n```dart\nGetMaterialApp( // Avant: MaterialApp(\n  home: MyHome(),\n)\n```\n\nAccédez à un nouvel écran:\n\n```dart\n\nGet.to(ÉcranSuivant());\n```\n\nAccédez au nouvel écran par le nom. Voir plus de détails sur les itinéraires nommés (named routes) [ici](./documentation/fr_FR/route_management.md#navigation-avec-des-itinraires-nomms)\n\n```dart\n\nGet.toNamed('/details');\n```\n\nPour fermer des snackbars, dialogs, bottomsheets, ou tout ce que vous auriez normalement fermé avec Navigator.pop(context);\n\n```dart\nGet.back();\n```\n\nPour aller à l'écran suivant avec aucune option pour revenir à l'écran précédent (pour une utilisation dans SplashScreens, écrans de connexion, etc.)\n\n```dart\nGet.off(NextScreen());\n```\n\nPour aller à l'écran suivant et annuler tous les itinéraires précédents (utile dans les paniers d'achat en ligne, les sondages et les tests)\n\n```dart\nGet.offAll(NextScreen());\n```\n\nAvez-vous remarqué que vous n'avez eu besoin d'utiliser 'context' pour aucune de ces opérations? C'est l'un des plus grands avantages de l'utilisation de la gestion de route avec Get. Avec cela, vous pouvez appeler toutes ces méthodes à partir de votre classe de contrôleur, sans soucis.\n\n### Plus de details sur la gestion de route\n\n**Get fonctionne avec des itinéraires nommés (named routes) et offre également un contrôle plus granulaire de vos routes! Il y a une documentation approfondie [ici](./documentation/fr_FR/route_management.md)**\n\n## Gestion des dependances\n\nGet a un gestionnaire de dépendances (dependency manager) simple et puissant qui vous permet de récupérer la même classe que votre Bloc ou Controller avec seulement 1 ligne de code, pas de 'context' Provider, pas d'inheritedWidget:\n\n```dart\nController controller = Get.put(Controller()); // Au lieu de Controller controller = Controller();\n```\n\n- Remarque: Si vous utilisez le gestionnaire d'état de Get, accordez plus d'attention à l'API 'Bindings', qui facilitera la connexion de vos Vues à vos contrôleurs.\n\nAu lieu d'instancier votre classe dans la classe que vous utilisez, vous l'instanciez dans l'instance Get, ce qui la rendra disponible dans toute votre application.\nVous pouvez donc utiliser votre contrôleur (ou classe Bloc) normalement.\n\n**Conseil:** La gestion des dépendances est découplée des autres parties du package, donc si, par exemple, votre application utilise déjà un gestionnaire d'état (n'importe lequel, peu importe), vous n'avez pas besoin de tout réécrire, vous pouvez l'utiliser avec l'injection de dépendance de Get sans aucun problème.\n\n```dart\ncontroller.fetchApi();\n```\n\nImaginez que vous ayez parcouru de nombreuses routes et que vous ayez besoin de données qui ont été laissées dans votre contrôleur, vous auriez besoin d'un gestionnaire d'état combiné avec le 'Provider' ou 'Get_it', n'est-ce pas? Pas avec Get. Il vous suffit de demander à Get de \"trouver\" votre contrôleur, vous n'avez pas besoin de dépendances supplémentaires:\n\n```dart\nController controller = Get.find();\n//Oui, cela ressemble à de la magie. Get trouvera votre contrôleur et vous le livrera. Vous pouvez avoir 1 million de contrôleurs instanciés, Get vous retournera toujours le bon contrôleur.\n```\n\nEt puis vous pourrez récupérer les données de votre contrôleur obtenu précédemment:\n\n```dart\nText(controller.textFromApi);\n```\n\n### Plus de details sur la gestion des dependances\n\n**Trouvez une explication plus détaillée sur la gestion des dépendances [ici](./documentation/fr_FR/dependency_management.md)**\n\n# Utils\n\n## Internationalization\n\n### Traductions\n\nLes traductions sont enregistrées sous forme de dictionaire clé-valeur simple.\nPour ajouter des traductions, créez une classe qui 'extend' `Translations`.\n\n```dart\nimport 'package:get/get.dart';\n\nclass Messages extends Translations {\n  @override\n  Map<String, Map<String, String>> get keys => {\n        'en_US': {\n          'hello': 'Hello World',\n        },\n        'de_DE': {\n          'hello': 'Hallo Welt',\n        }\n      };\n}\n```\n\n#### Utiliser les traductions\n\nAjouter juste `.tr` à la clé et elle sera traduite selon la valeur actuelle `Get.locale` et de `Get.fallbackLocale`.\n\n```dart\nText('title'.tr);\n```\n\n#### Utiliser les traductions avec le singulier et le pluriel\n\n```dart\nvar products = [];\nText('cléAuSingulier'.trPlural('cléAuPluriel', products.length, Args));\n```\n\n#### Utiliser les traductions avec paramètres\n\n```dart\nimport 'package:get/get.dart';\n\n\nMap<String, Map<String, String>> get keys => {\n    'en_US': {\n        'logged_in': 'logged in as @name with email @email',\n    },\n    'es_ES': {\n       'logged_in': 'iniciado sesión como @name con e-mail @email',\n    }\n};\n\nText('logged_in'.trParams({\n  'name': 'Jhon',\n  'email': 'jhon@example.com'\n  }));\n```\n\n### Locales\n\n'Locales' signifie lieux.\nPour definir les traductions, passer les paramètres 'locale' et 'translations' à GetMaterialApp.\n\n```dart\nreturn GetMaterialApp(\n    translations: Messages(), // Vos traductions\n    locale: Locale('en', 'US'), // Les traductions seront faites dans cette 'locale' (langue)\n    fallbackLocale: Locale('en', 'UK'), // definit le 'language de secours' au cas oú un language invalide est sélectionné.\n);\n```\n\n#### Changer la locale\n\nAppelez `Get.updateLocale (locale)` pour mettre à jour la locale. Les traductions utilisent alors automatiquement la nouvelle langue.\n\n```dart\nvar locale = Locale('en', 'US');\nGet.updateLocale(locale);\n```\n\n#### Locale du systeme\n\nPour lire les paramètres régionaux ('locales') du système, vous pouvez utiliser `Get.deviceLocale`.\n\n```dart\nreturn GetMaterialApp(\n    locale: Get.deviceLocale,\n);\n```\n\n## Changer le Theme\n\nVeuillez ne pas utiliser de widget de niveau supérieur à `GetMaterialApp` pour le mettre à jour. Cela peut créer des clés ('keys') en double. Beaucoup de gens sont habitués à l'approche préhistorique de la création d'un widget \"ThemeProvider\" juste pour changer le thème de votre application, et ce n'est certainement PAS nécessaire avec **GetX ™**.\n\nVous pouvez créer votre thème personnalisé et l'ajouter simplement dans `Get.changeTheme` sans aucune préconfiguration pour cela:\n\n```dart\nGet.changeTheme(ThemeData.light());\n```\n\nSi vous voulez créer quelque chose comme un bouton qui change le thème dans `onTap`, vous pouvez combiner deux API **GetX ™** pour cela:\n\n- L'API qui vérifie si le \"Thème\" sombre est utilisé.\n- Et l'API de changement de thème, vous pouvez simplement le mettre dans un 'onPressed':\n\n```dart\nGet.changeTheme(Get.isDarkMode? ThemeData.light(): ThemeData.dark());\n```\n\nLorsque 'onPressed' est appelé, si `.darkmode` est activé, il passera au _thème clair_, et lorsque le _thème clair_ est actif, il passera au _thème sombre_.\n\n## GetConnect\n\nGetConnect est un moyen facile de communiquer de votre backend à votre frontend avec http ou websockets.\n\n### Configuration par defaut\n\nVous pouvez simplement 'extends' GetConnect et utiliser les méthodes GET / POST / PUT / DELETE / SOCKET pour communiquer avec votre API Rest ou vos websockets.\n\n```dart\nclass UserProvider extends GetConnect {\n  // Get request\n  Future<Response> getUser(int id) => get('http://youapi/users/$id');\n  // Post request\n  Future<Response> postUser(Map data) => post('http://youapi/users', body: data);\n  // Post request with File\n  Future<Response<CasesModel>> postCases(List<int> image) {\n    final form = FormData({\n      'file': MultipartFile(image, filename: 'avatar.png'),\n      'otherFile': MultipartFile(image, filename: 'cover.png'),\n    });\n    return post('http://youapi/users/upload', form);\n  }\n\n  GetSocket userMessages() {\n    return socket('https://yourapi/users/socket');\n  }\n}\n```\n\n### Configuration personnalisee\n\nGetConnect est hautement personnalisable. Vous pouvez définir l'URL de base, comme modificateurs de réponse, comme modificateurs de requêtes, définir un authentificateur, et même le nombre de tentatives oú il tentera de s'authentifier, en plus de donner la possibilité de définir un décodeur standard qui transformera toutes vos Requêtes dans vos Modèles sans aucune configuration supplémentaire.\n\n```dart\nclass HomeProvider extends GetConnect {\n  @override\n  void onInit() {\n    // Toute 'Request' passera à jsonEncode donc CasesModel.fromJson()\n    httpClient.defaultDecoder = CasesModel.fromJson;\n    httpClient.baseUrl = 'https://api.covid19api.com';\n    // baseUrl = 'https://api.covid19api.com';\n    // Il définit baseUrl pour Http et websockets si utilisé sans instance [httpClient]\n\n    // Cela attachera la propriété 'apikey' sur l'en-tête ('header') de toutes les 'request's\n    httpClient.addRequestModifier((request) {\n      request.headers['apikey'] = '12345678';\n      return request;\n    });\n\n    // Même si le serveur envoie des données avec le pays \"Brésil\",\n    // cela ne sera jamais affiché aux utilisateurs, car vous supprimez\n    // ces données de la réponse, même avant que la réponse ne soit délivrée\n    httpClient.addResponseModifier<CasesModel>((request, response) {\n      CasesModel model = response.body;\n      if (model.countries.contains('Brazil')) {\n        model.countries.remove('Brazil');\n      }\n    });\n\n    httpClient.addAuthenticator((request) async {\n      final response = await get(\"http://yourapi/token\");\n      final token = response.body['token'];\n      // Définit l'en-tête\n      request.headers['Authorization'] = \"$token\";\n      return request;\n    });\n\n    // L'Autenticator sera appelé 3 fois si HttpStatus est HttpStatus.unauthorized\n    httpClient.maxAuthRetries = 3;\n  }\n\n\n  @override\n  Future<Response<CasesModel>> getCases(String path) => get(path);\n}\n```\n\n## Middleware GetPage\n\nGetPage a maintenant une nouvelle propriété qui prend une liste de GetMiddleWare et les exécute dans l'ordre spécifique.\n\n**Note**: Lorsque GetPage a un Middleware, tous les enfants de cette page auront automatiquement les mêmes middlewares.\n\n### Priority\n\nL'ordre des middlewares à exécuter peut être défini par la priorité dans GetMiddleware.\n\n```dart\nfinal middlewares = [\n  GetMiddleware(priority: 2),\n  GetMiddleware(priority: 5),\n  GetMiddleware(priority: 4),\n  GetMiddleware(priority: -8),\n];\n```\n\nces middlewares seront exécutés dans cet ordre **-8 => 2 => 4 => 5**\n\n### Redirect\n\n    Cette fonction sera appelée lors de la recherche de la page de l'itinéraire appelé. Elle reçoit RouteSettings comme résultat vers oú rediriger. Sinon donnez-lui la valeur null et il n'y aura pas de redirection.\n\n```dart\nRouteSettings redirect(String route) {\n  final authService = Get.find<AuthService>();\n  return authService.authed.value ? null : RouteSettings(name: '/login');\n}\n```\n\n### onPageCalled\n\nCette fonction sera appelée lorsque cette page sera appelée.\nVous pouvez l'utiliser pour changer quelque chose sur la page ou lui donner une nouvelle page.\n\n```dart\nGetPage onPageCalled(GetPage page) {\n  final authService = Get.find<AuthService>();\n  return page.copyWith(title: 'Welcome ${authService.UserName}');\n}\n```\n\n### OnBindingsStart\n\nCette fonction sera appelée juste avant l'initialisation des liaisons ('bidings').\nIci, vous pouvez modifier les liaisons de cette page.\n\n```dart\nList<Bindings> onBindingsStart(List<Bindings> bindings) {\n  final authService = Get.find<AuthService>();\n  if (authService.isAdmin) {\n    bindings.add(AdminBinding());\n  }\n  return bindings;\n}\n```\n\n### OnPageBuildStart\n\nCette fonction sera appelée juste après l'initialisation des liaisons ('bidings').\nIci, vous pouvez faire quelque chose après avoir créé les liaisons et avant de créer le widget de page.\n\n```dart\nGetPageBuilder onPageBuildStart(GetPageBuilder page) {\n  print('les liaisons sont prêtes');\n  return page;\n}\n```\n\n### OnPageBuilt\n\nCette fonction sera appelée juste après l'appel de la fonction GetPage.page et vous donnera le résultat de la fonction et prendra le widget qui sera affiché.\n\n### OnPageDispose\n\nCette fonction sera appelée juste après avoir disposé tous les objets associés (contrôleurs, vues, ...) à la page.\n\n## Autres APIs\n\n```dart\n// donne les arguments actuels de currentScreen\nGet.arguments\n\n// donne le nom de l'itinéraire précédent\nGet.previousRoute\n\n// donne la route brute d'accès par exemple, rawRoute.isFirst()\nGet.rawRoute\n\n// donne accès à l'API de routing de GetObserver\nGet.routing\n\n// vérifier si le snackbar est ouvert\nGet.isSnackbarOpen\n\n// vérifier si la boîte de dialogue est ouverte\nGet.isDialogOpen\n\n// vérifie si la bottomSheet est ouverte\nGet.isBottomSheetOpen\n\n// supprime une route.\nGet.removeRoute()\n\n// retourne à plusieurs reprises jusqu'à ce que le prédicat retourne 'true'.\nGet.until()\n\n// passe à la route suivante et supprime toutes les routes précédentes jusqu'à ce que le prédicat retourne 'true'.\nGet.offUntil()\n\n// passe à la route nommée suivante et supprime toutes les routes précédentes jusqu'à ce que le prédicat retourne 'true'.\nGet.offNamedUntil()\n\n// Vérifie sur quelle plate-forme l'application s'exécute\nGetPlatform.isAndroid\nGetPlatform.isIOS\nGetPlatform.isMacOS\nGetPlatform.isWindows\nGetPlatform.isLinux\nGetPlatform.isFuchsia\n\n// Vérifie le type d'appareil\nGetPlatform.isMobile\nGetPlatform.isDesktop\n// Toutes les plates-formes sont prises en charge indépendamment, dans le Web!\n// Vous pouvez dire si vous utilisez un navigateur\n// sur Windows, iOS, OSX, Android, etc.\nGetPlatform.isWeb\n\n\n// Équivaut à: MediaQuery.of(context).size.height,\n// mais immuable.\nGet.height\nGet.width\n\n// Donne le 'context' actuel de 'Navigator'.\nGet.context\n\n// Donne le contexte du snackbar / dialogue / bottomsheet au premier plan, n'importe où dans votre code.\nGet.contextOverlay\n\n// Remarque: les méthodes suivantes sont des extensions sur le 'context'. Puisque vous\n// avez accès au contexte à n'importe quel endroit de votre interface utilisateur, vous pouvez l'utiliser n'importe où dans le code de l'interface utilisateur\n\n// Si vous avez besoin d'une hauteur / largeur variable (comme les fenêtres de bureau ou de navigateur qui peuvent être mises à l'échelle), vous devrez utiliser le contexte.\ncontext.width\ncontext.height\n\n// Vous donne le pouvoir de définir la moitié de l'écran, un tiers de celui-ci et ainsi de suite.\n// Utile pour les applications responsives.\n// paramètre dividedBy (double) optionnel - par défaut: 1\n// paramètre reducedBy (double) facultatif - par défaut: 0\ncontext.heightTransformer ()\ncontext.widthTransformer ()\n\n/// Similaire à MediaQuery.of(context).size\ncontext.mediaQuerySize()\n\n/// Similaire à MediaQuery.of(context).padding\ncontext.mediaQueryPadding()\n\n/// Similaire à MediaQuery.of(context).viewPadding\ncontext.mediaQueryViewPadding()\n\n/// Similaire à MediaQuery.of(context).viewInsets;\ncontext.mediaQueryViewInsets()\n\n/// Similaire à MediaQuery.of(context).orientation;\ncontext.orientation()\n\n/// Vérifie si l'appareil est en mode paysage\ncontext.isLandscape()\n\n/// Vérifie si l'appareil est en mode portrait\ncontext.isPortrait()\n\n/// Similaire à MediaQuery.of(context).devicePixelRatio;\ncontext.devicePixelRatio()\n\n/// Similaire à MediaQuery.of(context).textScaleFactor;\ncontext.textScaleFactor()\n\n/// Obtenir le côté le plus court de l'écran\ncontext.mediaQueryShortestSide()\n\n/// Vrai si la largeur est supérieure à 800p\ncontext.showNavbar()\n\n/// Vrai si le côté le plus court est inférieur à 600p\ncontext.isPhone()\n\n/// Vrai si le côté le plus court est plus grand que 600p\ncontext.isSmallTablet()\n\n/// Vrai si le côté le plus court est plus grand que 720p\ncontext.isLargeTablet()\n\n/// Vrai si l'appareil actuel est une tablette\ncontext.isTablet()\n\n/// Renvoie une valeur <T> en fonction de la taille de l'écran\n/// peut donner une valeur pour:\n/// watch: si le côté le plus court est inférieur à 300\n/// mobile: si le côté le plus court est inférieur à 600\n/// tablette: si le côté le plus court est inférieur à 1200\n/// bureautique: si la largeur est supérieure à 1200\ncontext.responsiveValue<T>()\n```\n\n### Parametres globaux et configurations manuelles facultatifs\n\nGetMaterialApp configure tout pour vous, mais si vous souhaitez configurer Get manuellement:\n\n```dart\nMaterialApp(\n  navigatorKey: Get.key,\n  navigatorObservers: [GetObserver()],\n);\n```\n\nVous pourrez également utiliser votre propre middleware dans `GetObserver`, cela n'influencera rien.\n\n```dart\nMaterialApp(\n  navigatorKey: Get.key,\n  navigatorObservers: [\n    GetObserver(MiddleWare.observer) // Ici\n  ],\n);\n```\n\nVous pouvez créer _Global Settings_ pour `Get`. Ajoutez simplement `Get.config` à votre code avant de changer de route.\nOu faites-le directement dans votre `GetMaterialApp`\n\n```dart\nGetMaterialApp(\n  enableLog: true,\n  defaultTransition: Transition.fade,\n  opaqueRoute: Get.isOpaqueRouteDefault,\n  popGesture: Get.isPopGestureEnable,\n  transitionDuration: Get.defaultDurationTransition,\n  defaultGlobalState: Get.defaultGlobalState,\n);\n\nGet.config(\n  enableLog = true,\n  defaultPopGesture = true,\n  defaultTransition = Transitions.cupertino\n)\n```\n\nVous pouvez éventuellement rediriger tous les messages de journalisation (logging) de `Get`.\nSi vous souhaitez utiliser votre propre package de journalisation préféré,\net souhaitez capturer les logs là-bas:\n\n```dart\nGetMaterialApp(\n  enableLog: true,\n  logWriterCallback: localLogWriter,\n);\n\nvoid localLogWriter(String text, {bool isError = false}) {\n  // transmettez le message à votre package de journalisation préféré ici\n  // veuillez noter que même si enableLog: false, les messages du journal seront poussés dans ce 'callback'\n  // vérifiez le 'flag' si vous le souhaitez via GetConfig.isLogEnable\n}\n\n```\n\n### State Widgets Locaux\n\nCes Widgets vous permettent de gérer une valeur unique, et de garder l'état éphémère et localement.\nNous avons des saveurs pour réactif et simple.\nPar exemple, vous pouvez les utiliser pour basculer obscureText dans un `TextField`, peut-être créer un\nPanneau extensible, ou peut-être modifier l'index actuel dans `BottomNavigationBar` tout en modifiant le contenu\nde 'body' dans un `Scaffold`.\n\n#### ValueBuilder\n\nUne simplification de `StatefulWidget` qui fonctionne avec un callback `.setState` qui prend la valeur mise à jour.\n\n```dart\nValueBuilder<bool>(\n  initialValue: false,\n  builder: (value, updateFn) => Switch(\n    value: value,\n    onChanged: updateFn, // même signature! vous pouvez utiliser (newValue) => updateFn (newValue)\n  ),\n  // si vous devez appeler quelque chose en dehors de la méthode du builder.\n  onUpdate: (value) => print(\"Valeur mise à jour: $value\"),\n  onDispose: () => print(\"Widget détruit\"),\n),\n```\n\n#### ObxValue\n\nSimilaire à [`ValueBuilder`](#valuebuilder), mais c'est la version Reactive, vous passez une instance Rx (rappelez-vous les .obs magiques?) et il\nse met à jour automatiquement ... n'est-ce pas génial?\n\n```dart\nObxValue((data) => Switch(\n        value: data.value,\n        onChanged: data, // Rx a une fonction _callable_! Vous pouvez utiliser (flag) => data.value = flag,\n    ),\n    false.obs,\n),\n```\n\n## Conseils utiles\n\n`.obs`ervables (également appelés types _Rx_) ont une grande variété de méthodes et d'opérateurs internes.\n\n> Il est très courant de croire qu'une propriété avec `.obs` ** EST ** la valeur réelle ... mais ne vous y trompez pas!\n> Nous évitons la déclaration Type de la variable, car le compilateur de Dart est assez intelligent, et le code\n> semble plus propre, mais:\n\n```dart\nvar message = 'Hello world'.obs;\nprint( 'Message \"$message\" est de Type ${message.runtimeType}');\n```\n\nBien que `message` _prints_ la vraie valeur du String, le Type est **RxString**!\n\nDonc, vous ne pouvez pas faire `message.substring( 0, 4 )`.\nVous devez utiliser la vraie `valeur` dans _observable_:\nLa façon \"la plus utilisée\" est `.value`, mais, que vous pouviez aussi...\n\n```dart\nfinal name = 'GetX'.obs;\n// \"met à jour\" le flux, uniquement si la valeur est différente de la valeur actuelle.\nname.value = 'Hey';\n\n// Toutes les propriétés Rx sont \"appelables\" et renvoie la nouvelle valeur.\n// mais cette approche n'accepte pas `null`, l'interface utilisateur ne sera pas reconstruite.\nname('Hello');\n\n// est comme un getter, affiche `Hello`.\nname() ;\n\n/// nombres:\n\nfinal count = 0.obs;\n\n// Vous pouvez utiliser toutes les opérations non mutables à partir de num primitives!\ncount + 1;\n\n// Fais attention! ceci n'est valable que si `count` n'est pas final, mais var\ncount += 1;\n\n// Vous pouvez également comparer avec des valeurs:\ncount > 2;\n\n/// booleans:\n\nfinal flag = false.obs;\n\n// bascule la valeur entre true / false\nflag.toggle();\n\n\n/// tous les types:\n\n// Définit la `valeur` sur null.\nflag.nil();\n\n// Toutes les opérations toString (), toJson () sont transmises à la `valeur`\nprint( count ); // appelle `toString ()` à l'intérieur de RxInt\n\nfinal abc = [0,1,2].obs;\n// Convertit la valeur en un Array json, affiche RxList\n// Json est pris en charge par tous les types Rx!\nprint('json: ${jsonEncode(abc)}, type: ${abc.runtimeType}');\n\n// RxMap, RxList et RxSet sont des types Rx spéciaux, qui étendent leurs types natifs.\n// mais vous pouvez travailler avec une liste comme une liste régulière, bien qu'elle soit réactive!\nabc.add(12); // pousse 12 dans la liste et MET À JOUR le flux.\nabc[3]; // comme Lists, lit l'index 3.\n\n\n// l'égalité fonctionne avec le Rx et la valeur, mais hashCode est toujours pris à partir de la valeur\nfinal number = 12.obs;\nprint( number == 12 ); // retource > true\n\n/// Modèles Rx personnalisés:\n\n// toJson (), toString () sont différés à l'enfant, vous pouvez donc implémenter 'override' sur eux, et print() l'observable directement.\n\nclass User {\n    String name, last;\n    int age;\n    User({this.name, this.last, this.age});\n\n    @override\n    String toString() => '$name $last, $age ans';\n}\n\nfinal user = User(name: 'John', last: 'Doe', age: 33).obs;\n\n// `user` est\" réactif \", mais les propriétés à l'intérieur NE SONT PAS!\n// Donc, si nous changeons une variable à l'intérieur ...\nuser.value.name = 'Roi';\n// Le widget ne se reconstruira pas !,\n// `Rx` n'a aucun indice lorsque vous changez quelque chose à l'intérieur de l'utilisateur.\n// Donc, pour les classes personnalisées, nous devons \"notifier\" manuellement le changement.\nuser.refresh();\n\n// ou utiliser `update()`!\nuser.update((value){\n  value.name='Roi';\n});\n\nprint( user );\n```\n\n#### GetView\n\nJ'adore ce widget. Si simple, mais si utile!\n\nC'est un widget `const Stateless` qui a un getter` controller` pour un `Controller` enregistré, c'est tout.\n\n```dart\n class AwesomeController extends GetxController {\n   final String title = 'My Awesome View';\n }\n\n  // N'oubliez PAS de passer le `Type` que vous avez utilisé pour enregistrer votre contrôleur!\n class AwesomeView extends GetView<AwesomeController> {\n   @override\n   Widget build(BuildContext context) {\n     return Container(\n       padding: EdgeInsets.all(20),\n       child: Text(controller.title), // appelez `controller.quelqueChose`\n     );\n   }\n }\n```\n\n#### GetResponsiveView\n\nÉtendez ce widget pour créer une vue réactive.\nce widget contient la propriété `screen` qui a toutes les\ninformations sur la taille et le type de l'écran.\n\n##### Guide d utilisation\n\nVous avez deux options pour le créer:\n\n- avec la méthode `builder` vous renvoyez le widget à construire.\n- avec les méthodes `desktop`,` tablet`, `phone`,` watch`. la méthode spécifique sera exécutée lorsque le type d'écran correspond à la méthode.\n  Lorsque l'écran est [ScreenType.Tablet], la méthode `tablet` sera exécutée et ainsi de suite.\n  **Note:** Si vous utilisez cette méthode, veuillez définir la propriété `alwaysUseBuilder` à `false`\n\nAvec la propriété `settings`, vous pouvez définir la limite de largeur pour les types d'écran.\n\n![exemple](https://github.com/SchabanBo/get_page_example/blob/master/docs/Example.gif?raw=true)\nCode pour cet écran\n[code](https://github.com/SchabanBo/get_page_example/blob/master/lib/pages/responsive_example/responsive_view.dart)\n\n#### GetWidget\n\nLa plupart des gens n'ont aucune idée de ce widget ou confondent totalement son utilisation.\nLe cas d'utilisation est très rare, mais très spécifique: il `met en cache` un contrôleur.\nEn raison du _cache_, ne peut pas être un `const Stateless`.\n\n> Alors, quand avez-vous besoin de \"mettre en cache\" un contrôleur?\n\nSi vous utilisez, une autre fonctionnalité \"pas si courante\" de **GetX**: `Get.create()`.\n\n`Get.create(()=>Controller())` générera un nouveau `Controller` chaque fois que vous appelez\n`Get.find<Controller>()`.\n\nC'est là que `GetWidget` brille ... comme vous pouvez l'utiliser, par exemple,\npour conserver une liste de <Todo>s. Donc, si le widget est \"reconstruit\", il conservera la même instance de contrôleur.\n\n#### GetxService\n\nCette classe est comme un `GetxController`, elle partage le même cycle de vie ( `onInit()`, `onReady()`, `onClose()`), mais n'a pas de \"logique\" en elle.\nIl notifie simplement le **GetX** Dependency Injection system, que cette sous-classe\n**ne peut pas** être supprimé de la mémoire.\n\nDonc est très utile pour garder vos \"Services\" toujours à portée de main et actifs avec `Get.find()`. Comme:\n`ServiceAPI`, `ServiceDeSauvegarde`, `ServiceDeCaching`.\n\n```dart\nFuture<void> main() async {\n  await initServices(); /// Attend l'initialisation des services.\n  runApp(SomeApp());\n}\n\n/// Est une démarche intelligente pour que vos services s'initialisent avant d'exécuter l'application Flutter.\n/// car vous pouvez contrôler le flux d'exécution (peut-être devez-vous charger une configuration de thème,\n/// apiKey, langue définie par l'utilisateur ... donc chargez SettingService avant d'exécuter ApiService.\n/// donc GetMaterialApp () n'a pas besoin de se reconstruire et prend les valeurs directement.\nvoid initServices() async {\n  print('starting services ...');\n  /// C'est ici que vous mettez get_storage, hive, shared_pref initialization.\n  /// ou les connexions moor, ou autres choses async.\n  await Get.putAsync(() => DbService().init());\n  await Get.putAsync(SettingsService()).init();\n  print('Tous les services ont démarré...');\n}\n\nclass DbService extends GetxService {\n  Future<DbService> init() async {\n    print('$runtimeType retarde de 2 sec');\n    await 2.delay();\n    print('$runtimeType prêts!');\n    return this;\n  }\n}\n\nclass SettingsService extends GetxService {\n  void init() async {\n    print(\"$runtimeType retarde d'1 sec\");\n    await 1.delay();\n    print('$runtimeType prêts!');\n  }\n}\n\n```\n\nLa seule façon de supprimer réellement un `GetxService`, est d'utiliser`Get.reset ()`qui est comme un\n\"Hot Reboot\" de votre application. N'oubliez donc pas que si vous avez besoin d'une persistance absolue d'une instance de classe\ndurée de vie de votre application, utilisez `GetxService`.\n\n# Changements par rapport a 2.0\n\n1- Types Rx:\n\n| Avant   | Après      |\n| ------- | ---------- |\n| StringX | `RxString` |\n| IntX    | `RxInt`    |\n| MapX    | `RxMap`    |\n| ListX   | `RxList`   |\n| NumX    | `RxNum`    |\n| DoubleX | `RxDouble` |\n\nRxController et GetBuilder ont maintenant fusionné, vous n'avez plus besoin de mémoriser le contrôleur que vous souhaitez utiliser, utilisez simplement GetxController, cela fonctionnera pour une gestion simple de l'état et également pour la réactivité.\n\n2- NamedRoutes\n\nAvant:\n\n```dart\nGetMaterialApp(\n  namedRoutes: {\n    '/': GetRoute(page: Home()),\n  }\n)\n```\n\nMaintenant:\n\n```dart\nGetMaterialApp(\n  getPages: [\n    GetPage(name: '/', page: () => Home()),\n  ]\n)\n```\n\nPourquoi ce changement?\nSouvent, il peut être nécessaire de décider quelle page sera affichée à partir d'un paramètre, ou d'un 'login token', l'approche précédente était inflexible, car elle ne le permettait pas.\nL'insertion de la page dans une fonction a considérablement réduit la consommation de RAM, puisque les routes ne seront pas allouées en mémoire depuis le démarrage de l'application, et cela a également permis de faire ce type d'approche:\n\n```dart\n\nGetStorage box = GetStorage();\n\nGetMaterialApp(\n  getPages: [\n    GetPage(name: '/', page:(){\n      return box.hasData('token') ? Home() : Login();\n    })\n  ]\n)\n```\n\n# Pourquoi Getx?\n\n1- Plusieurs fois après une mise à jour de Flutter, plusieurs de vos packages seront invalides. Parfois, des erreurs de compilation se produisent, des erreurs apparaissent souvent pour lesquelles il n'y a toujours pas de réponses, et le développeur doit savoir d'où vient l'erreur, suivre l'erreur, puis seulement essayer d'ouvrir un problème dans le référentiel correspondant et voir son problème résolu. Get centralise les principales ressources pour le développement (gestion des états, des dépendances et des routes), vous permettant d'ajouter un package unique à votre pubspec et de commencer à travailler. Après une mise à jour Flutter, la seule chose à faire est de mettre à jour la dépendance Get et de vous mettre au travail. Get résout également les problèmes de compatibilité. Combien de fois une version d'un package n'est pas compatible avec la version d'un autre, parce que l'une utilise une dépendance dans une version et l'autre dans une autre version? Ce n'est pas non plus un problème avec Get, car tout est dans le même package et est entièrement compatible.\n\n2- Flutter est facile, Flutter est incroyable, mais Flutter a encore quelques règles standard qui peuvent être indésirables pour la plupart des développeurs, comme `Navigator.of (context) .push (context, builder [...]`. Get simplifie le développement. Au lieu de écrire 8 lignes de code pour simplement appeler une route, vous pouvez simplement le faire: `Get.to (Home ())` et vous avez terminé, vous passerez à la page suivante. Les URL Web dynamiques sont une chose vraiment pénible à voir avec Flutter actuellement, et cela avec GetX est stupidement simple. La gestion des états dans Flutter et la gestion des dépendances sont également quelque chose qui génère beaucoup de discussions, car il y a des centaines de modèles dans la pub. Mais rien n'est aussi simple que d'ajouter un \".obs\" à la fin de votre variable, et placez votre widget dans un Obx, et c'est tout, toutes les mises à jour de cette variable seront automatiquement mises à jour à l'écran.\n\n3- Facilité sans vous soucier des performances. Les performances de Flutter sont déjà étonnantes, mais imaginez que vous utilisez un gestionnaire d'état et un localisateur pour distribuer vos classes blocs / stores / 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é à simplement utiliser votre «contrôleur`, et quand il n'était plus utilisé par personne, il serait 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 pas avoir à vous soucier d'autre chose que de la programmation. Vous serez assuré de consommer le minimum de ressources nécessaires, sans même avoir créé de logique pour cela.\n\n4- Découplage réel. Vous avez peut-être entendu le concept \"séparer la vue de la business logic\". Ce n'est pas une particularité de BLoC, MVC, MVVM, et tout autre standard sur le marché a ce concept. Cependant, ce concept peut souvent être atténué dans Flutter en raison de l'utilisation de `context`.\nSi vous avez besoin de contexte pour trouver un InheritedWidget, vous en avez besoin dans la vue, ou passez le `context` par paramètre. Je trouve particulièrement cette solution très moche, et pour travailler en équipe, nous serons toujours dépendants de la 'business logic' de View. Getx n'est pas orthodoxe avec l'approche standard, et même s'il n'interdit pas complètement l'utilisation de StatefulWidgets, InitState, etc., il a toujours une approche similaire qui peut être plus propre. Les contrôleurs ont des cycles de vie, et lorsque vous devez faire une requête APIREST par exemple, vous ne dépendez de rien de la vue. Vous pouvez utiliser onInit pour lancer l'appel http et lorsque les données arrivent, les variables sont remplies. Comme GetX est totalement réactif (vraiment, et fonctionne sous streams), une fois les éléments remplis, tous les widgets qui utilisent cette variable seront automatiquement mis à jour dans la vue.\nCela permet aux personnes ayant une expertise de l'interface utilisateur de travailler uniquement avec des widgets et de ne pas avoir à envoyer quoi que ce soit à la business logic autre que des événements utilisateur (comme cliquer sur un bouton), tandis que les personnes travaillant avec la business logic seront libres de créer et de tester la Business logic séparément.\n\n# Communite\n\n## Chaines communautaires\n\nGetX a une communauté très active et utile. Si vous avez des questions, ou souhaitez obtenir de l'aide concernant l'utilisation de ce framework, veuillez rejoindre nos canaux communautaires, votre question sera répondue plus rapidement, et ce sera l'endroit le plus approprié. Ce référentiel est exclusif pour l'ouverture des issues Github et la demande de ressources, mais n'hésitez pas à faire partie de la communauté GetX.\n| **Slack** | **Discord** | **Telegram** |\n| :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------- |\n| [![Get sur 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) |\n\n## Comment contribuer\n\n_Voulez-vous contribuer au projet? Nous serons fiers de vous mettre en avant comme l'un de nos collaborateurs. Voici quelques points sur lesquels vous pouvez contribuer et améliorer encore Get (et Flutter)._\n\n- Aider à traduire les 'Readme's dans d'autres langues.\n- Ajout de documentation au readme (beaucoup de fonctions de Get n'ont pas encore été documentées).\n- Rédiger des articles ou réaliser des vidéos pour apprendre à utiliser Get (ils seront insérés dans le Readme et à l'avenir dans notre Wiki).\n- Offrir des PRs pour code / tests.\n- Ajouter de nouvelles fonctions.\n\nToute contribution est bienvenue!\n\n## Articles et videos\n\n- [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).\n- [Complete GetX™ Navigation](https://www.youtube.com/watch?v=RaqPIoJSTtI) - Route management video by Amateur Coder.\n- [Complete GetX State Management](https://www.youtube.com/watch?v=CNpXbeI_slw) - State management video by Amateur Coder.\n- [GetX™ Other Features](https://youtu.be/ttQtlX_Q0eU) - Utils, storage, bindings and other features video by Amateur Coder.\n- [Firestore User with GetX | Todo App](https://www.youtube.com/watch?v=BiV0DcXgk58) - Video by Amateur Coder.\n- [Firebase Auth with GetX | Todo App](https://www.youtube.com/watch?v=-H-T_BSgfOE) - Video by Amateur Coder.\n- [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).\n- [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).\n- [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.\n- [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.\n- [GetX Flutter Firebase Auth Example](https://medium.com/@jeffmcmorris/getx-flutter-firebase-auth-example-b383c1dd1de2) - Article by Jeff McMorris.\n- [Flutter State Management with GetX – Complete App](https://www.appwithflutter.com/flutter-state-management-with-getx/) - by App With Flutter.\n- [Flutter Routing with Animation using Get Package](https://www.appwithflutter.com/flutter-routing-using-get-package/) - by App With Flutter.\n"
  },
  {
    "path": "README-hi.md",
    "content": "\n![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png)\n\n[![pub  package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)\n\n[![popularity](https://badges.bar/get/popularity)](https://pub.dev/packages/sentry/score)\n\n[![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)\n\n[![pub  points](https://badges.bar/get/pub%20points)](https://pub.dev/packages/get/score)\n\n![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)\n\n[![style:  effective  dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart)\n\n[![Discord  Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N)\n\n[![Get  on  Slack](https://img.shields.io/badge/slack-join-orange.svg)](https://communityinviter.com/apps/getxworkspace/getx)\n\n[![Telegram](https://img.shields.io/badge/chat-on%20Telegram-blue.svg)](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g)\n\n<a href=\"https://github.com/Solido/awesome-flutter\">\n\n<img alt=\"Awesome Flutter\" src=\"https://img.shields.io/badge/Awesome-Flutter-blue.svg?longCache=true&style=flat-square\" />\n\n</a>\n\n<a href=\"https://www.buymeacoffee.com/jonataslaw\" target=\"_blank\"><img src=\"https://i.imgur.com/aV6DDA7.png\" alt=\"Buy Me A Coffee\" style=\"height: 41px !important;width: 174px !important; box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;\" > </a>\n\n![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/getx.png)\n\n<div align=\"center\">\n\n**Languages:**\n\n[![English](https://img.shields.io/badge/Language-English-blueviolet?style=for-the-badge)](README.md)\n\n[![Vietnamese](https://img.shields.io/badge/Language-Vietnamese-blueviolet?style=for-the-badge)](README-vi.md)\n\n[![Indonesian](https://img.shields.io/badge/Language-Indonesian-blueviolet?style=for-the-badge)](README.id-ID.md)\n\n[![Urdu](https://img.shields.io/badge/Language-Urdu-blueviolet?style=for-the-badge)](README.ur-PK.md)\n\n[![Chinese](https://img.shields.io/badge/Language-Chinese-blueviolet?style=for-the-badge)](README.zh-cn.md)\n\n[![Portuguese](https://img.shields.io/badge/Language-Portuguese-blueviolet?style=for-the-badge)](README.pt-br.md)\n\n[![Spanish](https://img.shields.io/badge/Language-Spanish-blueviolet?style=for-the-badge)](README-es.md)\n\n[![Russian](https://img.shields.io/badge/Language-Russian-blueviolet?style=for-the-badge)](README.ru.md)\n\n[![Polish](https://img.shields.io/badge/Language-Polish-blueviolet?style=for-the-badge)](README.pl.md)\n\n[![Korean](https://img.shields.io/badge/Language-Korean-blueviolet?style=for-the-badge)](README.ko-kr.md)\n\n[![French](https://img.shields.io/badge/Language-French-blueviolet?style=for-the-badge)](README-fr.md)\n\n[![Japanese](https://img.shields.io/badge/Language-Japanese-blueviolet?style=for-the-badge)](README.ja-JP.md)\n\n[![Turkish](https://img.shields.io/badge/Language-Turkish-blueviolet?style=for-the-badge)](README.tr-TR.md)\n\n[![Hindi](https://img.shields.io/badge/Language-Hindi-blueviolet?style=for-the-badge)](README-hi.md)\n\n</div>\n\n- [Get के बारे में](#about-get)\n\n- [इंस्टॉलिंग](#installing)\n\n- [Get के साथ काउंटर ऐप](#counter-app-with-getx)\n\n- [तीन सिद्धांत](#the-three-pillars)\n\n  - [स्टेट मैनेजमेंट](#state-management)\n\n    - [रिएक्टिव स्टेट मैनेजर ](#reactive-state-manager)\n\n    - [स्टेट मैनेजमेंट के बारे में और जाने](#more-details-about-state-management)\n\n  - [रूट मैनेजमेंट ](#route-management)\n\n    - [रूट मैनेजमेंट के बारे में और जाने](#more-details-about-route-management)\n\n  - [डिपेंडेंसी मैनेजमेंट](#dependency-management)\n\n    - [डिपेंडेंसी मैनेजमेंट के बारे में और जाने](#more-details-about-dependency-management)\n\n- [मदद करने वाले फीचर्स](#utils)\n\n  - [इंटरनॅशनलिनाइज़ेशन](#internationalization)\n\n    - [अनुवाद](#translations)\n\n      - [अनुवादों का उपयोग करना](#using-translations)\n\n    - [क्षेत्र के अनुसार पसंद](#locales)\n\n      - [लोकेल बदलें](#change-locale)\n\n      - [सिस्टम लोकेलस ](#system-locale)\n\n  - [थीम बदलें](#change-theme)\n\n  - [GetConnect](#getconnect)\n\n    - [डिफ़ॉल्ट कॉन्फ़िगरेशन ](#default-configuration)\n\n    - [कस्टम कॉन्फ़िगरेशन](#custom-configuration)\n\n  - [GetPage Middleware](#getpage-middleware)\n\n    - [वरीयता](#priority)\n\n    - [रीडायरेक्ट](#redirect)\n\n    - [पेज कॉल होने पर](#onpagecalled)\n\n    - [बाइंडिंग शुरू होने पर](#onbindingsstart)\n\n    - [पेज बिल्ड स्टार्ट पर](#onpagebuildstart)\n\n    - [पेज पूरा बन ने पर](#onpagebuilt)\n\n    - [पेज डिस्पोसे होने पर](#onpagedispose)\n\n  - [अन्य उन्नत एपीआई](#other-advanced-apis)\n\n    - [वैकल्पिक वैश्विक सेटिंग्स और मैन्युअल कॉन्फ़िगरेशन](#optional-global-settings-and-manual-configurations)\n\n    - [लोकल स्टेट विद्गेट्स ](#local-state-widgets)\n\n      - [वैल्यू बिल्डर](#valuebuilder)\n\n      - [ObxValue](#obxvalue)\n\n  - [उपयोगी सलाह](#useful-tips)\n\n    - [GetView](#getview)\n\n    - [GetResponsiveView](#getresponsiveview)\n\n      - [इसका उपयोग कैसे करना है](#how-to-use-it)\n\n    - [GetWidget](#getwidget)\n\n    - [GetxService](#getxservice)\n\n- [2.0 से बड़े बदलाव](#breaking-changes-from-20)\n\n- [क्यों GetX?](#why-getx)\n\n- [समुदाय](#community)\n\n  - [सामुदायिक चैनल](#community-channels)\n\n  - [कैसे योगदान करें](#how-to-contribute)\n\n  - [लेख और वीडियो](#articles-and-videos)\n\n# Get के बारे में\n\n- GetX, Flutter के लिए एक अतिरिक्त हल्का और शक्तिशाली समाधान है। यह स्टेट मैनेजमेंट, डिपेंडेंसी इंजेक्शन और नेविगेशन  को जल्दी और व्यावहारिक रूप से जोड़ता है।\n\n- GetX के 3 बुनियादी सिद्धांत हैं। इसका मतलब है कि पुस्तकालय में सभी संसाधनों के लिए ये प्राथमिकताएं हैं: **उत्पादकता, प्रदर्शन और संगठन।**\n\n  - **प्रदर्शन**: GetX प्रदर्शन और संसाधनों की न्यूनतम खपत पर केंद्रित है। GetX स्ट्रीम या चेंज नोटिफ़ायर का उपयोग नहीं करता है।\n\n  - **उत्पादकता**: GetX एक आसान और सुखद सिंटैक्स का उपयोग करता है। कोई फर्क नहीं पड़ता कि आप क्या करना चाहते हैं, GetX के साथ हमेशा एक आसान तरीका होता है। यह विकास के घंटों को बचाएगा और अधिकतम प्रदर्शन प्रदान करेगा जो आपका एप्लिकेशन प्रदान कर सकता है।\n\n    आम तौर पर, डेवलपर को स्मृति से नियंत्रकों को हटाने के बारे में चिंतित होना चाहिए। GetX के साथ यह आवश्यक नहीं है क्योंकि संसाधनों को स्मृति से हटा दिया जाता है जब वे डिफ़ॉल्ट रूप से उपयोग नहीं किए जाते हैं। यदि आप इसे स्मृति में रखना चाहते हैं, तो आपको अपनी निर्भरता में स्पष्ट रूप से **\"permanent: true\"** घोषित करना होगा। इस तरह, समय बचाने के अलावा, आपको स्मृति पर अनावश्यक निर्भरता होने का जोखिम कम होता है। डिपेंडेंसी लोडिंग भी डिफ़ॉल्ट रूप से आलसी है।\n\n  - **संगठन**: गेटएक्स व्यू, प्रेजेंटेशन लॉजिक, बिजनेस लॉजिक, डिपेंडेंसी इंजेक्शन और नेविगेशन को पूरी तरह से अलग करने की अनुमति देता है। आपको मार्गों के बीच नेविगेट करने के लिए संदर्भ की आवश्यकता नहीं है, इसलिए आप इसके लिए विजेट ट्री (विज़ुअलाइज़ेशन) पर निर्भर नहीं हैं। आपको विरासत में मिले विजेट के माध्यम से अपने नियंत्रकों/ब्लॉकों तक पहुँचने के लिए संदर्भ की आवश्यकता नहीं है, इसलिए आप अपने प्रस्तुति तर्क और व्यावसायिक तर्क को अपनी विज़ुअलाइज़ेशन परत से पूरी तरह से अलग कर सकते हैं। आपको मल्टीप्रोवाइडर्स के माध्यम से अपने विजेट ट्री में अपने कंट्रोलर/मॉडल/ब्लॉक क्लास को इंजेक्ट करने की आवश्यकता नहीं है। इसके लिए, GetX अपने स्वयं के निर्भरता इंजेक्शन सुविधा का उपयोग करता है, DI को अपने दृष्टिकोण से पूरी तरह से अलग करता है।\n\n    **GetX** के साथ आप जानते हैं कि डिफ़ॉल्ट रूप से क्लीन कोड वाले अपने एप्लिकेशन की प्रत्येक सुविधा को कहां खोजना है। रखरखाव को आसान बनाने के अलावा, यह मॉड्यूल के साझाकरण को कुछ ऐसा बनाता है जो तब तक फ़्लटर में अकल्पनीय था, कुछ पूरी तरह से संभव था।\n\n    **BLoC** फ़्लटर में कोड व्यवस्थित करने के लिए एक प्रारंभिक बिंदु था, यह व्यावसायिक तर्क को विज़ुअलाइज़ेशन से अलग करता है। GetX इसका एक स्वाभाविक विकास है, न केवल व्यावसायिक तर्क बल्कि प्रस्तुति तर्क को अलग करना। निर्भरता और मार्गों के बोनस इंजेक्शन को भी अलग कर दिया गया है, और डेटा स्तर इससे बाहर है। आप जानते हैं कि सब कुछ कहाँ है, और यह सब एक हैलो वर्ल्ड बनाने की तुलना में आसान तरीके से है।\n\n    Flutter SDK के साथ उच्च-प्रदर्शन अनुप्रयोगों के निर्माण के लिए गेटएक्स सबसे आसान, व्यावहारिक और स्केलेबल तरीका है। इसके चारों ओर एक बड़ा पारिस्थितिकी तंत्र है जो पूरी तरह से एक साथ काम करता है, यह शुरुआती लोगों के लिए आसान है, और यह विशेषज्ञों के लिए सटीक है। यह सुरक्षित, स्थिर, अप-टू-डेट है, और अंतर्निहित एपीआई की एक विशाल श्रृंखला प्रदान करता है जो डिफ़ॉल्ट फ़्लटर एसडीके में मौजूद नहीं हैं।\n\n- **GetX** फूला हुआ नहीं है। इसमें कई विशेषताएं हैं जो आपको बिना किसी चिंता के प्रोग्रामिंग शुरू करने की अनुमति देती हैं, लेकिन इनमें से प्रत्येक सुविधा अलग-अलग कंटेनरों में होती है और केवल उपयोग के बाद ही शुरू होती है। यदि आप केवल राज्य प्रबंधन का उपयोग करते हैं, तो केवल राज्य प्रबंधन संकलित किया जाएगा। यदि आप केवल मार्गों का उपयोग करते हैं, तो राज्य प्रबंधन से कुछ भी संकलित नहीं किया जाएगा।\n\n- GetX में एक विशाल पारिस्थितिकी तंत्र, एक बड़ा समुदाय, बड़ी संख्या में सहयोगी हैं, और जब तक फ़्लटर मौजूद है, तब तक इसे बनाए रखा जाएगा। GetX भी **Android, iOS, Web, Mac, Linux, Windows** और आपके Server पर समान Code के साथ चलने में सक्षम है।\n\n  **आपके Backend पर Frontend पर बने आपके कोड का पूरी तरह से पुन: उपयोग करना संभव है  [Get  Server](https://github.com/jonataslaw/get_server)**.\n\n**इसके अलावा, संपूर्ण विकास प्रक्रिया पूरी तरह से स्वचालित हो सकती है, दोनों सर्वर पर और फ्रंट एंड पर  [Get  CLI](https://github.com/jonataslaw/get_cli)**.\n\n**इसके अलावा, आपकी उत्पादकता को और बढ़ाने के लिए, हमारे पास है\n\n**[VSCODE के लिए एक्सटेंशन](https://marketplace.visualstudio.com/items?itemName=get-snippets.get-snippets)  and  the  [Android Studio और Intellij के लिए एक्सटेंशन](https://plugins.jetbrains.com/plugin/14975-getx-snippets)**\n\n# इंस्टॉलिंग\n\nअपनी ```pubspec.yaml``` फ़ाइल में Get को ऐड करे\n\n```yaml\n\ndependencies:\n  ...\n  get:\n\n```\n\nGet को अन फाइल्स में Import करे जहां आप Get को इस्तेमाल करेंगे: \n\n```dart\n\nimport 'package:get/get.dart';\n\n```\n\n# GetX के साथ काउंटर ऐप\n\nFlutter पर नए Project पर Default रूप से बनाए गए \"काउंटर\" प्रोजेक्ट में 100 से अधिक लाइनें (टिप्पणियों के साथ) हैं। Get की शक्ति दिखाने के लिए, मैं प्रदर्शित करूंगा कि प्रत्येक क्लिक के साथ राज्य को बदलने वाला \"काउंटर\" कैसे बनाया जाए, Navigation किया जाए और State Management किया जाए, सभी एक संगठित तरीके से, व्यावसायिक तर्क को दृश्य से अलग करते हुए, केवल में टिप्पणियों सहित 26 लाइन कोड।\n\n- चरण 1:\n\n  अपने **MaterialApp()** से पहले “Get” जोड़ें, इसे **GetMaterialApp()** में बदल दें\n\n```dart\n\nvoid main() => runApp(GetMaterialApp(home: Home()));\n\n```\n\n- **सूचना**: यह Flutter के MaterialApp को संशोधित नहीं करता है, GetMaterialApp एक संशोधित MaterialApp नहीं है, यह सिर्फ एक पूर्व-कॉन्फ़िगर विजेट है, जिसमें एक बच्चे के रूप में डिफ़ॉल्ट MaterialApp है। आप इसे मैन्युअल रूप से कॉन्फ़िगर कर सकते हैं, लेकिन यह निश्चित रूप से आवश्यक नहीं है। GetMaterialApp मार्ग बनाएगा, उन्हें इंजेक्ट करेगा, अनुवाद इंजेक्ट करेगा, मार्ग नेविगेशन के लिए आपको जो कुछ भी चाहिए उसे इंजेक्ट करेगा। यदि आप केवल राज्य प्रबंधन या निर्भरता प्रबंधन के लिए गेट का उपयोग करते हैं, तो GetMaterialApp का उपयोग करना आवश्यक नहीं है। GetMaterialApp मार्गों, स्नैकबार, अंतर्राष्ट्रीयकरण, बॉटमशीट, संवाद, और मार्गों से संबंधित उच्च-स्तरीय एपिस और संदर्भ की अनुपस्थिति के लिए आवश्यक है।\n\n- **सूचना²**: यह चरण केवल तभी आवश्यक है जब आप Navigation (`Get.to()`, `Get.back()` इत्यादि) का उपयोग करने वाले हों। यदि आप इसका उपयोग नहीं करने जा रहे हैं तो चरण 1 करने की आवश्यकता नहीं है।\n\n- चरण 2:\n\n  अपना व्यावसायिक तर्क वर्ग बनाएं और उसके अंदर सभी चर, विधियों और नियंत्रकों को रखें।\n\n  आप किसी भी Variable Ko \".obs\" का प्रयोग करके Observable बना सकते है\n\n```dart\n\nclass Controller extends GetxController{\n\n  var count = 0.obs;\n\n  increment() => count++;\n\n}\n\n```\n\n- चरण 3:\n\n  अपना दृश्य बनाएं, StatelessWidget का उपयोग करें और कुछ RAM सहेजें, Get के साथ आपको StatefulWidget का उपयोग करने की आवश्यकता नहीं है।\n\n```dart\n\nclass Home extends StatelessWidget {\n\n  @override\n\n  Widget build(context) {\n\n    // Get.put() का उपयोग करके अपनी Class के सभी Children के लिए उपलब्ध कराने के लिए तत्काल करें।\n\n    final Controller c = Get.put(Controller());\n\n    return Scaffold(\n\n      // जब भी गिनती बदली जाए तो Text() को अपडेट करने के लिए Obx(()=> का उपयोग करें।\n\n      appBar: AppBar(title: Obx(() => Text(\"Clicks: ${c.count}\"))),\n\n      // 8 लाइन Navigator.push() को एक साधारण Get.to() से बदलें । आपको \"context\" की आवश्यकता नहीं है ।\n\n      body: Center(child: ElevatedButton(\n\n              child: Text(\"Go to Other\"), onPressed: () => Get.to(Other()))),\n\n      floatingActionButton:\n\n          FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment));\n\n  }\n\n}\n\nclass Other extends StatelessWidget {\n\n  // आप किसी अन्य Page द्वारा उपयोग किए जा रहे Controller को खोजने के लिए Get से पूछ सकते हैं और आपको उस पर Redirect कर सकते हैं।\n\n  final Controller c = Get.find();\n\n  @override\n\n  Widget build(context){\n\n     // बदले हुए count Variable को Access करें\n\n     return Scaffold(body: Center(child: Text(\"${c.count}\")));\n\n  }\n\n}\n\n```\n\n**परिणाम**:\n\n![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/counter-app-gif.gif)\n\nयह एक सरल Project है लेकिन यह पहले ही स्पष्ट कर देती है कि Get कितना शक्तिशाली है। जैसे-जैसे आपकी परियोजना बढ़ती है, यह अंतर और अधिक महत्वपूर्ण होता जाएगा।\n\nGet को टीमों के साथ काम करने के लिए डिज़ाइन किया गया था, लेकिन यह व्यक्तिगत डेवलपर के काम को आसान बनाता है।\n\nअपनी समय सीमा में सुधार करें, Performance को खोए बिना समय पर सब कुछ वितरित करें। Get हर किसी के लिए नहीं है, लेकिन अगर आपने उस वाक्यांश के साथ पहचान की है, तो Get आपके लिए है!\n\n# तीन सिद्धांत\n\n## State  management\n\nGet के दो अलग-अलग State Manager हैं: Simple State Builder (हम इसे GetBuilder कहते हैं) और Reactive State Manager (GetX/Obx)\n\n### Reactive  State  Manager\n\nReactive Programming कई लोगों को अलग-थलग कर सकती है क्योंकि इसे जटिल कहा जाता है। GetX Reactive Programming को काफी सरल बना देता है:\n\n- आपको StreamControllers बनाने की आवश्यकता नहीं होगी।\n\n- आपको प्रत्येक Variable के लिए StreamBuilder बनाने की आवश्यकता नहीं होगी\n\n- आपको प्रत्येक Class के लिए एक State बनाने की आवश्यकता नहीं होगी।\n\n- आपको Initial Value के लिए एक Get बनाने की आवश्यकता नहीं होगी।\n\n- आपको Code Generators का उपयोग करने की आवश्यकता नहीं होगी\n\n**Get** के साथ **Reactive Programming**, **\"setState()\"** का उपयोग करने जितना आसान है।\n\nआइए कल्पना करें कि आपके पास एक name Variable है और चाहते हैं कि हर बार जब आप इसे बदलते हैं, तो इसका उपयोग करने वाले सभी Widgets बदल जाएँ ।\nयह आपका count Variable है\n\n```dart\n\nvar name = 'Adison Masih';\n\n```\n\nइसे Observable बनाने के लिए, आपको बस इसके अंत में \".obs\" जोड़ना होगा:\n```dart\n\nvar name = 'Adison Masih'.obs;\n\n```\n\nअगर आप आप उस Value को दिखाना चाहते हैं और जब भी Value बदलती हैं तो स्क्रीन को करना चाहते हैं, तो यह करें:\n\n```dart\n\nObx(() => Text(\"${controller.name}\"));\n\n```\n\nबस इतना ही। यह _इत्ना_ आसान है।\n\n### State Management के बारे में अधिक जानकारी\n\nराज्य प्रबंधन की अधिक गहन व्याख्या [यहां](./documentation/en_US/state_management.md) देखें । वहां आपको अधिक उदाहरण और **Simple State Manager** और **Reactive State Manager** के बीच का अंतर दिखाई देगा\n\nआपको GetX की शक्ति का अच्छा अंदाजा हो जाएगा।\n\n## Route  प्रबंधन\n\nयदि आप बिना **context** के **Routes/Snackbars/Dialogs/Bottomsheets** का उपयोग करने जा रहे हैं, तो GetX आपके लिए भी उत्कृष्ट है, बस इसे देखें:\n\nअपने **\"MaterialApp()\"** से पहले **“Get”** जोड़ें, इसे **\"GetMaterialApp()\"** में बदल दें\n\n```dart\n\nGetMaterialApp( // यह पहले MaterialApp था\n\n  home: MyHome(),\n\n)\n\n```\n\nएक नई स्क्रीन पर Navigate करें:\n```dart\n\nGet.to(NextScreen());\n\n```\n\nनाम के साथ नई स्क्रीन पर Navigate करें। **Named Routes** पर अधिक विवरण [यहां](./documentation/en_US/route_management.md#navigation-with-named-routes) देखें।\n\n```dart\n\nGet.toNamed('/details');\n\n```\n\nSnackbar, Dialog तथा Bottomsheets या ऐसी किसी भी चीज़ को बंद करने के लिए आप आम तौर पर ```Navigator.pop(context);``` के साथ बंद करते हैं;\n\n```dart\n\nGet.back();\n\n```\nअगली Screen पर जाने के लिए और पिछली Screen पर वापस जाने का कोई विकल्प नहीं है (SplashScreens, Login Screens आदि में उपयोग के लिए)\n\n```dart\n\nGet.off(NextScreen());\n\n```\n\nअगली Screen पर जाने और पिछले सभी Routes को रद्द करने के लिए (Shopping Carts, Polls और Tests में उपयोगी)\n\n```dart\n\nGet.offAll(NextScreen());\n\n```\n\nध्यान दिया कि आपको इनमें से कोई भी काम करने के लिए **\"context\"** का उपयोग करने की आवश्यकता नहीं है? **\"Get Route Management\"** का उपयोग करने का यह सबसे बड़ा लाभ है। इसके साथ, आप इन सभी **\"Methods\"** को अपने **\"Controller Class\"** से बिना किसी चिंता के Execute कर सकते हैं।\n\n### Route Management के बारे में अधिक जानकारी\n\n**\"Named Routes\"** के साथ काम करें और अपने Routes पर **\"Lower-Level Control\"** भी प्राप्त करें! [यहां](./documentation/en_US/route_management.md) गहन दस्तावेज है\n"
  },
  {
    "path": "README-ne.md",
    "content": "![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png)\n\n[![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)\n[![popularity](https://img.shields.io/pub/popularity/get?logo=dart)](https://pub.dev/packages/get/score)\n[![likes](https://img.shields.io/pub/likes/get?logo=dart)](https://pub.dev/packages/get/score)\n[![pub points](https://img.shields.io/pub/points/sentry?logo=dart)](https://pub.dev/packages/get/score)\n![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)\n[![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart)\n[![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N)\n[![Get on Slack](https://img.shields.io/badge/slack-join-orange.svg)](https://communityinviter.com/apps/getxworkspace/getx)\n[![Telegram](https://img.shields.io/badge/chat-on%20Telegram-blue.svg)](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g)\n<a href=\"https://github.com/Solido/awesome-flutter\">\n<img alt=\"Awesome Flutter\" src=\"https://img.shields.io/badge/Awesome-Flutter-blue.svg?longCache=true&style=flat-square\" />\n</a>\n<a href=\"https://www.buymeacoffee.com/jonataslaw\" target=\"_blank\"><img src=\"https://i.imgur.com/aV6DDA7.png\" alt=\"Buy Me A Coffee\" style=\"height: 41px !important;width: 174px !important; box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;\" > </a>\n\n![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/getx.png)\n\n<div align=\"center\">\n\n**Languages:**\n\n[![English](https://img.shields.io/badge/Language-English-blueviolet?style=for-the-badge)](README.md)\n[![Vietnamese](https://img.shields.io/badge/Language-Vietnamese-blueviolet?style=for-the-badge)](README-vi.md)\n[![Indonesian](https://img.shields.io/badge/Language-Indonesian-blueviolet?style=for-the-badge)](README.id-ID.md)\n[![Urdu](https://img.shields.io/badge/Language-Urdu-blueviolet?style=for-the-badge)](README.ur-PK.md)\n[![Chinese](https://img.shields.io/badge/Language-Chinese-blueviolet?style=for-the-badge)](README.zh-cn.md)\n[![Portuguese](https://img.shields.io/badge/Language-Portuguese-blueviolet?style=for-the-badge)](README.pt-br.md)\n[![Spanish](https://img.shields.io/badge/Language-Spanish-blueviolet?style=for-the-badge)](README-es.md)\n[![Russian](https://img.shields.io/badge/Language-Russian-blueviolet?style=for-the-badge)](README.ru.md)\n[![Polish](https://img.shields.io/badge/Language-Polish-blueviolet?style=for-the-badge)](README.pl.md)\n[![Korean](https://img.shields.io/badge/Language-Korean-blueviolet?style=for-the-badge)](README.ko-kr.md)\n[![French](https://img.shields.io/badge/Language-French-blueviolet?style=for-the-badge)](README-fr.md)\n[![Japanese](https://img.shields.io/badge/Language-Japanese-blueviolet?style=for-the-badge)](README.ja-JP.md)\n[![Hindi](https://img.shields.io/badge/Language-Hindi-blueviolet?style=for-the-badge)](README-hi.md)\n[![Bangla](https://img.shields.io/badge/Language-Bangla-blueviolet?style=for-the-badge)](README-bn.md)\n[![Nepali](https://img.shields.io/badge/Language-Nepali-blueviolet?style=for-the-badge)](README-ne.md)\n\n</div>\n\n- [Get को बारेमा](#about-get)\n- [इन्स्टल गर्ने तरिका](#installing)\n- [GetX सहित काउन्टर एप](#counter-app-with-getx)\n- [तीन मुख्य आधार](#the-three-pillars)\n  - [स्टेट व्यवस्थापन](#state-management)\n    - [रिएक्टिभ स्टेट म्यानेजर](#reactive-state-manager)\n    - [स्टेट व्यवस्थापनबारे थप विवरण](#more-details-about-state-management)\n  - [रुट व्यवस्थापन](#route-management)\n    - [रुट व्यवस्थापनबारे थप विवरण](#more-details-about-route-management)\n  - [डिपेन्डेन्सी व्यवस्थापन](#dependency-management)\n    - [डिपेन्डेन्सी व्यवस्थापनबारे थप विवरण](#more-details-about-dependency-management)\n- [युटिल्स (Utils)](#utils)\n  - [अन्तर्राष्ट्रियकरण](#internationalization)\n    - [अनुवादहरू](#translations)\n      - [अनुवाद प्रयोग गर्ने तरिका](#using-translations)\n    - [लोकेलहरू (Locales)](#locales)\n      - [लोकेल परिवर्तन गर्ने](#change-locale)\n      - [सिस्टम लोकेल](#system-locale)\n  - [थिम परिवर्तन](#change-theme)\n  - [GetConnect](#getconnect)\n    - [डिफल्ट कन्फिगरेसन](#default-configuration)\n    - [कस्टम कन्फिगरेसन](#custom-configuration)\n  - [GetPage मिडलवेयर](#getpage-middleware)\n    - [प्राथमिकता](#priority)\n    - [रिडाइरेक्ट (Redirect)](#redirect)\n    - [onPageCalled](#onpagecalled)\n    - [OnBindingsStart](#onbindingsstart)\n    - [OnPageBuildStart](#onpagebuildstart)\n    - [OnPageBuilt](#onpagebuilt)\n    - [OnPageDispose](#onpagedispose)\n  - [अन्य उन्नत API हरू](#other-advanced-apis)\n    - [वैकल्पिक ग्लोबल सेटिङ र म्यानुअल कन्फिगरेसन](#optional-global-settings-and-manual-configurations)\n    - [लोकल स्टेट विजेटहरू](#local-state-widgets)\n      - [ValueBuilder](#valuebuilder)\n      - [ObxValue](#obxvalue)\n  - [उपयोगी टिप्स](#useful-tips)\n    - [GetView](#getview)\n    - [GetResponsiveView](#getresponsiveview)\n      - [यसलाई कसरी प्रयोग गर्ने](#how-to-use-it)\n    - [GetWidget](#getwidget)\n    - [GetxService](#getxservice)\n- [2.0 बाट भएका ब्रेकिङ परिवर्तनहरू](#breaking-changes-from-20)\n- [किन Getx?](#why-getx)\n- [कम्युनिटी](#community)\n  - [कम्युनिटी च्यानलहरू](#community-channels)\n  - [कसरी योगदान गर्ने](#how-to-contribute)\n  - [लेख र भिडियोहरू](#articles-and-videos)\n\n# Get को बारेमा\n\n- GetX Flutter को लागि एक अतिरिक्त-हल्का र शक्तिशाली समाधान हो। यसले उच्च प्रदर्शनको स्टेट व्यवस्थापन, बौद्धिक डिपेन्डेन्सी इन्जेक्शन, र रुट व्यवस्थापनलाई छिटो र व्यावहारिक रूपमा संयोजन गर्दछ।\n\n- GetX का ३ आधारभूत सिद्धान्तहरू छन्। यसको अर्थ पुस्तकालयका सबै स्रोतहरूको लागि यी प्राथमिकताहरू हुन्: **PRODUCTIVITY (उत्पादकता), PERFORMANCE (प्रदर्शन) र ORGANIZATION (संगठन)।**\n  - **PERFORMANCE (प्रदर्शन):** GetX प्रदर्शन र स्रोतहरूको न्यूनतम खपतमा केन्द्रित छ। GetX ले Streams वा ChangeNotifier प्रयोग गर्दैन।\n\n  - **PRODUCTIVITY (उत्पादकता):** GetX ले सजिलो र रमाइलो सिन्ट्याक्स प्रयोग गर्दछ। तपाईं जे गर्न चाहनुहुन्छ, GetX सँग सधैं सजिलो तरिका हुन्छ। यसले विकासका घण्टाहरू बचत गर्नेछ र तपाईंको अनुप्रयोगले दिन सक्ने अधिकतम प्रदर्शन प्रदान गर्नेछ।\n\n    सामान्यतया, विकासकर्ताले मेमोरीबाट Controller हरू हटाउने बारे चिन्ता गर्नुपर्छ। GetX सँग यो आवश्यक छैन किनकि स्रोतहरू डिफल्ट रूपमा प्रयोग नभएपछि मेमोरीबाट हटाइन्छन्। यदि तपाईं यसलाई मेमोरीमा राख्न चाहनुहुन्छ भने, तपाईंले आफ्नो डिपेन्डेन्सीमा \"permanent: true\" स्पष्ट रूपमा घोषणा गर्नुपर्छ। त्यसरी, समय बचत गर्नुको साथै, तपाईं मेमोरीमा अनावश्यक डिपेन्डेन्सीहरू हुने जोखिममा कम हुनुहुन्छ। डिपेन्डेन्सी लोडिङ पनि डिफल्ट रूपमा लेजी (lazy) हुन्छ।\n\n  - **ORGANIZATION (संगठन):** GetX ले View, प्रिजेन्टेसन लजिक, बिजनेस लजिक, डिपेन्डेन्सी इन्जेक्शन, र नेभिगेसनको पूर्ण डिकपलिंग (decoupling) गर्न अनुमति दिन्छ। रुटहरू बीच नेभिगेट गर्न तपाईंलाई context को आवश्यकता पर्दैन, त्यसैले तपाईं यसको लागि widget tree (visualization) मा निर्भर हुनुहुन्न। तपाईंलाई inheritedWidget मार्फत आफ्ना controllers/blocs पहुँच गर्न context आवश्यकता पर्दैन, त्यसैले तपाईंले आफ्नो प्रिजेन्टेसन लजिक र बिजनेस लजिकलाई आफ्नो भिजुअलाइजेसन लेयरबाट पूर्ण रूपमा अलग गर्नुहुन्छ। तपाईंले `MultiProvider` हरू मार्फत आफ्नो widget tree मा Controllers/Models/Blocs कक्षाहरू इन्जेक्ट गर्नुपर्दैन। यसको लागि, GetX ले आफ्नो डिपेन्डेन्सी इन्जेक्शन सुविधा प्रयोग गर्दछ, DI लाई यसको view बाट पूर्ण रूपमा अलग गर्दछ।\n\n    GetX सँग तपाईं आफ्नो एप्लिकेसनको हरेक फिचर कहाँ छ भन्ने कुरा सजिलै थाहा पाउनुहुन्छ, र डिफल्ट रूपमा कोड सफा रहन्छ। यसले मर्मतसम्भार (maintenance) सजिलो बनाउनुका साथै, Flutter मा पहिले असम्भवजस्तै लाग्ने मोड्युल साझेदारीलाई पनि पूर्ण रूपमा सम्भव बनाउँछ।\n    Flutter मा कोड व्यवस्थित गर्ने सुरुआती बिन्दु BLoC थियो, जसले business logic लाई visualization बाट अलग गर्‍यो। GetX यसको प्राकृतिक विकास हो—यसले business logic मात्र होइन, presentation logic पनि अलग गर्छ। थप रूपमा, dependency injection र routes पनि decoupled छन्, र data layer पनि यीबाट छुट्टै रहन्छ। तपाईंलाई सबै कुरा कहाँ छ भन्ने स्पष्ट हुन्छ, र यो सबै \"hello world\" बनाउने भन्दा पनि सजिलो तरिकाले गर्न सकिन्छ।\n    GetX, Flutter SDK प्रयोग गरेर उच्च-प्रदर्शन एपहरू बनाउने सबैभन्दा सजिलो, व्यवहारिक, र scalable तरिका हो। यसको वरिपरि ठूलो ecosystem छ जुन उत्कृष्ट रूपमा सँगै काम गर्छ; यो सुरु गर्नेहरूका लागि सजिलो छ र अनुभवी विकासकर्ताहरूका लागि पनि सटीक छ। यो सुरक्षित, स्थिर, अद्यावधिक, र default Flutter SDK मा नभएका धेरै built-in API हरूसहित आउँछ।\n\n- GetX अनावश्यक रूपमा भारी (bloated) छैन। यसमा धेरै सुविधाहरू छन् जसले तपाईंलाई कुनै चिन्ता बिना विकास सुरु गर्न मद्दत गर्छ, तर प्रत्येक सुविधा छुट्टाछुट्टै container मा हुन्छ र प्रयोग गरेपछि मात्रै सुरु हुन्छ। यदि तपाईंले State Management मात्र प्रयोग गर्नुभयो भने State Management मात्रै compile हुन्छ। यदि तपाईंले routes मात्रै प्रयोग गर्नुभयो भने state management सम्बन्धी कोड compile हुँदैन।\n\n- GetX को विशाल ecosystem, ठूलो समुदाय, धेरै सहयोगीहरू छन्, र Flutter रहुञ्जेल यसको मर्मतसम्भार जारी रहनेछ। GetX एउटै कोडबाट Android, iOS, Web, Mac, Linux, Windows र server मा पनि चल्न सक्षम छ।\n  **[Get Server](https://github.com/jonataslaw/get_server) प्रयोग गरेर frontend मा लेखेको कोड backend मा पनि पूर्ण रूपमा पुन: प्रयोग गर्न सकिन्छ।**\n\n**थप रूपमा, [Get CLI](https://github.com/jonataslaw/get_cli) प्रयोग गरेर server र frontend दुवैमा सम्पूर्ण विकास प्रक्रिया पूर्ण रूपमा automate गर्न सकिन्छ।**\n\n**अझ बढी उत्पादकता बढाउनका लागि, हामीसँग [VSCode को extension](https://marketplace.visualstudio.com/items?itemName=get-snippets.get-snippets) र [Android Studio/Intellij को extension](https://plugins.jetbrains.com/plugin/14975-getx-snippets) पनि उपलब्ध छन्।**\n\n# इन्स्टल गर्ने तरिका\n\nतपाईंको `pubspec.yaml` फाइलमा Get थप्नुहोस्:\n\n```yaml\ndependencies:\n  get:\n```\n\nजहाँ प्रयोग हुन्छ, ती फाइलहरूमा get इम्पोर्ट गर्नुहोस्:\n\n```dart\nimport 'package:get/get.dart';\n```\n\n# GetX सहित काउन्टर एप\n\nFlutter मा नयाँ प्रोजेक्ट बनाउँदा डिफल्ट आउने \"counter\" प्रोजेक्टमा (comments सहित) 100 भन्दा बढी लाइन हुन्छन्। Get कति शक्तिशाली छ देखाउन, म प्रत्येक क्लिकमा state परिवर्तन हुने, पेजहरू बीच स्विच हुने, र स्क्रिनहरूबीच state साझा हुने \"counter\" कसरी बनाउने भनेर देखाउँछु—यो सबै व्यवस्थित तरिकाले, business logic लाई view बाट अलग गरेर, comments सहित जम्मा 26 लाइन कोडमा।\n\n- चरण १:\n  आफ्नो `MaterialApp` अगाडि `Get` थपेर यसलाई `GetMaterialApp` बनाउनुहोस्\n\n```dart\nvoid main() => runApp(GetMaterialApp(home: Home()));\n```\n\n- नोट: यसले Flutter को `MaterialApp` लाई परिवर्तन गर्दैन। `GetMaterialApp` परिवर्तन गरिएको `MaterialApp` होइन; यो केवल pre-configured Widget हो, जसको child को रूपमा default `MaterialApp` हुन्छ। तपाईंले यसलाई manually configure गर्न सक्नुहुन्छ, तर सामान्यतया आवश्यक पर्दैन। `GetMaterialApp` ले routes बनाउँछ, तिनीहरू inject गर्छ, translations inject गर्छ, र route navigation का लागि चाहिने सबै कुरा तयार पार्छ। यदि तपाईं Get लाई state management वा dependency management का लागि मात्र प्रयोग गर्दै हुनुहुन्छ भने `GetMaterialApp` आवश्यक छैन। `GetMaterialApp` routes, snackbars, internationalization, bottomSheets, dialogs, र context बिना प्रयोग हुने high-level APIs का लागि आवश्यक हुन्छ।\n- नोट²: यो चरण route management (`Get.to()`, `Get.back()` आदि) प्रयोग गर्ने हो भने मात्र आवश्यक हुन्छ। यदि प्रयोग गर्नुहुन्न भने चरण १ आवश्यक छैन।\n\n- चरण २:\n  आफ्नो business logic class बनाउनुहोस् र त्यसभित्र सबै variables, methods, र controllers राख्नुहोस्।\n  साधारण `.obs` प्रयोग गरेर कुनै पनि variable लाई observable बनाउन सकिन्छ।\n\n```dart\nclass Controller extends GetxController{\n  var count = 0.obs;\n  increment() => count++;\n}\n```\n\n- चरण ३:\n  आफ्नो View बनाउनुहोस्, `StatelessWidget` प्रयोग गर्नुहोस् र केही RAM बचत गर्नुहोस्। Get प्रयोग गर्दा `StatefulWidget` को आवश्यकता धेरै अवस्थामा नपर्न सक्छ।\n\n```dart\nclass Home extends StatelessWidget {\n\n  @override\n  Widget build(context) {\n\n        // आफ्नो class लाई Get.put() प्रयोग गरेर instantiate गर्नुहोस्,\n        // ताकि त्यो त्यहाँका सबै \"child\" routes मा उपलब्ध होस्।\n    final Controller c = Get.put(Controller());\n\n    return Scaffold(\n          // count परिवर्तन हुँदा Text() अपडेट गर्न Obx(() => ...) प्रयोग गर्नुहोस्।\n          appBar: AppBar(title: Obx(() => Text(\"क्लिक: ${c.count}\"))),\n\n          // 8 लाइनको Navigator.push को सट्टा साधारण Get.to() प्रयोग गर्नुहोस्। context चाहिँदैन।\n      body: Center(child: ElevatedButton(\n            child: Text(\"अर्को पेजमा जानुहोस्\"), onPressed: () => Get.to(Other()))),\n      floatingActionButton:\n          FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment));\n  }\n}\n\nclass Other extends StatelessWidget {\n  // अर्को पेजले प्रयोग गरिरहेको Controller लाई Get.find() मार्फत पाउन सकिन्छ।\n  final Controller c = Get.find();\n\n  @override\n  Widget build(context){\n    // अपडेट भएको count variable प्रयोग गर्नुहोस्\n     return Scaffold(body: Center(child: Text(\"${c.count}\")));\n  }\n}\n```\n\nनतिजा:\n\n![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/counter-app-gif.gif)\n\nयो सरल प्रोजेक्ट हो, तर यसले Get कति शक्तिशाली छ भन्ने कुरा स्पष्ट देखाउँछ। तपाईंको प्रोजेक्ट बढ्दै जाँदा यो फरक अझ स्पष्ट देखिन्छ।\n\nGet टिमसँग काम गर्न डिजाइन गरिएको हो, तर यसले एकल डेभलपरको काम पनि सरल बनाउँछ।\n\nआफ्नो deadline सुधार्नुहोस्, performance नघटाई काम समयमै डेलिभर गर्नुहोस्। Get सबैका लागि नहुन सक्छ, तर यदि तपाईंलाई यो कुरा उपयुक्त लाग्छ भने Get तपाईंका लागि हो!\n\n# तीन मुख्य आधार\n\n## स्टेट व्यवस्थापन\n\nGet मा दुई फरक स्टेट म्यानेजर छन्: simple state manager (यसलाई हामी GetBuilder भन्छौं) र reactive state manager (GetX/Obx)।\n\n### रिएक्टिभ स्टेट म्यानेजर\n\nरिएक्टिभ प्रोग्रामिङ जटिल छ भन्ने धारणा भएकाले धेरैलाई यो अप्ठ्यारो लाग्न सक्छ। तर GetX ले reactive programming लाई धेरै सरल बनाउँछ:\n\n- तपाईंले StreamController बनाउनुपर्दैन।\n- प्रत्येक variable को लागि StreamBuilder बनाउनुपर्दैन।\n- प्रत्येक state का लागि छुट्टै class बनाउनुपर्दैन।\n- initial value का लागि get बनाउनुपर्दैन।\n- code generators प्रयोग गर्नुपर्दैन।\n\nGet सँग reactive programming गर्नु `setState` प्रयोग गरे जत्तिकै सजिलो हुन्छ।\n\nमानौं तपाईंसँग `name` variable छ र तपाईं चाहनुहुन्छ कि यसलाई परिवर्तन गर्दा यसलाई प्रयोग गर्ने सबै widgets स्वतः अपडेट होउन्।\n\nयो तपाईंको `name` variable हो:\n\n```dart\nvar name = 'Jonatas Borges';\n```\n\nयसलाई observable बनाउन, अन्त्यमा `.obs` थप्नुहोस्:\n\n```dart\nvar name = 'Jonatas Borges'.obs;\n```\n\nUI मा त्यो value देखाउन र value परिवर्तन हुँदा स्क्रिन अपडेट गर्न, यसरी गर्नुहोस्:\n\n```dart\nObx(() => Text(\"${controller.name}\"));\n```\n\nयत्ति हो। यति सजिलो छ।\n\n### स्टेट व्यवस्थापनबारे थप विवरण\n\n**स्टेट व्यवस्थापनको अझ विस्तृत व्याख्या [यहाँ](./documentation/en_US/state_management.md) हेर्नुहोस्। त्यहाँ तपाईंले थप उदाहरणहरू र simple state manager तथा reactive state manager बीचको फरक पनि देख्नुहुनेछ।**\n\nयसले तपाईंलाई GetX को शक्ति राम्रोसँग बुझ्न मद्दत गर्छ।\n\n## रुट व्यवस्थापन\n\nयदि तपाईं context बिना routes/snackbars/dialogs/bottomsheets प्रयोग गर्न चाहनुहुन्छ भने GetX तपाईंका लागि उत्कृष्ट विकल्प हो:\n\nआफ्नो `MaterialApp` अगाडि `Get` थपेर यसलाई `GetMaterialApp` बनाउनुहोस्:\n\n```dart\nGetMaterialApp( // पहिले: MaterialApp(\n  home: MyHome(),\n)\n```\n\nनयाँ स्क्रिनमा जान:\n\n```dart\n\nGet.to(NextScreen());\n```\n\nनाम (named route) प्रयोग गरेर नयाँ स्क्रिनमा जान। Named routes बारे थप विवरण [यहाँ](./documentation/en_US/route_management.md#navigation-with-named-routes) हेर्नुहोस्।\n\n```dart\n\nGet.toNamed('/details');\n```\n\nsnackbar, dialog, bottomsheet, वा सामान्यतया `Navigator.pop(context)` ले बन्द गर्ने कुनै पनि चीज बन्द गर्न:\n\n```dart\nGet.back();\n```\n\nअर्को स्क्रिनमा जान र अघिल्लो स्क्रिनमा फर्किने विकल्प हटाउन (SplashScreen, login screens आदि लागि):\n\n```dart\nGet.off(NextScreen());\n```\n\nअर्को स्क्रिनमा जान र सबै अघिल्ला routes हटाउन (shopping carts, polls, tests मा उपयोगी):\n\n```dart\nGet.offAll(NextScreen());\n```\n\nहेर्नुभयो? यी कुनै पनि काम गर्न तपाईंलाई context चाहिएन। यही नै Get route management को सबैभन्दा ठूलो फाइदामध्ये एक हो। यसरी तपाईं यी सबै methods आफ्नो controller class भित्रैबाट सजिलै चलाउन सक्नुहुन्छ।\n\n### रुट व्यवस्थापनबारे थप विवरण\n\n**Get ले named routes सँग काम गर्छ र तपाईंलाई routes माथि low-level control पनि दिन्छ! यसको विस्तृत documentation [यहाँ](./documentation/en_US/route_management.md) उपलब्ध छ।**\n\n## डिपेन्डेन्सी व्यवस्थापन\n\nGet सँग सरल र शक्तिशाली dependency manager छ, जसले Provider context वा inheritedWidget बिना, केवल १ लाइन कोडमै तपाईंको Bloc वा Controller जस्तै class प्राप्त गर्न दिन्छ:\n\n```dart\nController controller = Get.put(Controller()); // Controller controller = Controller(); को सट्टा\n```\n\n- नोट: यदि तपाईं Get को State Manager प्रयोग गर्दै हुनुहुन्छ भने bindings API मा ध्यान दिनुहोस्; यसले तपाईंको view र controller जोड्न सजिलो बनाउँछ।\n\nतपाईंले प्रयोग गरिरहेको class भित्र instantiate गर्नुको सट्टा, तपाईं class लाई Get instance भित्र instantiate गर्नुहुन्छ, जसले यसलाई पुरै App मा उपलब्ध बनाउँछ।\nत्यसपछि तपाईं आफ्नो controller (वा Bloc class) सामान्य रूपमा प्रयोग गर्न सक्नुहुन्छ।\n\n**टिप:** Get को dependency management, package का अन्य भागहरूबाट decoupled छ। त्यसैले तपाईंको app पहिले नै कुनै पनि state manager प्रयोग गरिरहेको छ भने पनि सबै कुरा फेरि लेख्नुपर्दैन; यो dependency injection सिधै प्रयोग गर्न सकिन्छ।\n\n```dart\ncontroller.fetchApi();\n```\n\nमानौं तपाईं धेरै routes हुँदै अघि बढ्नुभयो र controller मा पहिलेको data फेरि चाहियो। सामान्यतया state manager सँग Provider वा Get_it चाहिन्थ्यो, हैन? Get सँग त्यस्तो चाहिँदैन। तपाईंले Get लाई controller \"find\" गर्न भन्नु मात्र पर्छ; अतिरिक्त dependency आवश्यक पर्दैन:\n\n```dart\nController controller = Get.find();\n// हो, यो जादू जस्तो देखिन्छ—Get ले सही controller फेला पारेर तपाईंलाई दिन्छ।\n// लाखौं controllers instantiate भए पनि Get ले सही controller नै दिन्छ।\n```\n\nत्यसपछि तपाईं पहिले प्राप्त भएको controller data फेरि प्रयोग गर्न सक्नुहुन्छ:\n\n```dart\nText(controller.textFromApi);\n```\n\n### डिपेन्डेन्सी व्यवस्थापनबारे थप विवरण\n\n**डिपेन्डेन्सी व्यवस्थापनको विस्तृत व्याख्या [यहाँ](./documentation/en_US/dependency_management.md) हेर्नुहोस्।**\n\n# युटिल्स\n\n## अन्तर्राष्ट्रियकरण\n\n### अनुवादहरू\n\nअनुवादहरू साधारण key-value dictionary map को रूपमा राखिन्छन्।\ncustom translations थप्न class बनाएर `Translations` लाई extend गर्नुहोस्।\n\n```dart\nimport 'package:get/get.dart';\n\nclass Messages extends Translations {\n  @override\n  Map<String, Map<String, String>> get keys => {\n        'en_US': {\n          'hello': 'Hello World',\n        },\n        'de_DE': {\n          'hello': 'Hallo Welt',\n        }\n      };\n}\n```\n\n#### अनुवाद प्रयोग गर्ने तरिका\n\nनिर्दिष्ट key को अन्त्यमा `.tr` थप्नुहोस्। त्यसपछि `Get.locale` र `Get.fallbackLocale` को हालको मान अनुसार अनुवाद हुन्छ।\n\n```dart\nText('title'.tr);\n```\n\n#### एकवचन र बहुवचनसहित अनुवाद प्रयोग गर्ने तरिका\n\n```dart\nvar products = [];\nText('singularKey'.trPlural('pluralKey', products.length, Args));\n```\n\n#### parameters सहित अनुवाद प्रयोग गर्ने तरिका\n\n```dart\nimport 'package:get/get.dart';\n\n\nMap<String, Map<String, String>> get keys => {\n    'en_US': {\n    'logged_in': '@name को रूपमा @email इमेलसहित लगइन गरिएको छ',\n    },\n    'es_ES': {\n     'logged_in': '@name को रूपमा @email इमेलसहित लगइन गरिएको छ',\n    }\n};\n\nText('logged_in'.trParams({\n  'name': 'Jhon',\n  'email': 'jhon@example.com'\n  }));\n```\n\n### लोकेलहरू\n\nlocale र translations सेट गर्न `GetMaterialApp` मा parameters दिनुहोस्।\n\n```dart\nreturn GetMaterialApp(\n  translations: Messages(), // तपाईंका अनुवादहरू\n  locale: Locale('en', 'US'), // अनुवाद यही locale मा देखाइन्छ\n  fallbackLocale: Locale('en', 'UK'), // अमान्य locale चयन भए fallback locale प्रयोग हुन्छ\n);\n```\n\n#### लोकेल परिवर्तन गर्ने\n\nlocale अपडेट गर्न `Get.updateLocale(locale)` चलाउनुहोस्। त्यसपछि अनुवादले स्वतः नयाँ locale प्रयोग गर्छ।\n\n```dart\nvar locale = Locale('en', 'US');\nGet.updateLocale(locale);\n```\n\n#### सिस्टम लोकेल\n\nsystem locale पढ्न `Get.deviceLocale` प्रयोग गर्न सकिन्छ।\n\n```dart\nreturn GetMaterialApp(\n    locale: Get.deviceLocale,\n);\n```\n\n## थिम परिवर्तन\n\nअपडेट गर्न `GetMaterialApp` भन्दा माथिल्लो स्तरको widget प्रयोग नगर्नुहोस्। यसले duplicate keys समस्या ल्याउन सक्छ। थिम बदल्न मात्र `ThemeProvider` widget बनाउने पुरानो शैली धेरैले प्रयोग गर्छन्, तर **GetX™** मा यो आवश्यक छैन।\n\nतपाईं custom theme बनाएर कुनै boilerplate बिना `Get.changeTheme` भित्र सिधै प्रयोग गर्न सक्नुहुन्छ:\n\n```dart\nGet.changeTheme(ThemeData.light());\n```\n\nयदि `onTap` मा Theme बदल्ने बटन बनाउनु छ भने, तपाईं **GetX™** का दुई API संयोजन गर्न सक्नुहुन्छ:\n\n- dark `Theme` प्रयोगमा छ कि छैन जाँच्ने API\n- र `Theme` परिवर्तन गर्ने API, जसलाई `onPressed` मा राख्न सकिन्छ:\n\n```dart\nGet.changeTheme(Get.isDarkMode? ThemeData.light(): ThemeData.dark());\n```\n\n`.darkmode` सक्रिय हुँदा यो _light theme_ मा स्विच हुन्छ, र _light theme_ सक्रिय हुँदा _dark theme_ मा बदलिन्छ।\n\n## GetConnect\n\nGetConnect भनेको backend र frontend बीच http वा websocket मार्फत संवाद गर्ने सजिलो तरिका हो।\n\n### डिफल्ट कन्फिगरेसन\n\nतपाईं GetConnect लाई extend गरेर GET/POST/PUT/DELETE/SOCKET methods प्रयोग गरी आफ्नो REST API वा websocket सँग सजिलै संवाद गर्न सक्नुहुन्छ।\n\n```dart\nclass UserProvider extends GetConnect {\n  // GET अनुरोध\n  Future<Response> getUser(int id) => get('http://youapi/users/$id');\n  // POST अनुरोध\n  Future<Response> postUser(Map data) => post('http://youapi/users', body: data);\n  // फाइलसहित POST अनुरोध\n  Future<Response<CasesModel>> postCases(List<int> image) {\n    final form = FormData({\n      'file': MultipartFile(image, filename: 'avatar.png'),\n      'otherFile': MultipartFile(image, filename: 'cover.png'),\n    });\n    return post('http://youapi/users/upload', form);\n  }\n\n  GetSocket userMessages() {\n    return socket('https://yourapi/users/socket');\n  }\n}\n```\n\n### कस्टम कन्फिगरेसन\n\nGetConnect धेरै नै customizable छ। तपाईं base URL, response modifiers, request modifiers, authenticator, र authenticate गर्ने प्रयास संख्या सेट गर्न सक्नुहुन्छ। साथै standard decoder सेट गरेर कुनै अतिरिक्त configuration बिना सबै requests लाई तपाईंका Models मा रूपान्तरण गर्न सकिन्छ।\n\n```dart\nclass HomeProvider extends GetConnect {\n  @override\n  void onInit() {\n    // सबै requests jsonDecode हुँदै CasesModel.fromJson मा जान्छन्\n    httpClient.defaultDecoder = CasesModel.fromJson;\n    httpClient.baseUrl = 'https://api.covid19api.com';\n    // baseUrl = 'https://api.covid19api.com'; // यसले baseUrl सेट गर्छ\n    // यदि [httpClient] instance बिना प्रयोग भयो भने Http र websocket दुवैका लागि\n\n    // यसले सबै requests का headers मा 'apikey' थप्छ\n    httpClient.addRequestModifier((request) {\n      request.headers['apikey'] = '12345678';\n      return request;\n    });\n\n    // server ले \"Brazil\" को data पठाए पनि,\n    // response deliver हुनुअघि नै हटाइने भएकाले\n    // त्यो data प्रयोगकर्तालाई देखिँदैन\n    httpClient.addResponseModifier<CasesModel>((request, response) {\n      CasesModel model = response.body;\n      if (model.countries.contains('Brazil')) {\n        model.countries.remove('Brazilll');\n      }\n    });\n\n    httpClient.addAuthenticator((request) async {\n      final response = await get(\"http://yourapi/token\");\n      final token = response.body['token'];\n      // header सेट गर्ने\n      request.headers['Authorization'] = \"$token\";\n      return request;\n    });\n\n    // यदि HttpStatus.unauthorized आयो भने\n    // authenticator 3 पटकसम्म call हुन्छ\n    httpClient.maxAuthRetries = 3;\n  }\n\n  @override\n  Future<Response<CasesModel>> getCases(String path) => get(path);\n}\n```\n\n## GetPage मिडलवेयर\n\nअब GetPage मा नयाँ property छ जसले GetMiddleware को list लिन्छ र तिनलाई निर्दिष्ट क्रम अनुसार चलाउँछ।\n\n**नोट**: GetPage मा middleware भएमा, त्यस page का सबै child pages मा पनि ती middleware स्वतः लागू हुन्छन्।\n\n### प्राथमिकता\n\nmiddlewares चल्ने क्रम GetMiddleware भित्रको priority बाट सेट गर्न सकिन्छ।\n\n```dart\nfinal middlewares = [\n  GetMiddleware(priority: 2),\n  GetMiddleware(priority: 5),\n  GetMiddleware(priority: 4),\n  GetMiddleware(priority: -8),\n];\n```\n\nयी middlewares **-8 => 2 => 4 => 5** क्रममै चल्छन्।\n\n### रिडाइरेक्ट\n\nयो function call गरिएको route को page खोजिँदै गर्दा चल्छ। यसले redirect का लागि `RouteSettings` return गर्छ। `null` फर्काए redirect हुँदैन।\n\n```dart\nRouteSettings redirect(String route) {\n  final authService = Get.find<AuthService>();\n  return authService.authed.value ? null : RouteSettings(name: '/login')\n}\n```\n\n### onPageCalled\n\nयो function page call भएपछि, कुनै object create हुनुअघि चल्छ।\nयसले page का केही गुण परिवर्तन गर्न वा नयाँ page return गर्न मद्दत गर्छ।\n\n```dart\nGetPage onPageCalled(GetPage page) {\n  final authService = Get.find<AuthService>();\n  return page.copyWith(title: 'Welcome ${authService.UserName}');\n}\n```\n\n### OnBindingsStart\n\nयो function Bindings initialize हुनुअघि चल्छ।\nयहाँबाट तपाईं यस page का Bindings परिवर्तन गर्न सक्नुहुन्छ।\n\n```dart\nList<Bindings> onBindingsStart(List<Bindings> bindings) {\n  final authService = Get.find<AuthService>();\n  if (authService.isAdmin) {\n    bindings.add(AdminBinding());\n  }\n  return bindings;\n}\n```\n\n### OnPageBuildStart\n\nयो function Bindings initialize भएलगत्तै चल्छ।\nयहाँ bindings तयार भएपछि र page widget बन्नुअघि केही काम गर्न सकिन्छ।\n\n```dart\nGetPageBuilder onPageBuildStart(GetPageBuilder page) {\n  print('bindings तयार छन्');\n  return page;\n}\n```\n\n### OnPageBuilt\n\nयो function `GetPage.page` call भएलगत्तै चल्छ र त्यस function को result (देखाइने widget) दिन्छ।\n\n### OnPageDispose\n\nयो function page सँग सम्बन्धित सबै objects (Controllers, views, ...) dispose भएपछि तुरुन्त चल्छ।\n\n## अन्य उन्नत API हरू\n\n```dart\n// हालको स्क्रिनबाट वर्तमान args पाउने\nGet.arguments\n\n// अघिल्लो route को नाम पाउने\nGet.previousRoute\n\n// raw route मा पहुँच दिने, जस्तै rawRoute.isFirst()\nGet.rawRoute\n\n// GetObserver बाट Routing API मा पहुँच\nGet.routing\n\n// snackbar खुला छ कि छैन जाँच्ने\nGet.isSnackbarOpen\n\n// dialog खुला छ कि छैन जाँच्ने\nGet.isDialogOpen\n\n// bottomsheet खुला छ कि छैन जाँच्ने\nGet.isBottomSheetOpen\n\n// एउटा route हटाउने\nGet.removeRoute()\n\n// predicate true नआएसम्म बारम्बार back जाने\nGet.until()\n\n// अर्को route मा जाने र predicate true नआएसम्म अघिल्ला routes हटाउने\nGet.offUntil()\n\n// अर्को named route मा जाने र predicate true नआएसम्म अघिल्ला routes हटाउने\nGet.offNamedUntil()\n\n// app कुन platform मा चलिरहेको छ जाँच्ने\nGetPlatform.isAndroid\nGetPlatform.isIOS\nGetPlatform.isMacOS\nGetPlatform.isWindows\nGetPlatform.isLinux\nGetPlatform.isFuchsia\n\n// device को प्रकार जाँच्ने\nGetPlatform.isMobile\nGetPlatform.isDesktop\n// web मा सबै platforms स्वतन्त्र रूपमा समर्थित छन्!\n// तपाईं browser भित्र चलिरहेको छ कि छैन थाहा पाउन सक्नुहुन्छ\n// Windows, iOS, OSX, Android आदि मा पनि\nGetPlatform.isWeb\n\n\n// MediaQuery.of(context).size.height को equivalent,\n// तर immutable\nGet.height\nGet.width\n\n// Navigator को current context दिन्छ\nGet.context\n\n// तपाईंको code को जहाँबाट पनि foreground snackbar/dialog/bottomsheet को context दिन्छ\nGet.contextOverlay\n\n// नोट: तलका methods, context मा extensions हुन्।\n// UI को जहाँ context छ, त्यहीँ यी प्रयोग गर्न सकिन्छ\n\n// changeable height/width चाहिएको छ भने (जस्तै Desktop वा browser window resize हुँदा)\n// context प्रयोग गर्नुपर्छ\ncontext.width\ncontext.height\n\n// स्क्रिनको आधा, एक-तिहाइ आदि जस्ता आकार सजिलै परिभाषित गर्न मद्दत गर्छ\n// responsive app का लागि उपयोगी\n// param dividedBy (double) optional - default: 1\n// param reducedBy (double) optional - default: 0\ncontext.heightTransformer()\ncontext.widthTransformer()\n\n/// MediaQuery.sizeOf(context) जस्तै\ncontext.mediaQuerySize()\n\n/// MediaQuery.paddingOf(context) जस्तै\ncontext.mediaQueryPadding()\n\n/// MediaQuery.viewPaddingOf(context) जस्तै\ncontext.mediaQueryViewPadding()\n\n/// MediaQuery.viewInsetsOf(context) जस्तै\ncontext.mediaQueryViewInsets()\n\n/// MediaQuery.orientationOf(context) जस्तै\ncontext.orientation()\n\n/// device landscape mode मा छ कि छैन जाँच्ने\ncontext.isLandscape()\n\n/// device portrait mode मा छ कि छैन जाँच्ने\ncontext.isPortrait()\n\n/// MediaQuery.devicePixelRatioOf(context) जस्तै\ncontext.devicePixelRatio()\n\n/// MediaQuery.textScaleFactorOf(context) जस्तै\ncontext.textScaleFactor()\n\n/// स्क्रिनको shortestSide पाउने\ncontext.mediaQueryShortestSide()\n\n/// width 800 भन्दा ठूलो भए true\ncontext.showNavbar()\n\n/// shortestSide 600 भन्दा सानो भए true\ncontext.isPhone()\n\n/// shortestSide 600 भन्दा ठूलो भए true\ncontext.isSmallTablet()\n\n/// shortestSide 720 भन्दा ठूलो भए true\ncontext.isLargeTablet()\n\n/// हालको device tablet भए true\ncontext.isTablet()\n\n/// screen size अनुसार value<T> return गर्छ\n/// निम्न अवस्थाका लागि value दिन सकिन्छ:\n/// watch: shortestSide 300 भन्दा सानो\n/// mobile: shortestSide 600 भन्दा सानो\n/// tablet: shortestSide 1200 भन्दा सानो\n/// desktop: width 1200 भन्दा ठूलो\ncontext.responsiveValue<T>()\n```\n\n### वैकल्पिक ग्लोबल सेटिङ र म्यानुअल कन्फिगरेसन\n\n`GetMaterialApp` ले धेरैजसो कुरा स्वचालित रूपमा configure गर्छ, तर तपाईं Get लाई manually पनि configure गर्न सक्नुहुन्छ।\n\n```dart\nMaterialApp(\n  navigatorKey: Get.key,\n  navigatorObservers: [GetObserver()],\n);\n```\n\nतपाईं `GetObserver` भित्र आफ्नै Middleware पनि प्रयोग गर्न सक्नुहुन्छ, यसले अरू व्यवहारमा असर गर्दैन।\n\n```dart\nMaterialApp(\n  navigatorKey: Get.key,\n  navigatorObservers: [\n    GetObserver(MiddleWare.observer) // यहाँ\n  ],\n);\n```\n\nतपाईं `Get` का लागि _Global Settings_ बनाउन सक्नुहुन्छ। कुनै route push गर्नु अघि code मा `Get.config` थप्नुहोस्।\nवा सिधै `GetMaterialApp` भित्र पनि सेट गर्न सकिन्छ।\n\n```dart\nGetMaterialApp(\n  enableLog: true,\n  defaultTransition: Transition.fade,\n  opaqueRoute: Get.isOpaqueRouteDefault,\n  popGesture: Get.isPopGestureEnable,\n  transitionDuration: Get.defaultDurationTransition,\n  defaultGlobalState: Get.defaultGlobalState,\n);\n\nGet.config(\n  enableLog = true,\n  defaultPopGesture = true,\n  defaultTransition = Transitions.cupertino\n)\n```\n\nतपाईं चाहनुहुन्छ भने `Get` का सबै logging messages लाई redirect गर्न सक्नुहुन्छ।\nआफ्नो मनपर्ने logging package प्रयोग गरेर\nत्यहीं logs capture गर्न:\n\n```dart\nGetMaterialApp(\n  enableLog: true,\n  logWriterCallback: localLogWriter,\n);\n\nvoid localLogWriter(String text, {bool isError = false}) {\n  // message लाई यहाँ आफ्नो मनपर्ने logging package मा पठाउनुहोस्\n  // नोट: enableLog: false भए पनि logs यो callback मा पठाइन्छन्\n  // चाहनुहुन्छ भने GetConfig.isLogEnable मार्फत flag जाँच्न सक्नुहुन्छ\n}\n\n```\n\n### लोकल स्टेट विजेटहरू\n\nयी Widgets ले तपाईंलाई एउटै value व्यवस्थापन गर्न र state लाई local/ephemeral रूपमा राख्न मद्दत गर्छ।\nReactive र Simple दुवै प्रकार उपलब्ध छन्।\nउदाहरणका लागि, `TextField` मा obscureText toggle गर्न, custom\nExpandable Panel बनाउन, वा `Scaffold` को body परिवर्तन गर्दै `BottomNavigationBar` को current index बदल्न सकिन्छ।\n\n#### ValueBuilder\n\n`StatefulWidget` को सरल रूप, जसले updated value लिने `.setState` callback सँग काम गर्छ।\n\n```dart\nValueBuilder<bool>(\n  initialValue: false,\n  builder: (value, updateFn) => Switch(\n    value: value,\n    onChanged: updateFn, // उही signature! चाहनुहुन्छ भने ( newValue ) => updateFn( newValue ) पनि प्रयोग गर्न सकिन्छ\n  ),\n  // builder method बाहिर केही call गर्नुपरेमा\n  onUpdate: (value) => print(\"मान अपडेट भयो: $value\"),\n  onDispose: () => print(\"विजेट हटाइयो\"),\n),\n```\n\n#### ObxValue\n\n[`ValueBuilder`](#valuebuilder) जस्तै, तर यो Reactive version हो। तपाईं Rx instance पास गर्नुहुन्छ (`.obs` याद छ?) र\nयो स्वतः अपडेट हुन्छ... शानदार छैन र?\n\n```dart\nObxValue((data) => Switch(\n        value: data.value,\n  onChanged: data, // Rx मा _callable_ function हुन्छ! चाहनुहुन्छ भने (flag) => data.value = flag पनि प्रयोग गर्न सकिन्छ\n    ),\n    false.obs,\n),\n```\n\n## उपयोगी टिप्स\n\n`.obs` observables (जसलाई _Rx_ Types पनि भनिन्छ) मा धेरै प्रकारका internal methods र operators हुन्छन्।\n\n> `.obs` भएको property नै वास्तविक value हो भनेर _सोच्नु_ सामान्य कुरा हो... तर यो भ्रममा नपर्नुहोस्!\n> हामी variable को Type declaration धेरै पटक छोड्छौं, किनकि Dart compiler पर्याप्त स्मार्ट छ, र code\n> सफा देखिन्छ, तर:\n\n```dart\nvar message = 'Hello world'.obs;\nprint( 'सन्देश \"$message\" को Type ${message.runtimeType} हो');\n```\n\n`message` ले वास्तविक String value _print_ गरे पनि यसको Type **RxString** नै हुन्छ!\n\nत्यसैले, `message.substring( 0, 4 )` सिधै गर्न मिल्दैन।\nतपाईंले _observable_ भित्रको वास्तविक `value` पहुँच गर्नुपर्छ:\nसबैभन्दा धेरै प्रयोग हुने तरिका `.value` हो, तर तपाईंले यो पनि प्रयोग गर्न सक्नुहुन्छ...\n\n```dart\nfinal name = 'GetX'.obs;\n// value अहिलेको भन्दा फरक भए मात्र stream \"update\" हुन्छ\nname.value = 'Hey';\n\n// सबै Rx properties \"callable\" हुन्छन् र नयाँ value फर्काउँछन्\n// तर यो तरिकाले `null` स्वीकार्दैन, UI rebuild हुँदैन\nname('Hello');\n\n// getter जस्तै काम गर्छ, 'Hello' print हुन्छ\nname() ;\n\n/// numbers:\n\nfinal count = 0.obs;\n\n// num primitives का सबै non-mutable operations प्रयोग गर्न सकिन्छ!\ncount + 1;\n\n// ध्यान दिनुहोस्! `count` final नभई var हुँदा मात्र यो मान्य हुन्छ\ncount += 1;\n\n// values सँग compare पनि गर्न सकिन्छ:\ncount > 2;\n\n/// booleans:\n\nfinal flag = false.obs;\n\n// value लाई true/false बीच switch गर्छ\nflag.toggle();\n\n\n/// all types:\n\n// `value` लाई null बनाउँछ\nflag.nil();\n\n// सबै toString(), toJson() operations `value` मा forward हुन्छन्\nprint( count ); // RxInt को भित्री `toString()` call हुन्छ\n\nfinal abc = [0,1,2].obs;\n// value लाई JSON array मा बदल्छ, RxList print हुन्छ\n// सबै Rx types मा Json support हुन्छ!\nprint('json: ${jsonEncode(abc)}, type: ${abc.runtimeType}');\n\n// RxMap, RxList र RxSet विशेष Rx types हुन्, जसले आफ्नै native types extend गर्छन्\n// तर reactive हुँदाहुँदै पनि List जस्तै सामान्य रूपमा काम गर्न सकिन्छ!\nabc.add(12); // list मा 12 थप्छ र stream UPDATE गर्छ\nabc[3]; // List जस्तै index 3 पढ्छ\n\n\n// equality Rx र value दुवैसँग काम गर्छ, तर hashCode चाहिँ सधैं value बाट लिइन्छ\nfinal number = 12.obs;\nprint( number == 12 ); // prints > true\n\n/// Custom Rx Models:\n\n// toJson(), toString() child मा defer हुन्छन्, त्यसैले तपाईं override गरेर observable लाई direct print() गर्न सक्नुहुन्छ\n\nclass User {\n    String name, last;\n    int age;\n    User({this.name, this.last, this.age});\n\n    @override\n  String toString() => '$name $last, $age वर्ष';\n}\n\nfinal user = User(name: 'John', last: 'Doe', age: 33).obs;\n\n// `user` \"reactive\" हो, तर भित्रका properties भने reactive छैनन्!\n// त्यसैले भित्रको कुनै variable परिवर्तन गर्‍यौं भने...\nuser.value.name = 'Roi';\n// widget rebuild हुँदैन\n// `Rx` लाई user भित्रको परिवर्तन स्वतः थाहा हुँदैन\n// त्यसैले custom class मा परिवर्तन manually \"notify\" गर्नुपर्छ\nuser.refresh();\n\n// वा `update()` method प्रयोग गर्न सकिन्छ!\nuser.update((value){\n  value.name='Roi';\n});\n\nprint( user );\n```\n\n## StateMixin\n\n`UI` state व्यवस्थापन गर्ने अर्को तरिका `StateMixin<T>` प्रयोग गर्नु हो।\nयसलाई लागू गर्न, `with` प्रयोग गरेर controller मा `StateMixin<T>` थप्नुहोस्,\nजसले T model स्वीकार्छ।\n\n```dart\nclass Controller extends GetController with StateMixin<User>{}\n```\n\n`change()` method ले चाहिएको बेला State परिवर्तन गर्छ।\ndata र status यसरी पास गर्नुहोस्:\n\n```dart\nchange(data, status: RxStatus.success());\n```\n\nRxStatus मा यी status उपलब्ध छन्:\n\n```dart\nRxStatus.loading();\nRxStatus.success();\nRxStatus.empty();\nRxStatus.error('message');\n```\n\nयसलाई UI मा देखाउन:\n\n```dart\nclass OtherClass extends GetView<Controller> {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n\n      body: controller.obx(\n        (state)=>Text(state.name),\n\n        // यहाँ तपाईं custom loading indicator राख्न सक्नुहुन्छ,\n        // default रूपमा Center(child:CircularProgressIndicator()) हुन्छ\n        onLoading: CustomLoadingIndicator(),\n        onEmpty: Text('डाटा फेला परेन'),\n\n        // यहाँ पनि आफ्नो error widget राख्न सकिन्छ,\n        // default रूपमा Center(child:Text(error)) हुन्छ\n        onError: (error)=>Text(error),\n      ),\n    );\n}\n```\n\n#### GetView\n\nयो Widget धेरै सरल तर निकै उपयोगी छ!\n\nयो `const Stateless` Widget हो, जसमा registered `Controller` का लागि `controller` getter हुन्छ—बस त्यत्ति।\n\n```dart\n class AwesomeController extends GetController {\n   final String title = 'मेरो उत्कृष्ट View';\n }\n\n  // controller register गर्दा प्रयोग गरेको `Type` सधैं पास गर्न सम्झनुहोस्!\n class AwesomeView extends GetView<AwesomeController> {\n   @override\n   Widget build(BuildContext context) {\n     return Container(\n       padding: EdgeInsets.all(20),\n       child: Text(controller.title), // `controller.something` सिधै call गर्नुहोस्\n     );\n   }\n }\n```\n\n#### GetResponsiveView\n\nresponsive view बनाउन यो widget extend गर्नुहोस्।\nयस widget मा `screen` property हुन्छ जसमा\nscreen को size र type सम्बन्धी सबै जानकारी हुन्छ।\n\n##### कसरी प्रयोग गर्ने\n\nयसलाई build गर्ने दुई तरिका छन्।\n\n- `builder` method प्रयोग गरेर build हुने widget return गर्ने।\n- `desktop`, `tablet`, `phone`, `watch` methods प्रयोग गर्ने।\n  screen type जुन method सँग मिल्छ, त्यही method build हुन्छ।\n  जस्तै screen [ScreenType.Tablet] भए `tablet` method चल्छ, आदि।\n  **नोट:** यो तरिका प्रयोग गर्दा `alwaysUseBuilder` property लाई `false` राख्नुहोस्।\n\n`settings` property प्रयोग गरेर screen types का width limit सेट गर्न सकिन्छ।\n\n![example](https://github.com/SchabanBo/get_page_example/blob/master/docs/Example.gif?raw=true)\nयो screen को कोड\n[code](https://github.com/SchabanBo/get_page_example/blob/master/lib/pages/responsive_example/responsive_view.dart)\n\n#### GetWidget\n\nधेरै मानिसलाई यो Widget बारे थाहा हुँदैन, वा यसको प्रयोगबारे भ्रम हुन्छ।\nयसको use case कमै हुन्छ, तर निकै specific छ: यसले Controller लाई `cache` गर्छ।\nयो _cache_ गर्ने भएकाले, यो `const Stateless` हुन सक्दैन।\n\n> त्यसो भए Controller लाई \"cache\" कहिले गर्नुपर्छ?\n\nयदि तपाईं **GetX** को अर्को कम प्रयोग हुने feature `Get.create()` प्रयोग गर्नुहुन्छ भने।\n\n`Get.create(()=>Controller())` ले `Get.find<Controller>()` तपाईंले कल गरेको प्रत्येक पटक\nनयाँ `Controller` बनाउँछ,\n\nयहीँ `GetWidget` सबैभन्दा उपयोगी हुन्छ... उदाहरणका लागि,\nTodo items को list राख्न। त्यसैले widget \"rebuilt\" भए पनि उही controller instance कायम रहन्छ।\n\n#### GetxService\n\nयो class `GetxController` जस्तै हो, र यसको lifecycle (`onInit()`, `onReady()`, `onClose()`) पनि उस्तै हुन्छ।\nतर यसभित्र आफ्नै \"logic\" हुँदैन। यसले **GetX** Dependency Injection system लाई यो subclass\nमेमोरीबाट **हटाउन नमिल्ने** हो भनेर मात्र सूचित गर्छ।\n\nत्यसैले `Get.find()` बाट आफ्ना \"Services\" सधैं reachable र active राख्न यो निकै उपयोगी छ। जस्तै:\n`ApiService`, `StorageService`, `CacheService`.\n\n```dart\nFuture<void> main() async {\n  await initServices(); /// SERVICES INITIALIZATION पर्खनुहोस्।\n  runApp(SomeApp());\n}\n\n/// Flutter app चलाउनु अघि Services initialize गर्नु राम्रो अभ्यास हो।\n/// यसले execution flow नियन्त्रण गर्न मद्दत गर्छ (जस्तै Theme configuration,\n/// apiKey, User को language आदि लोड गर्नुपरेमा... त्यसैले ApiService अघि SettingService लोड गर्नुहोस्।\n/// यसरी GetMaterialApp() लाई rebuild गर्न नपरी values सिधै लिन सक्छ।\nvoid initServices() async {\n  print('services सुरु हुँदैछन् ...');\n  /// यहीँ get_storage, hive, shared_pref initialization राखिन्छ।\n  /// वा moor connection, वा अन्य कुनै async initialization।\n  await Get.putAsync(() => DbService().init());\n  await Get.putAsync(SettingsService()).init();\n  print('सबै services सुरु भए...');\n}\n\nclass DbService extends GetxService {\n  Future<DbService> init() async {\n    print('$runtimeType 2 सेकेन्ड ढिलाइ');\n    await 2.delay();\n    print('$runtimeType तयार!');\n    return this;\n  }\n}\n\nclass SettingsService extends GetxService {\n  void init() async {\n    print('$runtimeType 1 सेकेन्ड ढिलाइ');\n    await 1.delay();\n    print('$runtimeType तयार!');\n  }\n}\n\n```\n\n`GetxService` लाई वास्तवमै delete गर्ने एक मात्र तरिका `Get.reset()` हो,\nजुन app को \"Hot Reboot\" जस्तै हो। त्यसैले app को सम्पूर्ण जीवनकालभरि class instance निरन्तर चाहिन्छ भने\n`GetxService` प्रयोग गर्नुहोस्।\n\n### परीक्षणहरू\n\nतपाईं आफ्ना controllers लाई अन्य class जस्तै test गर्न सक्नुहुन्छ, lifecycle सहित:\n\n```dart\nclass Controller extends GetxController {\n  @override\n  void onInit() {\n    super.onInit();\n    // मानलाई name2 मा परिवर्तन गर्ने\n    name.value = 'name2';\n  }\n\n  @override\n  void onClose() {\n    name.value = '';\n    super.onClose();\n  }\n\n  final name = 'name1'.obs;\n\n  void changeName() => name.value = 'name3';\n}\n\nvoid main() {\n  test('''\nreactive variable \"name\" को state, सबै lifecycle मा test गर्ने''',\n      () {\n    /// lifecycle बिना पनि controller test गर्न सकिन्छ,\n    /// तर GetX dependency injection प्रयोग गर्दै हुनुहुन्छ भने\n    ///  यो सिफारिस गरिँदैन\n    final controller = Controller();\n    expect(controller.name.value, 'name1');\n\n    /// GetX dependency injection प्रयोग गर्दा, तपाईं सबै test गर्न सक्नुहुन्छ,\n    /// प्रत्येक lifecycle पछि app को state समेत।\n    Get.put(controller); // onInit was called\n    expect(controller.name.value, 'name2');\n\n    /// functions test गर्ने\n    controller.changeName();\n    expect(controller.name.value, 'name3');\n\n    /// onClose was called\n    Get.delete<Controller>();\n\n    expect(controller.name.value, '');\n  });\n}\n```\n\n#### सुझावहरू\n\n##### Mockito वा mocktail\n\nयदि तपाईंले आफ्नो GetxController/GetxService mock गर्नुपर्छ भने, GetxController लाई extend गरी Mock सँग mixin गर्नुहोस्, यसरी:\n\n```dart\nclass NotificationServiceMock extends GetxService with Mock implements NotificationService {}\n```\n\n##### Get.reset() प्रयोग गर्ने\n\nयदि widget वा test groups परीक्षण गर्दै हुनुहुन्छ भने, अघिल्लो test का settings reset गर्न test अन्त्यमा वा `tearDown` मा `Get.reset` प्रयोग गर्नुहोस्।\n\n##### Get.testMode\n\nयदि controllers भित्र navigation प्रयोग गर्दै हुनुहुन्छ भने, `main` को सुरुमा `Get.testMode = true` राख्नुहोस्।\n\n# 2.0 बाट भएका ब्रेकिङ परिवर्तनहरू\n\n1- Rx types:\n\n| Before  | After      |\n| ------- | ---------- |\n| StringX | `RxString` |\n| IntX    | `RxInt`    |\n| MapX    | `RxMap`    |\n| ListX   | `RxList`   |\n| NumX    | `RxNum`    |\n| DoubleX | `RxDouble` |\n\nRxController र GetBuilder अब merge भएका छन्। अब कुन controller प्रयोग गर्ने भनेर छुट्टै सम्झिरहनुपर्दैन—`GetxController` मात्र प्रयोग गरे पुग्छ; यो simple state management र reactive दुवैमा काम गर्छ।\n\n2- Named Routes\nपहिले:\n\n```dart\nGetMaterialApp(\n  namedRoutes: {\n    '/': GetRoute(page: Home()),\n  }\n)\n```\n\nअब:\n\n```dart\nGetMaterialApp(\n  getPages: [\n    GetPage(name: '/', page: () => Home()),\n  ]\n)\n```\n\nयो परिवर्तन किन?\nधेरै अवस्थामा parameter वा login token का आधारमा कुन page देखाउने भन्ने निर्णय गर्नुपर्छ, तर पुरानो तरिका यसका लागि लचिलो थिएन।\npage लाई function भित्र राख्दा RAM खपत उल्लेखनीय रूपमा घट्यो, किनकि app सुरुहुँदा नै सबै routes मेमोरीमा allocate हुँदैनन्। साथै यसले यस्तो approach सम्भव बनायो:\n\n```dart\n\nGetStorage box = GetStorage();\n\nGetMaterialApp(\n  getPages: [\n    GetPage(name: '/', page:(){\n      return box.hasData('token') ? Home() : Login();\n    })\n  ]\n)\n```\n\n# किन Getx?\n\n1- Flutter update पछि धेरै package हरू टुट्ने अवस्था धेरै पटक आउँछ। कहिलेकाहीँ compilation errors आउँछन्, जसको समाधान तुरुन्त उपलब्ध हुँदैन। विकासकर्ताले error को स्रोत पत्ता लगाउनुपर्छ, trace गर्नुपर्छ, त्यसपछि मात्र सम्बन्धित repository मा issue खोल्नुपर्छ। Get ले विकासका मुख्य स्रोतहरू (state, dependency र route management) एउटै ठाउँमा ल्याउँछ, जसले pubspec मा एउटै package थपेर काम सुरु गर्न दिन्छ। Flutter update पछि सामान्यतया Get dependency update गरे पुग्छ। Get ले compatibility समस्या पनि कम गर्छ। एउटा package को version अर्कोसँग नमिल्ने समस्या पनि धेरै घट्छ, किनकि सबै कुरा एउटै package भित्र पूर्ण रूपमा compatible हुन्छ।\n\n2- Flutter सजिलो र उत्कृष्ट छ, तर अझै केही boilerplate चाहिन्छ जुन धेरै विकासकर्तालाई अनावश्यक लाग्न सक्छ, जस्तै `Navigator.of(context).push (context, builder [...])`। Get ले विकासलाई सरल बनाउँछ। route call गर्न 8 लाइन लेख्नुको सट्टा `Get.to(Home())` लेखेर सीधै अर्को page मा जान सकिन्छ। Flutter मा dynamic web URLs बनाउन अहिले पनि झन्झटिलो छ, तर GetX सँग यो धेरै सरल छ। Flutter मा state management र dependency management का लागि pub मा सयौं patterns छन्, जसले चर्चा बढाउँछ। तर variable को अन्त्यमा `.obs` थपेर widget लाई `Obx` भित्र राख्नु जत्तिकै सजिलो तरिका विरलै छ—त्यसपछि त्यो variable का सबै updates स्क्रिनमा स्वतः देखिन्छन्।\n\n3- performance को चिन्ता बिना सजिलो विकास। Flutter को performance पहिले नै राम्रो छ, तर मानौं तपाईं state manager र locator प्रयोग गरेर blocs/stores/controllers आदि बाँडिरहनु भएको छ—अब नचाहिँदा dependency manually हटाउनुपर्छ। GetX मा भने controller प्रयोग गरिरहँदा ठीकै, र कसैले प्रयोग नगरेपछि त्यो स्वतः memory बाट हट्छ। यही काम GetX गर्छ। SmartManagement सँग प्रयोग नभएका सबै चीजहरू memory बाट हट्छन्, र तपाईंले programming बाहेक अरू धेरै चिन्ता लिनुपर्दैन। यसरी कुनै अतिरिक्त logic नलेखी पनि न्यूनतम स्रोत प्रयोग सुनिश्चित हुन्छ।\n\n4- वास्तविक decoupling। तपाईंले \"view र business logic अलग राख्ने\" अवधारणा पक्कै सुन्नुभएको छ। यो BLoC, MVC, MVVM जस्ता patterns मा सामान्य अवधारणा हो। तर Flutter मा context प्रयोगका कारण यो व्यवहारमा कमजोर पर्न सक्छ।\nयदि InheritedWidget फेला पार्न context चाहियो भने context view मा राख्नुपर्छ वा parameter बाट पास गर्नुपर्छ। team मा काम गर्दा यसले View र business logic बीच अनावश्यक निर्भरता बढाउँछ। Getx ले केही unorthodox तर सफा approach दिन्छ। यसले StatefulWidget, InitState आदि पूर्ण रूपमा निषेध गर्दैन, तर प्रायः सफा विकल्प दिन्छ। Controllers का lifecycle हुन्छन्, र API REST call जस्ता कामका लागि view मा निर्भर हुनुपर्दैन। `onInit` बाट http call सुरु गर्न सकिन्छ, data आएपछि variables populate हुन्छन्। GetX पूर्ण रूपमा reactive भएकाले (streams मा काम गर्छ), data भरिएपछि त्यसलाई प्रयोग गर्ने widgets view मा स्वतः update हुन्छन्। यसले UI मा काम गर्ने व्यक्तिलाई widgets मै केन्द्रित हुन दिन्छ, र business logic टोलीलाई छुट्टै business logic बनाउन तथा test गर्न स्वतन्त्रता दिन्छ।\n\nयो library निरन्तर update हुँदै नयाँ features थपिरहनेछ। निःसंकोच PR पठाएर योगदान गर्नुहोस्।\n\n# कम्युनिटी\n\n## कम्युनिटी च्यानलहरू\n\nGetX को समुदाय अत्यन्त सक्रिय र सहयोगी छ। तपाईंलाई प्रश्न छ वा यो framework प्रयोगमा सहयोग चाहिन्छ भने, हाम्रो community channels मा जोडिनुहोस्—त्यहाँ छिटो र उचित उत्तर पाउनुहुन्छ। यो repository मुख्यतः issues खोल्न र features अनुरोध गर्नका लागि हो, तर GetX Community को हिस्सा बन्न निःसंकोच आउनुहोस्।\n\n| **Slack**                                                                                                                   | **Discord**                                                                                                                 | **Telegram**                                                                                                          |\n| :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------- |\n| [![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) |\n\n<a id=\"how-to-contribute\"></a>\n\n## योगदान कसरी गर्ने\n\n_प्रोजेक्टमा योगदान गर्न चाहनुहुन्छ? हामी तपाईंलाई हाम्रो सहयोगीको रूपमा देखाउन पाउँदा खुसी हुनेछौं। तपाईंले Get (र Flutter) लाई अझ राम्रो बनाउन योगदान गर्न सक्ने केही क्षेत्रहरू:_\n\n- README लाई अन्य भाषामा अनुवाद गर्न सहयोग गर्ने।\n- README मा documentation थप्ने (Get का धेरै functions अझै documented छैनन्)।\n- Get प्रयोग सिकाउने लेख वा भिडियो बनाउने (यी README र भविष्यमा Wiki मा थपिनेछन्)।\n- code/tests का लागि PRs दिने।\n- नयाँ functions थप्ने।\n\nकुनै पनि योगदान स्वागतयोग्य छ!\n\n<a id=\"articles-and-videos\"></a>\n\n## लेख र भिडियोहरू\n\n- [Flutter Getx EcoSystem package for arabic people](https://www.youtube.com/playlist?list=PLV1fXIAyjeuZ6M8m56zajMUwu4uE3-SL0) - [Pesa Coder](https://github.com/UsamaElgendy) को ट्युटोरियल।\n- [Dynamic Themes in 3 lines using GetX™](https://medium.com/swlh/flutter-dynamic-themes-in-3-lines-c3b375f292e3) - [Rod Brown](https://github.com/RodBr) को ट्युटोरियल।\n- [Complete GetX™ Navigation](https://www.youtube.com/watch?v=RaqPIoJSTtI) - Amateur Coder द्वारा Route management भिडियो।\n- [Complete GetX State Management](https://www.youtube.com/watch?v=CNpXbeI_slw) - Amateur Coder द्वारा State management भिडियो।\n- [GetX™ Other Features](https://youtu.be/ttQtlX_Q0eU) - Amateur Coder द्वारा Utils, storage, bindings र अन्य features सम्बन्धी भिडियो।\n- [Firestore User with GetX | Todo App](https://www.youtube.com/watch?v=BiV0DcXgk58) - Amateur Coder द्वारा भिडियो।\n- [Firebase Auth with GetX | Todo App](https://www.youtube.com/watch?v=-H-T_BSgfOE) - Amateur Coder द्वारा भिडियो।\n- [The Flutter GetX™ Ecosystem ~ State Management](https://medium.com/flutter-community/the-flutter-getx-ecosystem-state-management-881c7235511d) - [Aachman Garg](https://github.com/imaachman) द्वारा State management लेख।\n- [The Flutter GetX™ Ecosystem ~ Dependency Injection](https://medium.com/flutter-community/the-flutter-getx-ecosystem-dependency-injection-8e763d0ec6b9) - [Aachman Garg](https://github.com/imaachman) द्वारा Dependency Injection लेख।\n- [GetX, the all-in-one Flutter package](https://www.youtube.com/watch?v=IYQgtu9TM74) - Thad Carnevalli द्वारा State Management र Navigation समेटिएको छोटो ट्युटोरियल।\n- [Build a To-do List App from scratch using Flutter and GetX](https://www.youtube.com/watch?v=EcnqFasHf18) - Thad Carnevalli द्वारा UI + State Management + Storage भिडियो।\n- [GetX Flutter Firebase Auth Example](https://medium.com/@jeffmcmorris/getx-flutter-firebase-auth-example-b383c1dd1de2) - Jeff McMorris द्वारा लेख।\n- [Flutter State Management with GetX – Complete App](https://www.appwithflutter.com/flutter-state-management-with-getx/) - App With Flutter द्वारा।\n- [Flutter Routing with Animation using Get Package](https://www.appwithflutter.com/flutter-routing-using-get-package/) - App With Flutter द्वारा।\n- [A minimal example on dartpad](https://dartpad.dev/2b3d0d6f9d4e312c5fdbefc414c1727e?) - [Roi Peker](https://github.com/roipeker) द्वारा।\n- [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/) - [MD Sarfaraj](https://github.com/socialmad) द्वारा।\n- [How To Create an App with GetX Architect in Flutter with Get CLI](https://www.youtube.com/watch?v=7mb4qBA7kTk&t=1380s) - [MD Sarfaraj](https://github.com/socialmad) द्वारा।\n"
  },
  {
    "path": "README-vi.md",
    "content": "![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png)\n\n**Ngôn ngữ: Tiếng Việt (file này), [English](README.md), [Indonesian](README.id-ID.md), [Urdu](README.ur-PK.md), [Chinese](README.zh-cn.md), [Brazilian Portuguese](README.pt-br.md), [Spanish](README-es.md), [Russian](README.ru.md), [Polish](README.pl.md), [Korean](README.ko-kr.md), [French](README-fr.md).**\n\n[![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)\n[![popularity](https://badges.bar/get/popularity)](https://pub.dev/packages/sentry/score)\n[![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)\n[![pub points](https://badges.bar/get/pub%20points)](https://pub.dev/packages/get/score)\n![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)\n[![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart)\n[![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N)\n[![Get on Slack](https://img.shields.io/badge/slack-join-orange.svg)](https://communityinviter.com/apps/getxworkspace/getx)\n[![Telegram](https://img.shields.io/badge/chat-on%20Telegram-blue.svg)](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g)\n<a href=\"https://github.com/Solido/awesome-flutter\">\n<img alt=\"Awesome Flutter\" src=\"https://img.shields.io/badge/Awesome-Flutter-blue.svg?longCache=true&style=flat-square\" />\n</a>\n<a href=\"https://www.buymeacoffee.com/jonataslaw\" target=\"_blank\"><img src=\"https://i.imgur.com/aV6DDA7.png\" alt=\"Buy Me A Coffee\" style=\"height: 41px !important;width: 174px !important; box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;\" > </a>\n\n![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/getx.png)\n\n- [Về GetX](#về-getx)\n- [Cài Đặt](#cài-đặt)\n- [Counter App với GetX](#counter-app-với-getx)\n- [Tam Trụ](#tam-trụ)\n  - [Quản lý State](#quản-lý-state)\n    - [Quản lý Reactive State](#quản-lý-reactive-state)\n    - [Thêm thông tin về quản lý state](#thêm-thông-tin-về-quản-lý-state)\n  - [Quản lý route](#quản-lý-route)\n    - [Thêm thông tin về quản lý route](#thêm-thông-tin-về-quản-lý-route)\n  - [Quản lý dependency](#quản-lý-dependency)\n    - [Thêm thông tin về quản lý dependency](#thêm-thông-tin-về-quản-lý-dependency)\n- [Utils](#utils)\n  - [Internationalization](#internationalization)\n    - [Dịch thuật](#dịch-thuật)\n      - [Sử dụng bản dịch thuật](#sử-dụng-bản-dịch-thuật)\n    - [Locales](#locales)\n      - [Đổi locale](#đổi-locale)\n      - [System locale](#system-locale)\n  - [Đổi Theme](#đổi-theme)\n  - [GetConnect](#getconnect)\n    - [Cấu hình mặc định](#cấu-hình-mặc-định)\n    - [Cấu hình tùy chỉnh](#cấu-hình-tùy-chỉnh)\n  - [GetPage Middleware](#getpage-middleware)\n    - [Ưu tiên](#ưu-tiên)\n    - [Chuyển hướng](#chuyển-hướng)\n    - [onPageCalled](#onpagecalled)\n    - [OnBindingsStart](#onbindingsstart)\n    - [OnPageBuildStart](#onpagebuildstart)\n    - [OnPageBuilt](#onpagebuilt)\n    - [OnPageDispose](#onpagedispose)\n  - [APIs nâng cao khác](#apis-nâng-cao-khác)\n    - [Cấu hình thủ công và cài đặt chung tuỳ chọn](#cấu-hình-thủ-công-và-cài-đặt-chung-tuỳ-chọn)\n    - [Local State Widgets](#local-state-widgets)\n      - [ValueBuilder](#valuebuilder)\n      - [ObxValue](#obxvalue)\n  - [Mẹo hữu ích](#mẹo-hữu-ích)\n    - [GetView](#getview)\n    - [GetResponsiveView](#getresponsiveview)\n      - [Hướng dẫn sử dụng trước khi dùng](#hướng-dẫn-sử-dụng-trước-khi-dùng)\n    - [GetWidget](#getwidget)\n    - [GetxService](#getxservice)\n- [Thay đổi đột phá 2.0](#thay-đổi-đột-phá-2.0)\n- [Tại sao lại dùng GetX](#tại-sao-lại-dùng-getx)\n- [Cộng đồng](#cộng-đồng)\n  - [Kênh Cộng đồng](#kênh-cộng-đồng)\n  - [Cách cống hiến](#cách-cống-hiến)\n  - [Các bài báo và video](#các-bài-báo-và-video)\n\n# Về GetX\n\n- GetX hướng tới sự nhỏ gọn và giải pháp tối ưu cho Flutter với tốc độ ưu việt trong quản lý state, nạp dependency thông minh, và quản lý route nhanh chóng và thực tế.\n\n- GetX hướng tới 3 tham vọng chính, nghĩa là tất cả các tài nguyên của thư viện sẽ dành cho những điểm ưu tiên sau: **NĂNG SUẤT, HIỆU SUẤT VÀ TỔ CHỨC.**\n\n  - **HIỆU SUẤT:** GetX tập trung vào hiệu suất và mức tiêu thụ tài nguyên tối thiểu, do đó nó không sử dụng Streams hoặc ChangeNotifier.\n\n  - **NĂNG SUẤT:** GetX sử dụng một cú pháp dễ dàng và dễ thở. Bất kể bạn muốn làm gì, luôn có một cách dễ dàng hơn với GetX. Nó sẽ tiết kiệm hàng giờ phát triển và sẽ cung cấp hiệu suất tối đa mà ứng dụng của bạn có thể mang lại.\n\n    Nói chung, nhà phát triển nên quan tâm đến việc xóa những controller ra khỏi bộ nhớ. Với GetX, mặc định các tài nguyên sẽ\n    TỰ ĐỘNG xóa khỏi bộ nhớ khi không dùng nữa. Nếu bạn muốn giữ nó trong bộ nhớ, bạn phải khai báo rõ ràng \"permanent: true\" trong phần dependency của mình. Từ đó, bạn sẽ tiết kiệm thời gian và giảm rủi ro khi phụ thuộc vào bộ nhớ. Theo mặc định, tính năng tải dependency cũng lười biếng.\n\n  - **TỔ CHỨC:**\n    GetX cho phép tách toàn bộ View, presentation logic, business logic, nạp dependencies và điều hướng. Bạn không cần \"context\" để điều hướng giữa các route, vì vậy bạn sẽ độc lập trong sơ đồ widget (trực quan hóa). Bạn không cần \"context\" để truy cập Controller / Blocs của mình thông qua một InheritedWidget, vì vậy bạn hoàn toàn tách rời presentation logic và business logic ra khỏi lớp trực quan của mình. Bạn không cần phải đưa các Controller / Models / Blocs vào sơ đồ widget của mình thông qua `MultiProvider`, vì GetX sử dụng tính năng nạp dependency của riêng nó, tách hoàn toàn DI khỏi chế độ xem của nó.\n\n    Với GetX, bạn biết nơi tìm từng tính năng ứng dụng của mình, với cơ chế clean code theo mặc định. Ngoài việc giúp bảo trì dễ dàng, GetX giúp việc chia sẻ các mô-đun trở thành khả thi trong Flutter.\n    BLoC là điểm khởi đầu để tổ chức code trong Flutter, nó tách biệt business logic ra khỏi lớp trực quan hóa (visualization). GetX nảy sinh từ điều này, không chỉ tách biệt presentation logic mà còn cả business logic. Nạp dependency bổ sung và route cũng được tách ra và lớp dữ liệu cũng biến mất. Bạn sẽ biết mọi thứ ở đâu và sẽ hình dung tất cả những điều này dễ hơn cả xây dựng chương trình \"Hello World\".\n    GetX là cách dễ nhất, thiết thực và có thể mở rộng để xây dựng các ứng dụng hiệu suất cao với Flutter SDK. GetX chứa đựng một hệ sinh thái rộng lớn xung quanh nó hoạt động hoàn hảo cùng nhau, rất dễ dàng cho người mới bắt đầu và nó chính xác cho các chuyên gia. Nó an toàn, ổn định, luôn cập nhật và cung cấp một loạt các API được tích hợp sẵn mà không có trong Flutter SDK mặc định.\n\n- GetX không cồng kềnh và có vô số tính năng cho phép bạn bắt đầu lập trình mà không cần lo lắng về bất cứ điều gì. Đặc biệt, nó cho phép mỗi tính năng này nằm trong các vùng chứa riêng biệt và chỉ được bắt đầu sau khi sử dụng. Nếu bạn chỉ sử dụng phần quản lý state của GetX thì sẽ chỉ có quản lý state được sử dụng. Nếu bạn chỉ sử dụng route, thì GetX không biên dịch phần quản lý state.\n\n- GetX có một hệ sinh thái khổng lồ, một cộng đồng lớn, một số lượng lớn cộng tác viên và sẽ được duy trì miễn là Flutter còn tồn tại. GetX có khả năng chạy cùng một mã (code) trên Android, iOS, Web, Mac, Linux, Windows và trên máy chủ của bạn.\n  **Bạn hoàn toàn có thể sử dụng lại mã của mình trên frontend qua backend với [Get Server](https://github.com/jonataslaw/get_server)**.\n\n**Ngoài ra, toàn bộ quá trình phát triển có thể hoàn toàn tự động, cả trên máy chủ và frontend với [Get CLI](https://github.com/jonataslaw/get_cli)**.\n\n**Ngoài ra, nhằm tăng thêm năng suất của bạn, chúng tôi hỗ trợ\n[tiện ích trên VSCode](https://marketplace.visualstudio.com/items?itemName=get-snippets.get-snippets) và [tiện ích cho Android Studio/Intellij](https://plugins.jetbrains.com/plugin/14975-getx-snippets)**\n\n# Cài Đặt\n\nThêm Get vào file pubspec.yaml:\n\n```yaml\ndependencies:\n  get:\n```\n\nImport get vào file cần sử dụng:\n\n```dart\nimport 'package:get/get.dart';\n```\n\n# Counter App với GetX\n\nDự án \"counter\" được tạo theo mặc định trên dự án mới trên Flutter có hơn 100 dòng (có comments). Để thể hiện sức mạnh của Get, tôi sẽ trình bày cách tạo \"counter\" thay đổi trạng thái với mỗi lần nhấp, chuyển đổi giữa các trang và chia sẻ trạng thái giữa các màn hình, tất cả đều theo cách có tổ chức, tách biệt logic nghiệp vụ khỏi chế độ xem, CHỈ VỚI 26 DÒNG!\n\n- Bước 1:\n  Thêm \"Get\" trước MaterialApp, nó sẽ thành GetMaterialApp\n\n```dart\nvoid main() => runApp(GetMaterialApp(home: Home()));\n```\n\n- Chú ý: điều này không sửa đổi MaterialApp của Flutter, GetMaterialApp không phải là MaterialApp được sửa đổi, nó chỉ là một Widget được tạo trước với MaterialApp mặc định là child. Bạn có thể cấu hình điều này theo cách thủ công, nhưng nó chắc chắn là không cần thiết. GetMaterialApp sẽ tạo các route, đưa chúng vào, đưa bản dịch, đưa mọi thứ bạn cần để điều hướng route. Nếu bạn chỉ sử dụng Get để quản lý trạng thái hoặc quản lý phụ thuộc, thì không cần thiết phải sử dụng GetMaterialApp. Tóm lại, GetMaterialApp chỉ cần thiết cho các route, snacksbar, internationalization, bottomSheets, Dialog và các APIs cấp cao liên quan đến route và không có \"context\".\n- Chú ý²: Một lần nữa, bước này chỉ cần thiết nếu bạn sử dụng quản lý route (`Get.to ()`, `Get.back ()`, v.v.). Nếu bạn không sử dụng nó thì không cần thực hiện bước 1\n\n- Bước 2:\n  Tạo lớp business logic của bạn và đặt tất cả các biến (variables), hàm (function) và controller bên trong nó.\n  Bạn có thể làm cho bất kỳ biến nào có thể quan sát được đơn giản bằng cách sử dụng \".obs\".\n\n```dart\nclass Controller extends GetxController{\n  var count = 0.obs;\n  increment() => count++;\n}\n```\n\n- Bước 3:\n  Tạo widget của bạn, sử dụng StatelessWidget và tiết kiệm RAM, với Get, bạn có thể không cần sử dụng StatefulWidget nữa.\n\n```dart\nclass Home extends StatelessWidget {\n\n  @override\n  Widget build(context) {\n\n    // Instantiate your class using Get.put() to make it available for all \"child\" routes there.\n    final Controller c = Get.put(Controller());\n\n    return Scaffold(\n      // Use Obx(()=> to update Text() whenever count is changed.\n      appBar: AppBar(title: Obx(() => Text(\"Clicks: ${c.count}\"))),\n\n      // Replace the 8 lines Navigator.push by a simple Get.to(). You don't need context\n      body: Center(child: ElevatedButton(\n              child: Text(\"Go to Other\"), onPressed: () => Get.to(Other()))),\n      floatingActionButton:\n          FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment));\n  }\n}\n\nclass Other extends StatelessWidget {\n  // You can ask Get to find a Controller that is being used by another page and redirect you to it.\n  final Controller c = Get.find();\n\n  @override\n  Widget build(context){\n     // Access the updated count variable\n     return Scaffold(body: Center(child: Text(\"${c.count}\")));\n  }\n}\n```\n\nKết quả:\n\n![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/counter-app-gif.gif)\n\nĐây là một dự án đơn giản nhưng nó đã cho thấy rõ sức mạnh của Get. Khi dự án của bạn phát triển, sự khác biệt này sẽ trở nên đáng kể hơn.\n\nGet được thiết kế để làm việc với các nhóm, nhưng nó làm cho công việc của một nhà phát triển cá nhân trở nên đơn giản.\n\nCải thiện thời gian, giao mọi thứ đúng hạn mà không làm giảm hiệu suất. Get không dành cho tất cả mọi người, nhưng nếu bạn đã xác định gắn với Get, Get sẽ \"get\" bạn!\n\n# Tam Trụ\n\n## Quản lý State\n\nGet có 2 cách quản lý trạng thái (state managers) khác nhau : quản lý trạng thái đơn giản (chúng ta gọi nó là GetBuilder) và quản lý trạng thái phản ứng (the reactive state manager) (GetX/Obx).\n\n### Quản lý Reactive State\n\nLập trình phản ứng (reactive programming) có thể khiến nhiều người xa lánh vì nó được cho là phức tạp. GetX biến lập trình phản ứng thành một thứ khá đơn giản:\n\n- Bạn sẽ không cần tạo StreamControllers.\n- Bạn sẽ không cần tạo StreamBuilder cho mỗi biến.\n- Bạn sẽ không cần tạo một lớp (class) cho mỗi trạng thái.\n- Bạn sẽ không cần tạo get cho một giá trị ban đầu.\n- Bạn sẽ không cần sử dụng trình tạo mã.\n\nLập trình phản ứng với Get dễ dàng như sử dụng setState.\n\nHãy tưởng tượng rằng bạn có một biến tên và muốn rằng mỗi khi bạn thay đổi nó, tất cả các widget sử dụng nó sẽ được tự động thay đổi.\n\nĐây là biến đếm của bạn:\n\n```dart\nvar name = 'Jonatas Borges';\n```\n\nĐể nó có thể được lắng nghe, bạn chỉ cần thêm \".obs\" ở cuối:\n\n```dart\nvar name = 'Jonatas Borges'.obs;\n```\n\nVà trong UI, khi bạn muốn hiển thị giá trị đó và cập nhật màn hình bất cứ khi nào giá trị thay đổi, chỉ cần thực hiện điều này:\n\n```dart\nObx(() => Text(\"${controller.name}\"));\n```\n\nThế thôi. Chỉ là _thế_ thôi người ơi~.\n\n### Thêm thông tin về Quản lý state\n\n**Xem thông tin cụ thể tại [đây](./documentation/en_US/state_management.md). Tại đó, bạn có thể tham khảo ví dụ và so sánh sự khác nhau giữa quản lý state cơ bản và quản lý state reactive**\n\nBạn sẽ hình dung được sức mạnh của GetX.\n\n## Quản lý route\n\nNếu bạn chỉ sử dụng routes/snackbars/dialogs/bottomsheets không có context, GetX là lựa chọn số 2 trừ 1, nhìn đây:\n\nThêm \"Get\" trước MaterialApp, nó sẽ biến thành GetMaterialApp\n\n```dart\nGetMaterialApp( // Before: MaterialApp(\n  home: MyHome(),\n)\n```\n\nDi chuyển tới màn hình mới:\n\n```dart\n\nGet.to(NextScreen());\n```\n\nDi chuyển tới màn hình mới theo tên. Xem thêm tại [đây](./documentation/en_US/route_management.md#navigation-with-named-routes)\n\n```dart\n\nGet.toNamed('/details');\n```\n\nĐể đóng snackbars, dialogs, bottomsheets, hay bất kì thứ gì, bạn có thể xài cái này để thay Navigator.pop(context);\n\n```dart\nGet.back();\n```\n\nĐi đến màn hình kế tiếp và bỏ luôn màn hình cũ (thường dùng cho màn hình giới thiệu, màn hình đăng nhập, etc.)\n\n```dart\nGet.off(NextScreen());\n```\n\nĐi đến màn hình kế tiếp và đóng tất cả các routes (hữu dụng cho shopping cart, polls, và tests)\n\n```dart\nGet.offAll(NextScreen());\n```\n\nBạn có thấy nãy giờ chúng ta không sử dụng từ khóa \"context\"? Đây chính là thang điểm 9 + 1 của quản lý route ở Get. Với điểm mạnh trên, bạn có thể thao tác bất cứ đâu, kể cả trong controller class.\n\n### Thêm thông tin về quản lý route\n\n**Get hoạt động được với named routes và cũng cung cấp cách điều khiển ở cấp thấp (lower-level control) cho routes của bạn! Tài liệu chi tiết tại [đây](./documentation/en_US/route_management.md)**\n\n## Quản lý dependency\n\nGet hỗ trợ tính năng giúp bạn lấy class như Bloc hoặc Controller chỉ với 1 dòng, không cần Provider context hay InheritedWidget:\n\n```dart\nController controller = Get.put(Controller()); // Rather Controller controller = Controller();\n```\n\n- Chú ý: Nếu bạn dùng Get's State Manager, hãy chú ý đến việc bindings API, có thể giúp dễ dàng kết nối view đến controller.\n\nThay vì khởi tạo class của bạn trong class bạn đang sử dụng, bạn đang khởi tạo nó trong phiên bản Get, điều này sẽ làm cho nó có sẵn trên toàn bộ Ứng dụng của bạn.\nVì vậy, bạn có thể sử dụng bộ điều khiển (hoặc Bloc) của mình một cách bình thường\n\n**Mẹo:** quản lý dependency của Get được tách ra khỏi các phần khác của package, vì vậy, ví dụ: nếu ứng dụng của bạn đã sử dụng 1 trình quản lý trạng thái (bất kỳ cái nào, không quan trọng), bạn không cần phải viết lại tất cả, bạn có thể sử dụng nạp dependency của Get vô lo\n\n```dart\ncontroller.fetchApi();\n```\n\nHãy tưởng tượng rằng bạn đã điều hướng qua nhiều route và bạn cần dữ liệu bị còn sót trong controller của mình, bạn sẽ cần một trình quản lý dependency kết hợp với Provider hoặc Get_it, đúng không? Với Get, sử dụng Get để \"find\" cho controller, bạn sẽ hoàn toàn độc lập:\n\n```dart\nController controller = Get.find();\n//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.\n```\n\nVà sau đó, bạn sẽ có thể khôi phục dữ liệu controller của mình đã lấy được ở đó:\n\n```dart\nText(controller.textFromApi);\n```\n\n### Thêm thông tin về quản lý dependency\n\n**Xem thêm tại [đây](./documentation/en_US/dependency_management.md)**\n\n# Utils\n\n## Internationalization\n\n### Dịch thuật\n\nCác bản dịch được lưu giữ như một bản đồ từ điển (dictionary map) key-value đơn giản.\nĐể thêm các bản dịch tùy chỉnh, hãy tạo một class và kế thừa (extend) từ `Translation`.\n\n```dart\nimport 'package:get/get.dart';\n\nclass Messages extends Translations {\n  @override\n  Map<String, Map<String, String>> get keys => {\n        'en_US': {\n          'hello': 'Hello World',\n        },\n        'de_DE': {\n          'hello': 'Hallo Welt',\n        }\n      };\n}\n```\n\n#### Sử dụng bản dịch thuật\n\nChỉ cần thêm `.tr` vào key được chỉ định và nó sẽ được dịch, sử dụng giá trị hiện tại của` Get.locale` và `Get.fallbackLocale`.\n\n```dart\nText('title'.tr);\n```\n\n#### Sử dụng bản dịch thuật với số ít và số nhiều\n\n```dart\nvar products = [];\nText('singularKey'.trPlural('pluralKey', products.length, Args));\n```\n\n#### Sử dụng bản dịch với tham số (parameters)\n\n```dart\nimport 'package:get/get.dart';\n\n\nMap<String, Map<String, String>> get keys => {\n    'en_US': {\n        'logged_in': 'logged in as @name with email @email',\n    },\n    'es_ES': {\n       'logged_in': 'iniciado sesión como @name con e-mail @email',\n    }\n};\n\nText('logged_in'.trParams({\n  'name': 'Jhon',\n  'email': 'jhon@example.com'\n  }));\n```\n\n### Locales\n\nChuyển các tham số (parameters) cho `GetMaterialApp` để xác định ngôn ngữ và bản dịch.\n\n```dart\nreturn GetMaterialApp(\n    translations: Messages(), // your translations\n    locale: Locale('en', 'US'), // translations will be displayed in that locale\n    fallbackLocale: Locale('en', 'UK'), // specify the fallback locale in case an invalid locale is selected.\n);\n```\n\n#### Đổi locale\n\nGọi `Get.updateLocale (locale)` 'để cập nhật ngôn ngữ. Các bản dịch sau đó sẽ tự động sử dụng ngôn ngữ mới.\n\n```dart\nvar locale = Locale('en', 'US');\nGet.updateLocale(locale);\n```\n\n#### System locale\n\nĐể đọc system locale, sử dụng `Get.deviceLocale`.\n\n```dart\nreturn GetMaterialApp(\n    locale: Get.deviceLocale,\n);\n```\n\n## Đổi chủ đề (Theme)\n\nVui lòng không sử dụng bất kỳ Widget con nào cấp cao hơn `GetMaterialApp` để cập nhật nó. Điều này có thể kích hoạt các key trùng lặp. Rất nhiều người đã quen với cách tiếp cận thời tiền sử là tạo tiện ích \"ThemeProvider\" chỉ để thay đổi chủ đề ứng dụng của bạn và điều này KHÔNG cần thiết với ** GetX ™ **.\n\nBạn có thể tạo chủ đề tùy chỉnh của mình và chỉ cần thêm nó vào trong `Get.changeTheme` mà không cần bất kỳ điều gì khác:\n\n```dart\nGet.changeTheme(ThemeData.light());\n```\n\nNếu bạn muốn tạo một cái gì đó giống như một nút thay đổi Theme với `onTap`, bạn có thể kết hợp hai API ** GetX ™ ** cho điều đó:\n\n- Api kiểm tra xem `Theme` tối có đang được sử dụng hay không.\n- Và `Theme` sẽ thay đổi API, bạn sử dụng với `onPressed`:\n\n```dart\nGet.changeTheme(Get.isDarkMode? ThemeData.light(): ThemeData.dark());\n```\n\nKhi bật `.darkmode`, nó sẽ chuyển _light theme_, và khi bật _light theme_ , nó sẽ chuyển _dark theme_.\n\n## GetConnect\n\nGetConnect tạo giao thức tới http hoặc websockets\n\n### Cấu hình mặc định\n\nĐơn giản, bạn có thể kế thừa (extend) từ GetConnect và sử dụng các phương thức GET/POST/PUT/DELETE/SOCKET khi giao tiếp với Rest API hoặc websockets.\n\n```dart\nclass UserProvider extends GetConnect {\n  // Get request\n  Future<Response> getUser(int id) => get('http://youapi/users/$id');\n  // Post request\n  Future<Response> postUser(Map data) => post('http://youapi/users', body: data);\n  // Post request with File\n  Future<Response<CasesModel>> postCases(List<int> image) {\n    final form = FormData({\n      'file': MultipartFile(image, filename: 'avatar.png'),\n      'otherFile': MultipartFile(image, filename: 'cover.png'),\n    });\n    return post('http://youapi/users/upload', form);\n  }\n\n  GetSocket userMessages() {\n    return socket('https://yourapi/users/socket');\n  }\n}\n```\n\n### Cấu hình tùy chỉnh\n\nGetConnect có khả năng tùy chỉnh cao Bạn có thể xác định Url chính như answers, modifiers như request, xác địng authenticator và thậm chí số lần thử mà nó sẽ cố gắng authenticate, ngoài việc cung cấp khả năng xác định bộ giải mã chuẩn sẽ chuyển đổi tất cả các request của bạn thành Model mà không cần bất kỳ cấu hình bổ sung nào.\n\n```dart\nclass HomeProvider extends GetConnect {\n  @override\n  void onInit() {\n    // All request will pass to jsonEncode so CasesModel.fromJson()\n    httpClient.defaultDecoder = CasesModel.fromJson;\n    httpClient.baseUrl = 'https://api.covid19api.com';\n    // baseUrl = 'https://api.covid19api.com'; // It define baseUrl to\n    // Http and websockets if used with no [httpClient] instance\n\n    // It's will attach 'apikey' property on header from all requests\n    httpClient.addRequestModifier((request) {\n      request.headers['apikey'] = '12345678';\n      return request;\n    });\n\n    // Even if the server sends data from the country \"Brazil\",\n    // it will never be displayed to users, because you remove\n    // that data from the response, even before the response is delivered\n    httpClient.addResponseModifier<CasesModel>((request, response) {\n      CasesModel model = response.body;\n      if (model.countries.contains('Brazil')) {\n        model.countries.remove('Brazilll');\n      }\n    });\n\n    httpClient.addAuthenticator((request) async {\n      final response = await get(\"http://yourapi/token\");\n      final token = response.body['token'];\n      // Set the header\n      request.headers['Authorization'] = \"$token\";\n      return request;\n    });\n\n    //Autenticator will be called 3 times if HttpStatus is\n    //HttpStatus.unauthorized\n    httpClient.maxAuthRetries = 3;\n  }\n\n  @override\n  Future<Response<CasesModel>> getCases(String path) => get(path);\n}\n```\n\n## GetPage Middleware\n\nGetPage hiện có thuộc tính mới lấy danh sách GetMiddleWare và chạy chúng theo thứ tự cụ thể.\n\n**Chú ý**: Khi GetPage có Middleware (phần trung gian), tất cả các children của trang này sẽ tự động có cùng middlewares.\n\n### Ưu tiên\n\nThứ tự ưu tiên của Middlewares có thể đặt như sau trong GetMiddleware.\n\n```dart\nfinal middlewares = [\n  GetMiddleware(priority: 2),\n  GetMiddleware(priority: 5),\n  GetMiddleware(priority: 4),\n  GetMiddleware(priority: -8),\n];\n```\n\nvà chúng sẽ chạy như thế này **-8 => 2 => 4 => 5**\n\n### Chuyển hướng\n\nKhi bạn muốn tìm kiếm trang của route được gọi, function (hàm) sẽ khởi động. Kết quả là phải có RouteSettings để chuyển hướng đến. Hoặc cung cấp cho nó null và chuyển hướng không xảy ra.\n\n```dart\nRouteSettings redirect(String route) {\n  final authService = Get.find<AuthService>();\n  return authService.authed.value ? null : RouteSettings(name: '/login')\n}\n```\n\n### onPageCalled\n\nKhi bạn gọi một trang trước mọi thứ được tạo, hàm này sẽ khởi động và\nbạn có thể sử dụng nó để thay đổi điều gì đó về trang hoặc tạo cho nó một trang mới\n\n```dart\nGetPage onPageCalled(GetPage page) {\n  final authService = Get.find<AuthService>();\n  return page.copyWith(title: 'Welcome ${authService.UserName}');\n}\n```\n\n### OnBindingsStart\n\nHàm này sẽ khởi động ngay trước khi Bindings diễn ra và bạn có thể thay đổi Bindings cho trang này.\n\n```dart\nList<Bindings> onBindingsStart(List<Bindings> bindings) {\n  final authService = Get.find<AuthService>();\n  if (authService.isAdmin) {\n    bindings.add(AdminBinding());\n  }\n  return bindings;\n}\n```\n\n### OnPageBuildStart\n\nHàm này sẽ khởi động ngay sau khi Bindings diễn ra. Ở đây, bạn có thể làm thứ gì đó sau khi bạn tạo Bindings và trước khi tạo trang widget.\n\n```dart\nGetPageBuilder onPageBuildStart(GetPageBuilder page) {\n  print('bindings are ready');\n  return page;\n}\n```\n\n### OnPageBuilt\n\nHàm này sẽ khởi động ngay sau khi GetPage.page được gọi và sẽ cho bạn kết quả của hàm và lấy widget được hiển thị.\n\n### OnPageDispose\n\nFunction này sẽ khởi động ngay sau khi hủy bỏ tất cả các đối tượng liên quan (Controller, views, ...) của trang.\n\n## APIs nâng cao khác\n\n```dart\n// give the current args from currentScreen\nGet.arguments\n\n// give name of previous route\nGet.previousRoute\n\n// give the raw route to access for example, rawRoute.isFirst()\nGet.rawRoute\n\n// give access to Routing API from GetObserver\nGet.routing\n\n// check if snackbar is open\nGet.isSnackbarOpen\n\n// check if dialog is open\nGet.isDialogOpen\n\n// check if bottomsheet is open\nGet.isBottomSheetOpen\n\n// remove one route.\nGet.removeRoute()\n\n// back repeatedly until the predicate returns true.\nGet.until()\n\n// go to next route and remove all the previous routes until the predicate returns true.\nGet.offUntil()\n\n// go to next named route and remove all the previous routes until the predicate returns true.\nGet.offNamedUntil()\n\n//Check in what platform the app is running\nGetPlatform.isAndroid\nGetPlatform.isIOS\nGetPlatform.isMacOS\nGetPlatform.isWindows\nGetPlatform.isLinux\nGetPlatform.isFuchsia\n\n//Check the device type\nGetPlatform.isMobile\nGetPlatform.isDesktop\n//All platforms are supported independently in web!\n//You can tell if you are running inside a browser\n//on Windows, iOS, OSX, Android, etc.\nGetPlatform.isWeb\n\n\n// Equivalent to : MediaQuery.of(context).size.height,\n// but immutable.\nGet.height\nGet.width\n\n// Gives the current context of the Navigator.\nGet.context\n\n// Gives the context of the snackbar/dialog/bottomsheet in the foreground, anywhere in your code.\nGet.contextOverlay\n\n// Chí ú: Nếu bạn dùng cái này, nhớ đặtt. thànhnce you\n// have access to context in any place of your UI, you can use it anywhere in the UI code\n\n// If you need a changeable height/width (like Desktop or browser windows that can be scaled) you will need to use context.\ncontext.width\ncontext.height\n\n// Gives you the power to define half the screen, a third of it and so on.\n// Useful for responsive applications.\n// param dividedBy (double) optional - default: 1\n// param reducedBy (double) optional - default: 0\ncontext.heightTransformer()\ncontext.widthTransformer()\n\n/// Similar to MediaQuery.of(context).size\ncontext.mediaQuerySize()\n\n/// Similar to MediaQuery.of(context).padding\ncontext.mediaQueryPadding()\n\n/// Similar to MediaQuery.of(context).viewPadding\ncontext.mediaQueryViewPadding()\n\n/// Similar to MediaQuery.of(context).viewInsets;\ncontext.mediaQueryViewInsets()\n\n/// Similar to MediaQuery.of(context).orientation;\ncontext.orientation()\n\n/// Check if device is on landscape mode\ncontext.isLandscape()\n\n/// Check if device is on portrait mode\ncontext.isPortrait()\n\n/// Similar to MediaQuery.of(context).devicePixelRatio;\ncontext.devicePixelRatio()\n\n/// Similar to MediaQuery.of(context).textScaleFactor;\ncontext.textScaleFactor()\n\n/// Get the shortestSide from screen\ncontext.mediaQueryShortestSide()\n\n/// True if width be larger than 800\ncontext.showNavbar()\n\n/// True if the shortestSide is smaller than 600p\ncontext.isPhone()\n\n/// True if the shortestSide is largest than 600p\ncontext.isSmallTablet()\n\n/// True if the shortestSide is largest than 720p\ncontext.isLargeTablet()\n\n/// True if the current device is Tablet\ncontext.isTablet()\n\n/// Returns a value<T> according to the screen size\n/// can give value for:\n/// watch: if the shortestSide is smaller than 300\n/// mobile: if the shortestSide is smaller than 600\n/// tablet: if the shortestSide is smaller than 1200\n/// desktop: if width is largest than 1200\ncontext.responsiveValue<T>()\n```\n\n### Cấu hình thủ công và cài đặt chung tuỳ chọn\n\nGetMaterialApp configures everything for you, but if you want to configure Get manually.\n\n```dart\nMaterialApp(\n  navigatorKey: Get.key,\n  navigatorObservers: [GetObserver()],\n);\n```\n\nBạn cũng sẽ có thể dùng Middleware của riêng bạn trong `GetObserver`, điều này không ảnh hưởng những thứ khác.\n\n```dart\nMaterialApp(\n  navigatorKey: Get.key,\n  navigatorObservers: [\n    GetObserver(MiddleWare.observer) // Here\n  ],\n);\n```\n\nBạn có thể tạo _Global Settings_ cho `Get`. Chỉ cần thêm `Get.config` vào code của bạn trước khi đẩy (push) bất cứ route nào.\nHoặc làm nó trực tiếp trong `GetMaterialApp` của bạn.\n\n```dart\nGetMaterialApp(\n  enableLog: true,\n  defaultTransition: Transition.fade,\n  opaqueRoute: Get.isOpaqueRouteDefault,\n  popGesture: Get.isPopGestureEnable,\n  transitionDuration: Get.defaultDurationTransition,\n  defaultGlobalState: Get.defaultGlobalState,\n);\n\nGet.config(\n  enableLog = true,\n  defaultPopGesture = true,\n  defaultTransition = Transitions.cupertino\n)\n```\n\nBạn có thể tự chọn chuyển hướng tất cả logging messages từ `Get`.\nNếu bạn muốn sử dụng logging package ưa thích của riêng bạn, và muốn chụp lại những logs đó:\n\n```dart\nGetMaterialApp(\n  enableLog: true,\n  logWriterCallback: localLogWriter,\n);\n\nvoid localLogWriter(String text, {bool isError = false}) {\n  // pass the message to your favourite logging package here\n  // please note that even if enableLog: false log messages will be pushed in this callback\n  // you get check the flag if you want through GetConfig.isLogEnable\n}\n\n```\n\n### Local State Widgets\n\nCác Widget này cho phép bạn quản lý một giá trị duy nhất và giữ trạng thái tạm thời và cục bộ.\nChúng ta có các hướng đi cho Reactive và Simple.\nVí dụ: bạn có thể sử dụng chúng để chuyển đổi văn bản tối nghĩa trong một `TextField`, có thể tạo một widget\nExpandable Panel tùy chỉnh hoặc có thể sửa đổi chỉ mục hiện tại trong `BottomNavigationBar` trong khi thay đổi nội dung\nbên trong một `Scaffold`.\n\n#### ValueBuilder\n\nĐơn giản hóa của `StatefulWidget` hoạt động với lệnh gọi lại` .setState` nhận giá trị cập nhật.\n\n```dart\nValueBuilder<bool>(\n  initialValue: false,\n  builder: (value, updateFn) => Switch(\n    value: value,\n    onChanged: updateFn, // same signature! you could use ( newValue ) => updateFn( newValue )\n  ),\n  // if you need to call something outside the builder method.\n  onUpdate: (value) => print(\"Value updated: $value\"),\n  onDispose: () => print(\"Widget unmounted\"),\n),\n```\n\n#### ObxValue\n\nTương tự như [`ValueBuilder`](#valuebuilder), nhưng đây là phiên bản Reactive, bạn kèm một lệnh Rx (nhớ cái .obs không?) và nó cập nhật tự động ... hay chưa?\n\n```dart\nObxValue((data) => Switch(\n        value: data.value,\n        onChanged: data, // Rx has a _callable_ function! You could use (flag) => data.value = flag,\n    ),\n    false.obs,\n),\n```\n\n## Mẹo hữu ích\n\n`.obs` observable (variable có thể quan sát được) (còn được gọi là loại _Rx_) có nhiều phương thức và toán tử bên trong.\n\n> Is very common to _believe_ that a property with `.obs` **IS** the actual value... but make no mistake!\n> We avoid the Type declaration of the variable, because Dart's compiler is smart enough, and the code\n> looks cleaner, but:\n\n```dart\nvar message = 'Xin Chào'.obs;\nprint( 'Message \"$message\" has Type ${message.runtimeType}');\n```\n\nNgay cả khi `message` _prints_ giá trị String, thì kiểu của nó lại là ** RxString **!\n\nVì vậy, bạn không thể thực hiện `message.substring (0, 4) '. Bạn phải truy cập vào `value`thực bên trong _observable_: Cách được sử dụng nhiều nhất là`.value`, nhưng, bạn có biết rằng bạn cũng có thể sử dụng ...\n\n```dart\nfinal name = 'GetX'.obs;\n// only \"updates\" the stream, if the value is different from the current one.\nname.value = 'Hey';\n\n// All Rx properties are \"callable\" and returns the new value.\n// but this approach does not accepts `null`, the UI will not rebuild.\nname('Hello');\n\n// is like a getter, prints 'Hello'.\nname() ;\n\n/// numbers:\n\nfinal count = 0.obs;\n\n// You can use all non mutable operations from num primitives!\ncount + 1;\n\n// Watch out! this is only valid if `count` is not final, but var\ncount += 1;\n\n// You can also compare against values:\ncount > 2;\n\n/// booleans:\n\nfinal flag = false.obs;\n\n// switches the value between true/false\nflag.toggle();\n\n\n/// all types:\n\n// Sets the `value` to null.\nflag.nil();\n\n// All toString(), toJson() operations are passed down to the `value`\nprint( count ); // calls `toString()` inside  for RxInt\n\nfinal abc = [0,1,2].obs;\n// Converts the value to a json Array, prints RxList\n// Json is supported by all Rx types!\nprint('json: ${jsonEncode(abc)}, type: ${abc.runtimeType}');\n\n// RxMap, RxList and RxSet are special Rx types, that extends their native types.\n// but you can work with a List as a regular list, although is reactive!\nabc.add(12); // pushes 12 to the list, and UPDATES the stream.\nabc[3]; // like Lists, reads the index 3.\n\n\n// equality works with the Rx and the value, but hashCode is always taken from the value\nfinal number = 12.obs;\nprint( number == 12 ); // prints > true\n\n/// Custom Rx Models:\n\n// toJson(), toString() are deferred to the child, so you can implement override on them, and print() the observable directly.\n\nclass User {\n    String name, last;\n    int age;\n    User({this.name, this.last, this.age});\n\n    @override\n    String toString() => '$name $last, $age years old';\n}\n\nfinal user = User(name: 'Khang', last: 'Huỳnh', age: 33).obs;\n\n// `user` is \"reactive\", but the properties inside ARE NOT!\n// So, if we change some variable inside of it...\nuser.value.name = 'Kaiser';\n// The widget will not rebuild!,\n// `Rx` don't have any clue when you change something inside user.\n// So, for custom classes, we need to manually \"notify\" the change.\nuser.refresh();\n\n// or we can use the `update()` method!\nuser.update((value){\n  value.name='Kaiser';\n});\n\nprint( user );\n```\n\n## StateMixin\n\nMột cách khác để xử lý trạng thái `UI` của bạn là sử dụng`StateMixin <T>`.\nĐể triển khai nó, hãy sử dụng dấu `with` để thêm`StateMixin <T>` vào bộ điều khiển (controller) của bạn cho phép tích hợp kèm mô hình T.\n\n```dart\nclass Controller extends GetController with StateMixin<User>{}\n```\n\nPhương thức `change()` thay đổi trạng thái bất cứ khi nào chúng ta muốn.\nChỉ cần chuyển dữ liệu và trạng thái theo cách này:\n\n```dart\nchange(data, status: RxStatus.success());\n```\n\nRxStatus cho phép những trang thái này:\n\n```dart\nRxStatus.loading();\nRxStatus.success();\nRxStatus.empty();\nRxStatus.error('message');\n```\n\nĐể biểu hiện nó trên UI, sử dụng:\n\n```dart\nclass OtherClass extends GetView<Controller> {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n\n      body: controller.obx(\n        (state)=>Text(state.name),\n\n        // here you can put your custom loading indicator, but\n        // by default would be Center(child:CircularProgressIndicator())\n        onLoading: CustomLoadingIndicator(),\n        onEmpty: Text('No data found'),\n\n        // here also you can set your own error widget, but by\n        // default will be an Center(child:Text(error))\n        onError: (error)=>Text(error),\n      ),\n    );\n}\n```\n\n#### GetView\n\nWidget này là bảo bối của GetX, rất đơn giản, nhưng rất hữu ích!\n\nLà một Widget `const Stateless` có getter` controller` cho một `Controller` đã đăng ký, chỉ vậy thôi người ơi~.\n\n```dart\n class AwesomeController extends GetController {\n   final String title = 'My Awesome View';\n }\n\n  // ALWAYS remember to pass the `Type` you used to register your controller!\n class AwesomeView extends GetView<AwesomeController> {\n   @override\n   Widget build(BuildContext context) {\n     return Container(\n       padding: EdgeInsets.all(20),\n       child: Text(controller.title), // just call `controller.something`\n     );\n   }\n }\n```\n\n#### GetResponsiveView\n\nMở rộng tiện ích này để xây dựng chế độ responsive.\nWidget này chứa thuộc tính `screen` có tất cả\nthông tin về kích thước và loại màn hình.\n\n##### Hướng dẫn sử dụng trước khi dùng\n\nBạn có hai lựa chọn để xây dựng nó.\n\n- với phương thức `builder` bạn trả về tiện ích con để xây dựng.\n- với các phương thức `desktop`,` tablet`, `phone`,` watch`. cụ thể, các phương thức này sẽ tạo các loại màn hình khớp với ngữ cảnh khi màn hình là [ScreenType.Tablet] thì phương thức `tablet` sẽ được tạo ra và cứ như vậy.\n  **Chú ý:** Nếu bạn dùng cái này, nhớ đặt `alwaysUseBuilder` thành `false`\n\nVới thuộc tính `settings` bạn có thể đặt chiều dài tối thiểu cho các loại màn hình.\n\n![example](https://github.com/SchabanBo/get_page_example/blob/master/docs/Example.gif?raw=true)\nCode to this screen\n[code](https://github.com/SchabanBo/get_page_example/blob/master/lib/pages/responsive_example/responsive_view.dart)\n\n#### GetWidget\n\nHầu hết mọi người không biết gì về Widget này, hoặc hoàn toàn nhầm lẫn về cách sử dụng nó.\nTrường hợp sử dụng rất hiếm, nhưng rất cụ thể: Nó `caches` một Bộ điều khiển.\nBởi vì _cache_ không thể là một `const Stateless`.\n\n> Vậy khi nào mình cần cache bộ điều khiển (controller)?\n\nNếu sử dụng, bạn sẽ dùng cái này **GetX**: `Get.create()`.\n\n`Get.create(()=>Controller())` sẽ tạo một `Controller` với mỗi lần gọi `Get.find<Controller>()`,\n\nĐó là nơi mà `GetWidget` tỏa sáng ... chẳng hạn như bạn có thể sử dụng nó, để giữ một danh sách các mục Todo. Vì vậy, nếu widget được \"xây dựng lại\", nó sẽ giữ nguyên phiên bản controller.\n\n#### GetxService\n\nClass này giống như một `GetxController`, nó chia sẻ cùng một vòng đời (`onInit ()`,`onReady ()`,`onClose ()`).\nNhưng không có \"logic\" bên trong của nó. Nó chỉ thông báo cho ** GetX ** Hệ thống Nạp Dependency rằng class con này ** không thể ** bị xóa khỏi bộ nhớ.\n\nVì vậy, rất hữu ích để giữ cho \"Service\" của bạn luôn có thể truy cập và hoạt động với `Get.find ()`. Giống:\n`ApiService`,` StorageService`, `CacheService`.\n\n```dart\nFuture<void> main() async {\n  await initServices(); /// AWAIT SERVICES INITIALIZATION.\n  runApp(SomeApp());\n}\n\n/// Is a smart move to make your Services intiialize before you run the Flutter app.\n/// as you can control the execution flow (maybe you need to load some Theme configuration,\n/// apiKey, language defined by the User... so load SettingService before running ApiService.\n/// so GetMaterialApp() doesnt have to rebuild, and takes the values directly.\nvoid initServices() async {\n  print('starting services ...');\n  /// Here is where you put get_storage, hive, shared_pref initialization.\n  /// or moor connection, or whatever that's async.\n  await Get.putAsync(() => DbService().init());\n  await Get.putAsync(SettingsService()).init();\n  print('All services started...');\n}\n\nclass DbService extends GetxService {\n  Future<DbService> init() async {\n    print('$runtimeType delays 2 sec');\n    await 2.delay();\n    print('$runtimeType ready!');\n    return this;\n  }\n}\n\nclass SettingsService extends GetxService {\n  void init() async {\n    print('$runtimeType delays 1 sec');\n    await 1.delay();\n    print('$runtimeType ready!');\n  }\n}\n\n```\n\nCách duy nhất để thực sự xóa một `GetxService`, là với `Get.reset ()` giống như cách thức \"Khởi động nóng\" ứng dụng của bạn. Vì vậy, hãy nhớ rằng, nếu bạn cần sự tồn tại tuyệt đối của một class trong vòng đời tồn tại của nó trong ứng dụng của bạn, hãy sử dụng `GetxService`.\n\n# Thay đổi đột phá 2.0\n\n1- Rx types:\n\n| Before  | After      |\n| ------- | ---------- |\n| StringX | `RxString` |\n| IntX    | `RxInt`    |\n| MapX    | `RxMap`    |\n| ListX   | `RxList`   |\n| NumX    | `RxNum`    |\n| DoubleX | `RxDouble` |\n\nRxController và GetBuilder bây giờ đã hợp nhất, bạn không cần phải ghi nhớ bộ điều khiển nào bạn muốn sử dụng, chỉ cần sử dụng GetxController, nó sẽ hoạt động để quản lý trạng thái đơn giản và reactive.\n\n2- NamedRoutes\nBefore:\n\n```dart\nGetMaterialApp(\n  namedRoutes: {\n    '/': GetRoute(page: Home()),\n  }\n)\n```\n\nNow:\n\n```dart\nGetMaterialApp(\n  getPages: [\n    GetPage(name: '/', page: () => Home()),\n  ]\n)\n```\n\nTại sao lại thay đổi?\nThông thường, có thể cần phải quyết định trang nào sẽ được hiển thị từ một tham số hoặc mã thông báo đăng nhập, cách tiếp cận trước đây không linh hoạt, vì nó không cho phép điều này.\nViệc chèn trang vào một hàm đã làm giảm đáng kể mức tiêu thụ RAM, vì các tuyến sẽ không được cấp phát trong bộ nhớ kể từ khi ứng dụng được khởi động và nó cũng cho phép thực hiện kiểu tiếp cận này:\n\n```dart\n\nGetStorage box = GetStorage();\n\nGetMaterialApp(\n  getPages: [\n    GetPage(name: '/', page:(){\n      return box.hasData('token') ? Home() : Login();\n    })\n  ]\n)\n```\n\n# Tại sao lại dùng GetX\n\n1- Nhiều lần sau khi cập nhật Flutter, nhiều package của bạn sẽ bị hỏng. Đôi khi lỗi biên dịch code xảy ra, lỗi thường xuất hiện mà vẫn không có câu trả lời; và, chúng ta, nhà phát triển, cần biết lỗi đến từ đâu, theo dõi lỗi, chỉ sau đó cố gắng mở một vấn đề trong kho lưu trữ tương ứng và xem vấn đề của nó đã được giải quyết. Tập trung các tài nguyên chính để phát triển (Quản lý state, dependency và route), cho phép bạn thêm một gói duy nhất vào pubspec của mình và bắt đầu hoạt động. Sau khi cập nhật Flutter, điều duy nhất bạn cần làm là cập nhật Get dependency và bắt đầu làm việc. Get cũng giải quyết các vấn đề tương thích. Có bao nhiêu lần một phiên bản của một gói không tương thích với phiên bản của gói khác, vì một gói sử dụng phần phụ thuộc trong một phiên bản và gói kia trong phiên bản khác? Đây cũng không phải là vấn đề đáng lo ngại khi sử dụng Get, vì mọi thứ đều nằm trong cùng một gói và hoàn toàn tương thích.\n\n2- Flutter dễ học, Flutter siêu phàm, nhưng Flutter vẫn có một số bản soạn sẵn có thể không mong muốn đối với hầu hết các nhà phát triển, chẳng hạn như `Navigator.of (context) .push (context, builder [...] '. Get đơn giản hóa việc phát triển. Thay vì viết 8 dòng mã chỉ để gọi một tuyến đường, bạn chỉ cần làm điều đó: `` Get.to (Home ()) 'và bạn đã hoàn tất, bạn sẽ chuyển sang trang tiếp theo. Các url web động là một điều thực sự khó khăn để làm với Flutter hiện tại và điều đó với GetX đơn giản đến đần độn :). Quản lý trạng thái trong Flutter và quản lý các phần phụ thuộc cũng là điều tạo ra nhiều cuộc thảo luận, vì có hàng trăm mẫu trong pub (Dart package website). Nhưng không có gì dễ dàng bằng việc thêm \".obs\" ở cuối biến của bạn, và đặt tiện ích của bạn bên trong Obx, và thế là xong, tất cả các cập nhật cho biến đó sẽ được tự động cập nhật trên màn hình.\n\n3- Dễ dàng mà không phải lo lắng về hiệu suất. Hiệu suất của Flutter đã đáng kinh ngạc rồi, nhưng hãy tưởng tượng rằng bạn sử dụng trình quản lý state và trình định vị để phân phối các Blocs / stores / controllers / v.v. của bạn. Bạn sẽ phải gọi thủ công loại trừ sự phụ thuộc khi bạn không cần đến chúng. Nhưng bạn đã bao giờ nghĩ chỉ cần sử dụng bộ điều khiển của mình và khi nó không còn được ai sử dụng nữa, nó sẽ đơn giản được xóa khỏi bộ nhớ? Đó là những gì GetX làm. Với SmartManagement, mọi thứ không được sử dụng sẽ được xóa khỏi bộ nhớ và bạn không phải lo lắng về bất cứ điều gì ngoài lập trình. Bạn sẽ được đảm bảo rằng bạn đang sử dụng các nguồn tài nguyên cần thiết tối thiểu mà thậm chí không cần tạo ra một logic nào cho việc này.\n\n4- Tách khỏi thực tế. Bạn có thể đã nghe đến khái niệm \"tách khung nhìn (view) khỏi business logic\". Đây không phải là đặc thù của BLoC, MVC, MVVM và bất kỳ tiêu chuẩn nào khác trên thị trường đều có khái niệm này. Tuy nhiên, khái niệm này thường có thể được giảm thiểu trong Flutter do việc sử dụng ngữ cảnh (context).\nNếu bạn cần ngữ cảnh để tìm một InheritedWidget, bạn cần nó trong dạng xem hoặc chuyển ngữ cảnh theo tham số. Tôi đặc biệt thấy giải pháp này rất chán đời; hơn nữa, để làm việc theo nhóm, chúng tôi sẽ luôn phụ thuộc vào business logic của View. GetX không chính thống với cách tiếp cận tiêu chuẩn và mặc dù nó không cấm hoàn toàn việc sử dụng StatefulWidgets, InitState, v.v., nhưng nó luôn có một cách tiếp cận tương tự có thể rõ ràng hơn. Controller có vòng đời và khi bạn cần thực hiện yêu cầu APIREST chẳng hạn, bạn độc lập với View. Bạn có thể sử dụng onInit để bắt đầu cuộc gọi http và khi dữ liệu đến, các biến sẽ được điền. Vì GetX hoạt động hoàn toàn reactive (đó là sự thực và hoạt động theo luồng), khi các mục được lấp đầy, tất cả tiện ích con sử dụng biến đó sẽ được cập nhật tự động trong View. Điều này cho phép những người có chuyên môn về UI chỉ làm việc với các widget và không phải gửi bất kỳ thứ gì đến logic nghiệp vụ ngoài các sự kiện của người dùng (như nhấp vào nút), trong khi những người làm việc với logic nghiệp vụ sẽ được tự do tạo và kiểm tra logic nghiệp vụ riêng.\n\nThư viện này sẽ luôn được cập nhật và triển khai các tính năng mới. Hãy thoải mái đưa ra các bài PR và đóng góp cho chúng.\n\n# Cộng đồng\n\n## Kênh Cộng đồng\n\nGetX có một cộng đồng rất tích cực và hữu ích. Nếu bạn có thắc mắc hoặc muốn được hỗ trợ về việc sử dụng khuôn khổ này, vui lòng tham gia các kênh cộng đồng của chúng tôi, câu hỏi của bạn sẽ được trả lời nhanh hơn và đó sẽ là nơi phù hợp nhất. Kho lưu trữ này dành riêng cho các vấn đề mở và yêu cầu tài nguyên, nhưng hãy thoải mái trở thành một phần của Cộng đồng GetX.\n\n| **Slack**                                                                                                                   | **Discord**                                                                                                                 | **Telegram**                                                                                                          |\n| :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------- |\n| [![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) |\n\n## Cách cống hiến\n\n_Bạn muốn đóng góp cho dự án? Chúng tôi sẽ tự hào giới thiệu bạn với tư cách là một trong những cộng tác viên của chúng tôi. Dưới đây là một số điểm mà bạn có thể đóng góp và làm cho Get (và Flutter) tốt hơn nữa._\n\n- Giúp dịch readme sang các ngôn ngữ khác.\n- Thêm tài liệu vào readme (rất nhiều chức năng của Get chưa được tài liệu hóa).\n- Viết bài hoặc làm video dạy cách sử dụng Get (chúng sẽ được chèn vào Readme và trong tương lai trong Wiki của chúng tôi).\n- Đưa ra các PR cho mã / bài kiểm tra.\n- Bao gồm các chức năng mới.\n\nMọi đóng góp đều được hoan nghênh!\n\n## Các bài báo và video\n\n- [Flutter GetX EcoSystem package for arabic people](https://www.youtube.com/playlist?list=PLV1fXIAyjeuZ6M8m56zajMUwu4uE3-SL0) - Hướng dẫn bởi [Pesa Coder](https://github.com/UsamaElgendy).\n- [Dynamic Themes in 3 lines using GetX™](https://medium.com/swlh/flutter-dynamic-themes-in-3-lines-c3b375f292e3) - Hướng dẫn bởi [Rod Brown](https://github.com/RodBr).\n- [Complete GetX™ Navigation](https://www.youtube.com/watch?v=RaqPIoJSTtI) - Quản lý route bởi Amateur Coder.\n- [Complete GetX State Management](https://www.youtube.com/watch?v=CNpXbeI_slw) - Quản lý State video by Amateur Coder.\n- [GetX™ Other Features](https://youtu.be/ttQtlX_Q0eU) - Utils, storage, bindings and other features video by Amateur Coder.\n- [Firestore User with GetX | Todo App](https://www.youtube.com/watch?v=BiV0DcXgk58) - Video by Amateur Coder.\n- [Firebase Auth with GetX | Todo App](https://www.youtube.com/watch?v=-H-T_BSgfOE) - Video by Amateur Coder.\n- [The Flutter GetX™ Ecosystem ~ State Management](https://medium.com/flutter-community/the-flutter-getx-ecosystem-state-management-881c7235511d) - Quản lý State by [Aachman Garg](https://github.com/imaachman).\n- [The Flutter GetX™ Ecosystem ~ Dependency Injection](https://medium.com/flutter-community/the-flutter-getx-ecosystem-dependency-injection-8e763d0ec6b9) - Nạp dependency by [Aachman Garg](https://github.com/imaachman).\n- [GetX, the all-in-one Flutter package](https://www.youtube.com/watch?v=IYQgtu9TM74) - Giới thiệu sơ lược về quản lý State and Navigation by Thad Carnevalli.\n- [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.\n- [GetX Flutter Firebase Auth Example](https://medium.com/@jeffmcmorris/getx-flutter-firebase-auth-example-b383c1dd1de2) - Article by Jeff McMorris.\n- [Flutter State Management with GetX – Complete App](https://www.appwithflutter.com/flutter-state-management-with-getx/) - by App With Flutter.\n- [Flutter Routing with Animation using Get Package](https://www.appwithflutter.com/flutter-routing-using-get-package/) - by App With Flutter.\n- [A minimal example on dartpad](https://dartpad.dev/2b3d0d6f9d4e312c5fdbefc414c1727e?) - by [Roi Peker](https://github.com/roipeker)\n"
  },
  {
    "path": "README.id-ID.md",
    "content": "![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png)\n\n**Bahasa: Indonesia (file ini), [Inggris](README.md), [Orang Vietnam](README-vi.md), [Urdu](README.ur-PK.md), [China](README.zh-cn.md), [Portugis (Brazil)](README.pt-br.md), [Spanyol](README-es.md), [Russia](README.ru.md), [Polandia](README.pl.md), [Korea](README.ko-kr.md), [French](README-fr.md)**\n\n[![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)\n[![popularity](https://badges.bar/get/popularity)](https://pub.dev/packages/sentry/score)\n[![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)\n[![pub points](https://badges.bar/get/pub%20points)](https://pub.dev/packages/get/score)\n![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)\n[![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart)\n[![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N)\n[![Get on Slack](https://img.shields.io/badge/slack-join-orange.svg)](https://communityinviter.com/apps/getxworkspace/getx)\n[![Telegram](https://img.shields.io/badge/chat-on%20Telegram-blue.svg)](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g)\n<a href=\"https://github.com/Solido/awesome-flutter\">\n<img alt=\"Awesome Flutter\" src=\"https://img.shields.io/badge/Awesome-Flutter-blue.svg?longCache=true&style=flat-square\" />\n</a>\n<a href=\"https://www.buymeacoffee.com/jonataslaw\" target=\"_blank\"><img src=\"https://i.imgur.com/aV6DDA7.png\" alt=\"Buy Me A Coffee\" style=\"height: 41px !important;width: 174px !important; box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;\" > </a>\n\n![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/getx.png)\n\n- [Tentang Get](#tentang-get)\n- [Instalasi](#instalasi)\n- [Aplikasi Counter menggunakan GetX](#aplikasi-counter-menggunakan-getx)\n- [Tiga Pilar](#tiga-pilar)\n  - [State management](#state-management)\n    - [Reactive State Manager](#reactive-state-manager)\n    - [Detail lebih lanjut mengenai state management](#detail-lebih-lanjut-mengenai-state-management)\n  - [Route management](#route-management)\n    - [Detail lebih lanjut mengenai route management](#detail-lebih-lanjut-mengenai-route-management)\n  - [Dependency management](#dependency-management)\n    - [Detail lebih lanjut mengenai dependency management](#detail-lebih-lanjut-mengenai-dependency-management)\n- [Utilitas](#utilitas)\n  - [Internasionalisasi](#internasionalisasi)\n    - [Translasi](#translasi)\n      - [Menggunakan Translasi](#menggunakan-translasi)\n    - [Lokalisasi](#lokalisasi)\n      - [Mengubah Lokal](#mengubah-lokal)\n      - [Lokal Sistem](#lokal-sistem)\n  - [Mengubah Tema](#mengubah-tema)\n  - [GetConnect](#getconnect)\n    - [Konfigurasi Default](#konfigurasi-default)\n    - [Konfigurasi Kustom](#konfigurasi-kustom)\n  - [GetPage Middleware](#getpage-middleware)\n    - [Prioritas](#prioritas)\n    - [Redirect](#redirect)\n    - [OnPageCalled](#onpagecalled)\n    - [OnBindingsStart](#onbindingsstart)\n    - [OnPageBuildStart](#onpagebuildstart)\n    - [OnPageBuilt](#onpagebuilt)\n    - [OnPageDispose](#onpagedispose)\n  - [API Lanjutan Lainnya](#api-lanjutan-lainnya)\n    - [Pengaturan Global Opsional dan Konfigurasi Manual](#pengaturan-global-opsional-dan-konfigurasi-manual)\n    - [Local State Widgets](#local-state-widgets)\n      - [ValueBuilder](#valuebuilder)\n      - [ObxValue](#obxvalue)\n  - [Tips berguna](#tips-berguna)\n      - [GetView](#getview)\n      - [GetResponsiveView](#getresponsiveview)\n        - [Cara pakai](#cara-pakai)\n      - [GetWidget](#getwidget)\n      - [GetxService](#getxservice)\n- [Breaking change dari 2.0](#breaking-change-dari-20)\n- [Mengapa Getx?](#mengapa-getx)\n- [Komunitas](#komunitas)\n  - [Channel Komunitas](#kanal-komunitas)\n  - [Cara berkontribusi](#cara-berkontribusi)\n  - [Artikel dan Video](#artikel-dan-video)\n\n# Tentang Get\n\n- GetX adalah solusi ekstra-ringan dan powerful untuk Flutter. Ini mengkombinasikan state management dengan performa tinggi, injeksi dependensi yang cerdas, dan route management secara singkat dan praktis.\n\n- GetX memiliki 3 prinsip dasar, yang menjadi prioritas untuk semua resource yang ada di dalamnya: **PRODUKTIFITAS, PERFORMA DAN ORGANISASI**\n\n  - **PERFORMA:** GetX fokus pada performa dan konsumsi resource minimum. GetX tidak menggunakan Stream atau ChangeNotifier.\n\n  - **PRODUKTIFITAS:** GetX menggunakan sintaks yang mudah dan nyaman. Tidak peduli apa yang akan anda lakukan, akan selalu ada cara yang lebih mudah dengan GetX. Ini akan menghemat waktu development, dan meng-ekstrak performa maksimum pada aplikasi anda.\n  Umumnya, developer akan selalu berhubungan dengan penghapusan controller dari memori. Dengan GetX, ini tidak diperlukan, karena resource akan dihapus dari memori secara default ketika tidak digunakan. Jika anda ingin menyimpannnya kedalam memori, anda harus secara eksplisit mendeklarasikan \"permanent: true\" pada dependensi anda. Dengan begitu, selain menghemat waktu, anda juga mengurangi resiko memiliki dependensi yang tidak diperlukan dalam memori. Pemuatan dependensi juga bersifat \"lazy\" secara default.\n\n  - **ORGANISASI:** GetX memungkinkan pemisahan View, Presentation Logic, Business Logic, Dependency Injection, dan Navigasi.\n  Anda tidak perlu konteks untuk berpindah antar halaman. Jadi, anda tidak lagi bergantung pada widget tree (visualisasi) untuk hal ini. Anda tidak perlu konteks untuk mengakses controller/bloc melalui InheritedWidget. Dengan ini, anda benar benar memisahkan presentation logic dan business logic dari lapisan visual. Anda tidak perlu menginjeksi kelas Controller/Model/Bloc kedalam widget tree melalui multiprovider, untuk hal ini GetX menggunakan fitur dependency injection nya sendiri, memisahkan DI dari View secara total.\n  Dengan GetX, anda tahu dimana harus mencari setiap fitur dalam aplikasi anda, memiliki kode yang bersih secara default. Ini selain untuk memfasilitasi maintenance, membuat pembagian modul, sesuatu yang hingga saat itu di Flutter tidak terpikirkan, sesuatu yang sangat mungkin.\n  BLoC adalah permulaan awal dalam meng-organisir kode di Flutter, ini memisahkan business logic dari visualisasi. GetX adalah evolusi natural dari ini, tidak hanya memisahkan business logic, tapi juga presentation logic. Injeksi dependensi dan route juga dipisahkan sebagai bonus, dan lapisan data benar-benar terpisah secara menyeluruh. Anda tahu dimana semuanya berada, dan segalanya dengan cara yang lebih mudah daripada membuat sebuah hello world.\n  GetX adalah cara termudah, praktis, dan scalable untuk membangun aplikasi dengan performa tinggi menggunakan Flutter SDK, dengan ekosistem besar di sekelilingnya yang bekerjasama secara sempurna, mudah dipahami untuk pemula, dan akurat untuk ahli. Aman, stabil, up-to-date, dan menawarkan banyak cakupan build-in API yang tidak tersedia di dalam default Flutter SDK.\n\n- GetX tidak \"bloated\". Dirinya memiliki banyak fitur yang memungkinkan anda memulai programming tanpa mengkhawatirkan apapun, namun setiap fiturnya terletak didalam kontainer terpisah, dan hanya dimulai setelah digunakan. Jika anda hanya menggunakan State Management, hanya State Management yang akan di-compile. Jika anda hanya menggunakan routes, state management tidak akan di-compile.\n\n- GetX memiliki ekosistem yang besar, komunitas yang juga besar, banyak kolaborator, dan akan di maintenance selama Flutter ada. GetX juga mampu berjalan dengan kode yang sama di Android, iOS, Web, Mac, Linux, Windows, dan server anda.\n**Juga memungkinkan untuk me-reuse kode yang dibuat di frontend ke backend dengan [Get Server](https://github.com/jonataslaw/get_server)**.\n\n**Selain itu, seluruh proses development bisa di automasi secara menyeluruh, untuk keduanya (server dan frontend) menggunakan [Get CLI](https://github.com/jonataslaw/get_cli)**.\n\n**Selain itu, untuk lebih meningkatkan produktifitas anda, kami memiliki [ekstensi untuk VSCode](https://marketplace.visualstudio.com/items?itemName=get-snippets.get-snippets) dan [ekstensi untuk Android Studio/Intellij](https://plugins.jetbrains.com/plugin/14975-getx-snippets)**\n\n# Instalasi\n\nTambahkan Get kedalam file `pubspec.yaml` anda:\n\n```yaml\ndependencies:\n  get:\n```\n\nImport get didalam file dimana get akan digunakan:\n\n```dart\nimport 'package:get/get.dart';\n```\n\n# Aplikasi Counter menggunakan GetX\n\nProyek \"counter\" yang dibuat secara default ketika membuat proyek Flutter memiliki lebih dari 100 baris (termasuk comment). Untuk menunjukkan kekuatan Get, kami akan mendemonstrasikan bagaimana cara membuat \"counter\" yang mengubah state setiap klik, berpindah, dan berbagi state antar halaman, semua dalam cara yang terorganisir, memisahkan business logic dari view, dalam HANYA 26 BARIS KODE TERMASUK COMMENT.\n\n- Langkah 1:\n  Tambahkan \"Get\" sebelum MaterialApp, mengubahnya menjadi GetMaterialApp\n\n```dart\nvoid main() => runApp(GetMaterialApp(home: Home()));\n```\n\n- Catatan: ini tidak mengubah MaterialApp bawaan Flutter, GetMaterialApp bukan sebuah MaterialApp yang dimodifikasi, itu hanyalah sebuah Widget yang telah dikonfigurasi sebelumnya, yang mana memiliki default MaterialApp sebagai child. Anda bisa mengkonfigurasinya secara manual, namun hal itu benar-benar tidak diperlukan. GetMaterialApp akan membuat route, menginjeksinya, menginjeksi translasi/terjemahan, dan semua yang anda butuhkan untuk navigasi route. Jika anda hanya menggunakan Get untuk manajemen state atau manajemen dependensi, tidak perlu menggunakan GetMaterialApp. GetMaterialApp diperlukan untuk route, snackbar, internasionalisasi/terjemahan, bottomSheet, dialog, dan high-level API yang berhubungan dengan route dan ketiadaan konteks.\n\n- Catatan²: Langkah ini hanya diperlukan jika anda akan menggunakan manajemen route (`Get.to()`, `Get.back()` dan seterusnya). Jika anda tidak menggunakannya, langkah 1 tidak diperlukan.\n\n- Langkah 2:\n  Buat file baru untuk business logic dan taruh semua variabel, metode, dan kontroler didalamnya.\n  Anda bisa membuat variabel apapun menjadi \"observable\" menggunakan notasi tambahan \".obs\".\n\n```dart\nclass Controller extends GetxController{\n  var count = 0.obs;\n  increment() => count++;\n}\n```\n\n- Langkah 3:\n  Buat file baru untuk View, gunakan StatelessWidget dan hemat penggunaan RAM, dengan Get, anda mungkin tidak perlu lagi menggunakan StatefulWidget.\n\n```dart\nclass Home extends StatelessWidget {\n\n  @override\n  Widget build(context) {\n\n    // Instansiasi kelas anda menggunakan Get.put() untuk membuatnya tersedia untuk seluruh \"child\" route dibawahnya.    \n    final Controller c = Get.put(Controller());\n\n    return Scaffold(\n      // Gunakan Obx(() => ...) untuk mengupdate Text() ketika `count` berubah.\n      appBar: AppBar(title: Obx(() => Text(\"Clicks: ${c.count}\"))),\n\n      // Ganti 8 baris Navigator.push menggunan Get.to() agar lebih sederhana. Anda tidak perlu `context`.\n      body: Center(child: ElevatedButton(\n              child: Text(\"Go to Other\"), onPressed: () => Get.to(Other()))),\n      floatingActionButton:\n          FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment));\n  }\n}\n\nclass Other extends StatelessWidget {\n  // Anda bisa meminta Get untuk menemukan kontroler yang digunakan di halaman lain dan redirect ke halaman itu.\n  final Controller c = Get.find();\n\n  @override\n  Widget build(context){\n     // Akses variabel `count` yang telah di update.\n     return Scaffold(body: Center(child: Text(\"${c.count}\")));\n  }\n}\n```\n\nHasil:\n\n![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/counter-app-gif.gif)\n\nIni adalah proyek sederhana, namun sudah membuatnya terlihat jelas betapa powerful kemampuan yang dimiliki Get. Sepanjang proyek anda berkembang, perbedaan ini akan menjadi lebih signifikan.\n\nGet di desain untuk bekerja dalam tim, namun juga memudahkan pekerjaan untuk developer perseorangan dan membuatnya menjadi lebih sederhana.\n\nTingkatkan deadline anda, antarkan semuanya tanpa kehilangan performa. Get bukan untuk semua orang, namun jika anda tersinggung dengan frasa tersebut, Get cocok untukmu!\n\n# Tiga Pilar\n\n## State management\n\nGet memiliki dua state manager berbeda: Simple state manager (kami menyebutnya GetBuilder) dan Reactive state manager (GetX/Obx)\n\n### Reactive State Manager\n\nReactive programming bisa meng-alienasi banya orang karena katanya, sulit dimengerti. GetX mengubah reactive programming menjadi sesuatu yang cukup sederhana:\n\n- Anda tidak perlu membuat StreamController.\n- Anda tidak perlu membuat StreamBuilder untuk setiap variabel.\n- Anda tidak perlu membuat kelas untuk setiap state.\n- Anda tidak perlu membuat get untuk sebuah value awal (initial value).\n- Anda tidak perlu menggunakan generator kode.\n\nReactive programming dengan Get semudah menggunakan setState.\n\nBayangkan anda memiliki variabel nama, dan setiap kali anda mengubahnya, semua widget yang menggunakannya akan berubah secara otomatis.\n\nIni variabel count anda:\n\n```dart\nvar name = 'Jonatas Borges';\n```\n\nUntuk membuatnya \"observable\", anda hanya perlu menambahkan \".obs\" di belakangnya:\n\n```dart\nvar name = 'Jonatas Borges'.obs;\n```\n\nDan didalam UI, ketika anda ingin menampilkan value dan update tampilan ketika value itu berubah, cukup lakukan ini:\n\n```dart\nObx(() => Text(\"${controller.name}\"));\n```\n\nSelesai! _Sesederhana_ itu.\n\n### Detail lebih lanjut mengenai state management\n\n**Baca penjelasan lebih lanjut tentang state management [disini](./documentation/id_ID/state_management.md). Disana anda akan melihat contoh lebih banyak dan juga perbedaan diantara simple state manager dengan reactive state manager**\n\nAnda akan mendapatkan pemahaman yang baik tentang kekuatan dari GetX.\n\n## Route management\n\nJika anda ingin menggunakan routes/snackbars/dialogs/bottomsheets tanpa context, GetX luar biasa cocok untuk anda, lihat ini:\n\nTambahkan \"Get\" sebelum MaterialApp, mengubahnya menjadi GetMaterialApp\n\n```dart\nGetMaterialApp( // Sebelumnya: MaterialApp(\n  home: MyHome(),\n)\n```\n\nPindah ke halaman baru:\n\n```dart\n\nGet.to(NextScreen());\n```\n\nPindah ke halaman baru menggunakan nama. Baca detail lebih lanjut tentang penamaan route [disini](./documentation/id_ID/route_management.md#navigation-with-named-routes)\n\n```dart\n\nGet.toNamed('/details');\n```\n\nUntuk menutup snackbar, dialog, bottomsheet, atau apapun yang normalnya anda tutup menggunakan Navigator.pop(context);\n\n```dart\nGet.back();\n```\n\nUntuk pergi ke halaman baru dan mencegah user kembali ke halaman sebelumnya (biasanya digunakan untuk SplashScreen, LoginScreen, dsb).\n\n```dart\nGet.off(NextScreen());\n```\n\nUntuk pergi ke halaman baru dan batalkan navigasi sebelumnya (berguna untuk shopping cart, polls, dan test).\n\n```dart\nGet.offAll(NextScreen());\n```\n\nSadarkah bahwa anda tidak menggunakan context sama sekali untuk hal tersebut? Itu adalah keuntungan terbesar dalam menggunakan Get route management. Dengan ini, anda bisa mengeksekusi semua metode dari controller, tanpa ragu.\n\n### Detail lebih lanjut mengenai route management\n\n**Get bekerja dengan named route dan juga menawarkan kontrol dengan level yang lebih rendah untuk navigasimu! Dokumentasinya ada [disini](./documentation/id_ID/route_management.md)**\n\n## Dependency management\n\nGet memiliki dependency manager sederhana dan powerful yang memungkinkan anda mendapatkan kelas yang setara dengan Bloc atau Controller hanya dengan 1 baris kode, tanpa Provider context, tanpa inheritedWidget:\n\n```dart\nController controller = Get.put(Controller());\n```\n\n- Catatan: Jika anda menggunakan State Manager milik Get, harap untuk lebih memperhatikan [Bindings](./documentation/id_ID/dependency_management.md#bindings) api, yang mana akan membuat pengkoneksian View terhadap Controller jadi lebih mudah.\n\nDaripada menginstansiasi kelas anda didalam kelas yang anda gunakan, cukup lakukan hal itu di dalam Get instance, ini akan membuatnya tersedia di semua tempat di Aplikasimu. Jadi anda bisa menggunakan controller (atau class Bloc) secara normal.\n\n**Tips:** Dependency Management Get terpisah dari bagian lain dari package, jadi jika sebagai contoh aplikasi anda sudah menggunakan state manager (tidak peduli apapun itu), anda tidak perlu menulis ulang sama sekali, anda bisa menggunakan dependency injection tanpa masalah.\n\n```dart\ncontroller.fetchApi();\n```\n\nBayangkan anda bernavigasi melewati route yang sangat banyak, dan anda membutuhkan data yang tertinggal didalam controller jauh di belakang route sebelumnya, anda akan butuh state manager dikombinasikan dengan Provider atau Get_it, benar kan? Tidak dengan Get. Anda hanya perlu meminta Get untuk \"menemukan\" controllernya, anda tidak perlu dependensi tambahan:\n\n```dart\nController controller = Get.find();\n// Ya, terlihat seperti Sulap, Get akan menemukan controller anda, dan akan mengantarkannya ke lokasi anda.\n// Anda bisa memiliki 1 juta controller terinisialisasi, Get akan selalu memberimu controller yang tepat.\n```\n\nDan setelahnya anda bisa memperoleh data yang tertinggal sebelumnya:\n\n```dart\nText(controller.textFromApi);\n```\n\n### Detail lebih lanjut mengenai dependency management\n\n**Baca penjelasan lebih lanjut tentang dependency management [disini](./documentation/id_ID/dependency_management.md)**\n\n# Utilitas\n\n## Internasionalisasi\n\n### Translasi\n\nTranslasi disimpan sebagai key-value map sederhana.\nUntuk menambahkan translasi kustom, buat sebuah kelas dan extend `Translations`.\n\n```dart\nimport 'package:get/get.dart';\n\nclass Messages extends Translations {\n  @override\n  Map<String, Map<String, String>> get keys => {\n        'en_US': {\n          'hello': 'Hello World',\n        },\n        'id_ID': {\n          'hello': 'Halo Dunia',\n        }\n      };\n}\n```\n\n#### Menggunakan Translasi\n\nCukup tambahkan `.tr` setelah key yang disebutkan dan value nya akan diterjemahkan, menggunakan value awal dari `Get.locale` dan `Get.fallbackLocale`.\n\n```dart\nText('title'.tr);\n```\n\n### Lokalisasi\n\nBerikan parameter ke `GetMaterialApp` untuk mendefinisikan lokal dan translasi.\n\n```dart\nreturn GetMaterialApp(\n    translations: Messages(), // gunakan translasi yang anda buat\n    locale: Locale('id', 'ID'), // translasi akan ditampilkan di lokal ini\n    fallbackLocale: Locale('en', 'US'), // berikan lokal penumpu untuk berjaga-jaga jika lokal yang tidak valid dipilih\n);\n```\n\n#### Mengubah Lokal\n\nPanggil `Get.updateLocale(locale)` untuk memperbarui lokal. Setelahnya, translasi akan menggunakan lokal baru.\n\n```dart\nvar locale = Locale('en', 'US');\nGet.updateLocale(locale);\n```\n\n#### Lokal Sistem\n\nUntuk membaca lokal sistem, anda bisa menggunakan `Get.deviceLocale`.\n\n```dart\nreturn GetMaterialApp(\n    locale: Get.deviceLocale,\n);\n```\n\n## Mengubah Tema\n\nHarap untuk tidak menggunakan widget dengan level lebih tinggi daripada `GetMaterialApp` untuk memperbaruinya. Ini akan menyebabkan \"duplicate keys\". Banyak orang terbiasa menggunakan cara lama untuk membuat sebuah \"ThemeProvider\" widget hanya untuk mengubah tema aplikasi anda, dan ini tentu saja TIDAK diperlukan dengan **GetX™**.\n\nAnda bisa membuat tema kustom anda sendiri dan cukup menambahkannya kedalam `Get.changeTheme` tanpa boilerplate:\n\n```dart\nGet.changeTheme(ThemeData.light());\n```\n\nJika anda ingin membuat sesuatu seperti tombol yang mengubah Tema ketika `onPressed`, anda bisa mengkombinasikan dua **GetX™** API:\n\n- API yang melakukan pengecekan terhadap tema gelap `Get.isDarkMode`.\n- Dan API pengubah tema `Get.changeTheme`, anda cukup meletakannya didalam `onPressed`:\n\n```dart\nGet.changeTheme(Get.isDarkMode? ThemeData.light(): ThemeData.dark());\n```\n\nKetika `.darkmode` aktif, ini akan mengubah aplikasi anda ke _light theme_, dan sebaliknya, jika _light theme_ sedang aktif, ini akan mengubah aplikasi anda ke _dark theme_.\n\n## GetConnect\n\nGetConnect adalah cara mudah untuk berkomunikasi dari backend ke frontend menggunakan http atau websocket.\n\n### Konfigurasi Default\n\nAnda bisa secara sederhana meng-extend GetConnect dan menggunakan GET/POST/PUT/DELETE/SOCKET untuk berkomunikasi dengan REST API atau Websocket anda.\n\n```dart\nclass UserProvider extends GetConnect {\n  // Get request\n  Future<Response> getUser(int id) => get('http://youapi/users/$id');\n  // Post request\n  Future<Response> postUser(Map data) => post('http://youapi/users', body: data);\n  // Post request dengan File\n  Future<Response<CasesModel>> postCases(List<int> image) {\n    final form = FormData({\n      'file': MultipartFile(image, filename: 'avatar.png'),\n      'otherFile': MultipartFile(image, filename: 'cover.png'),\n    });\n    return post('http://youapi/users/upload', form);\n  }\n\n  GetSocket userMessages() {\n    return socket('https://yourapi/users/socket');\n  }\n}\n```\n\n### Konfigurasi Kustom\n\nGetConnect sangat bisa di disesuaikan, anda bisa mendefinisikan base URL, Response Modifier, Request Modifier, Authenticator, dan bahkan jumlah percobaan akses ulang (retry) yang mana akan mencoba meng-autentikasi dirinya sendiri, sebagai tambahan, anda juga bisa mendefinisikan dekoder standar yang akan mengubah seluruh request kedalam Model anda tanpa konfigurasi tambahan.\n\n```dart\nclass HomeProvider extends GetConnect {\n  @override\n  void onInit() {\n    // Semua request akan melewati jsonEncode, jadi, CasesModel.fromJson()\n    httpClient.defaultDecoder = CasesModel.fromJson;\n    httpClient.baseUrl = 'https://api.covid19api.com';\n    // baseUrl = 'https://api.covid19api.com'; // Ini akan men-setting baseUrl ke\n    // Http dan websocket jika digunakan tanpa [httpClient]\n\n    // Ini akan mengaitkan properti 'apikey' kedalam header dari semua request.\n    httpClient.addRequestModifier((request) {\n      request.headers['apikey'] = '12345678';\n      return request;\n    });\n\n    // Bahkan jika server mengirim data dari negara \"Brazil\"\n    // itu tidak akan pernah ditampilkan ke user, karena anda menghapus\n    // data tersebut sebelum response, bahkan sebelum response diantarkan.\n    httpClient.addResponseModifier<CasesModel>((request, response) {\n      CasesModel model = response.body;\n      if (model.countries.contains('Brazil')) {\n        model.countries.remove('Brazilll');\n      }\n    });\n\n    httpClient.addAuthenticator((request) async {\n      final response = await get(\"http://yourapi/token\");\n      final token = response.body['token'];\n      // Sesuaikan header\n      request.headers['Authorization'] = \"$token\";\n      return request;\n    });\n\n    // Authenticator akan dipanggil 3 kali jika\n    // HttpStatus == HttpStatus.unauthorized\n    httpClient.maxAuthRetries = 3;\n  }\n  }\n\n  @override\n  Future<Response<CasesModel>> getCases(String path) => get(path);\n}\n```\n\n## GetPage Middleware\n\nGetPage sekarang memiliki properti baru yang menerima list GetMiddleware dan menjalankannya dalam urutan spesifik.\n\n**Catatan**: Ketika GetPage memiliki middleware, seluruh child dari halaman tersebut akan secara otomatis memiliki middleware yang sama.\n\n### Prioritas\n\nUrutan dari Middleware yang akan dijalankan bisa diatur berdasarkan prioritas didalam GetMiddleware.\n\n```dart\nfinal middlewares = [\n  GetMiddleware(priority: 2),\n  GetMiddleware(priority: 5),\n  GetMiddleware(priority: 4),\n  GetMiddleware(priority: -8),\n];\n```\n\nmiddleware diatas akan dijalankan dengan urutan sebagai berikut **-8 => 2 => 4 => 5**\n\n### Redirect\n\nFungsi ini akan terpanggil ketika halaman dari route yang dipanggil sedang dicari. RouteSettings diperlukan untuk mengatur tujuan dari fungsi redirect. Atau berikan null jika tidak ingin ada redirect.\n\n```dart\nRouteSettings redirect(String route) {\n  final authService = Get.find<AuthService>();\n  return authService.authed.value ? null : RouteSettings(name: '/login')\n}\n```\n\n### OnPageCalled\n\nFungsi ini akan terpanggil ketika halaman yang dituju dipanggil sebelum apapun dibuat,\nanda bisa menggunakannya untuk mengubah sesuatu tentang halaman tersebut atau\nberikan halaman baru.\n\n```dart\nGetPage onPageCalled(GetPage page) {\n  final authService = Get.find<AuthService>();\n  return page.copyWith(title: 'Welcome ${authService.UserName}');\n}\n```\n\n### OnBindingsStart\n\nFungsi ini akan terpanggil tepat sebelum Binding ter-inisialisasi.\nDisini anda bisa mengubah Binding untuk halaman yang dituju.\n\n```dart\nList<Bindings> onBindingsStart(List<Bindings> bindings) {\n  final authService = Get.find<AuthService>();\n  if (authService.isAdmin) {\n    bindings.add(AdminBinding());\n  }\n  return bindings;\n}\n```\n\n### OnPageBuildStart\n\nFungsi ini akan terpanggil tepat setelah Binding ter-inisialisasi.\nDisini anda bisa melakukan sesuatu sebelum halaman yang dituju dibuat.\n\n```dart\nGetPageBuilder onPageBuildStart(GetPageBuilder page) {\n  print('bindings are ready');\n  return page;\n}\n```\n\n### OnPageBuilt\n\nFungsi ini akan terpanggil tepat setelah fungsi `GetPage.page` terpanggil dan akan memberikan anda hasil dari fungsinya. Dan mengambil widget yang akan ditampilkan.\n\n### OnPageDispose\n\nFungsi ini akan terpanggil tepat setelah semua objek yang berhubungan (Controller, Views, ...) ter-dispose dari halaman.\n\n## API Lanjutan Lainnya\n\n```dart\n// memberikan argument dari halaman yang sedang ditampilkan\nGet.arguments\n\n// memberikan nama dari route sebelumnya\nGet.previousRoute\n\n// memberikan akses raw route, contoh: rawRoute.isFirst()\nGet.rawRoute\n\n// memberikan akses terhadap Routing API dari GetObserver\nGet.routing\n\n// cek apakah snackbar sedang tampil\nGet.isSnackbarOpen\n\n// cek apakah dialog sedang tampil\nGet.isDialogOpen\n\n// cek apakah bottomsheet sedang tampil\nGet.isBottomSheetOpen\n\n// hapus satu route\nGet.removeRoute()\n\n// kembali berturut-turut hingga predikat mereturn nilai true.\nGet.until()\n\n// pergi ke halaman selanjutnya dan hapus semua route sebelumnya hingga predikat mereturn nilai true.\nGet.offUntil()\n\n// pergi ke halaman selanjutnya menggunakan nama dan hapus semua route sebelumnya hingga predikat mereturn nilai true.\nGet.offNamedUntil()\n\n// Cek di platform apa aplikasi sedang berjalan\nGetPlatform.isAndroid\nGetPlatform.isIOS\nGetPlatform.isMacOS\nGetPlatform.isWindows\nGetPlatform.isLinux\nGetPlatform.isFuchsia\n\n// Cek tipe perangkat\nGetPlatform.isMobile\nGetPlatform.isDesktop\n// Semua platform didukung secara independen di web!\n// Anda bisa mengetahui apakah anda menjalankannya didalam browser\n// di Windows, iOS, OSX, Android, dsb.\nGetPlatform.isWeb\n\n\n// Sama dengan : MediaQuery.of(context).size.height,\n// tapi immutable.\nGet.height\nGet.width\n\n// Memberikan konteks saat ini dari sebuah Navigator\nGet.context\n\n// Memberikan konteks dari snackbar/dialog/bottomsheet di Gives the latar depan, dimanapun di kode anda\nGet.contextOverlay\n\n// Catatan: metode berikut adalah sebuah perluasan konteks. Berhubung anda\n// memiliki akses terhadap konteks dimanapun di UI anda, anda bisa menggunakannya dimanapun di kode UI\n\n// Jika anda memerlukan height/width yang bisa dirubah (seperti Desktop atau browser yang bisa di sesuaikan) anda akan memerlukan konteks\ncontext.width\ncontext.height\n\n// Memberikan anda kemampuan untuk mendefinisikan separuh layar, sepertiga, dan seterusnya.\n// Berguna untuk aplikasi responsive.\n// param dibagi dengan (double) optional - default: 1\n// param dikurangi dengan (double) optional - default: 0\ncontext.heightTransformer()\ncontext.widthTransformer()\n\n/// Mirip seperti MediaQuery.of(context).size\ncontext.mediaQuerySize()\n\n/// Mirip seperti MediaQuery.of(context).padding\ncontext.mediaQueryPadding()\n\n/// Mirip seperti MediaQuery.of(context).viewPadding\ncontext.mediaQueryViewPadding()\n\n/// Mirip seperti MediaQuery.of(context).viewInsets;\ncontext.mediaQueryViewInsets()\n\n/// Mirip seperti MediaQuery.of(context).orientation;\ncontext.orientation()\n\n/// Cek apakah perangkat sedang dalam mode lansekap\ncontext.isLandscape()\n\n/// Cek apakah perangkat sedang dalam mode portrait\ncontext.isPortrait()\n\n/// Mirip seperti MediaQuery.of(context).devicePixelRatio;\ncontext.devicePixelRatio()\n\n/// Mirip seperti MediaQuery.of(context).textScaleFactor;\ncontext.textScaleFactor()\n\n/// Dapatkan shortestSide dari layar\ncontext.mediaQueryShortestSide()\n\n/// True jika layar lebih besar dari 800\ncontext.showNavbar()\n\n/// True jika shortestSide kurang dari 600p\ncontext.isPhone()\n\n/// True jika shortestSide lebih besar dari 600p\ncontext.isSmallTablet()\n\n/// True jika shortestSide lebih besar dari 720p\ncontext.isLargeTablet()\n\n/// True jika perangkat adalah sebuah Tablet\ncontext.isTablet()\n\n/// Memberikan sebuah value<T> berdasarkan ukuran layar\n/// dapat memberi value untuk:\n/// watch: jika shortestSide lebih kecil dari 300\n/// mobile: jika shortestSide lebih kecil dari 600\n/// tablet: jika shortestSide lebih kecil dari 1200\n/// desktop: jika lebar lebih besar dari 1200\ncontext.responsiveValue<T>()\n```\n\n### Pengaturan Global Opsional dan Konfigurasi Manual\n\nGetMaterialApp mengkonfigurasi semuanya untuk anda, namun jika anda ingin mengkonfigurasi Get secara manual.\n\n```dart\nMaterialApp(\n  navigatorKey: Get.key,\n  navigatorObservers: [GetObserver()],\n);\n```\n\nAnda juga bisa menggunakan Middleware anda sendiri melalui `GetObserver`, ini tidak akan mempengaruhi apapun.\n\n```dart\nMaterialApp(\n  navigatorKey: Get.key,\n  navigatorObservers: [\n    GetObserver(MiddleWare.observer) // Disini\n  ],\n);\n```\n\nAnda bisa membuat _Pengaturan Global_ untuk `Get`. Cukup tambahkan `Get.config` kedalam kode anda sebelum berpindah ke route manapun.\nAtau lakukan secara langsung di `GetMaterialApp`\n\n```dart\nGetMaterialApp(\n  enableLog: true,\n  defaultTransition: Transition.fade,\n  opaqueRoute: Get.isOpaqueRouteDefault,\n  popGesture: Get.isPopGestureEnable,\n  transitionDuration: Get.defaultDurationTransition,\n  defaultGlobalState: Get.defaultGlobalState,\n);\n\nGet.config(\n  enableLog = true,\n  defaultPopGesture = true,\n  defaultTransition = Transitions.cupertino\n)\n```\n\nAnda bisa secara opsional me-redirect seluruh pesan logging dari `Get`.\nJika anda ingin menggunakan logging buatan anda sendiri, logging package favorit,\ndan ingin meng-capture lognya:\n\n```dart\nGetMaterialApp(\n  enableLog: true,\n  logWriterCallback: localLogWriter,\n);\n\nvoid localLogWriter(String text, {bool isError = false}) {\n  // oper message ke logging package favorit anda disini\n  // harap dicatat bahwa meskipun enableLog: false, pesan log akan di-push dalam callback ini,\n  // anda dapat memeriksa flag-nya jika anda mau melalui GetConfig.isLogEnable\n}\n\n```\n\n### Local State Widgets\n\nWidget ini memungkinkan anda untuk mengelola satu nilai, dan menjaga state emphemeral dan lokal.\nKita memiliki rasa untuk Reactive dan Simple.\nContohnya, anda mungkin menggunakannya untuk men-toggle obscureText di sebuah `TextField`, mungkin membuat\nExpandable Panel kustom, atau mungkin memodifikasi index saat ini dalam `BottomNavigationBar` sembari mengganti konten\ndari body didalam `Scaffold`\n\n#### ValueBuilder\n\nSebuah simplifikasi dari `StatefulWidget` yang berfungsi dengan sebuah callback `.setState` yang menerima value yang telah diperbarui.\n\n```dart\nValueBuilder<bool>(\n  initialValue: false,\n  builder: (value, updateFn) => Switch(\n    value: value,\n    onChanged: updateFn, // signaturenya sama! anda bisa menggunakan ( newValue ) => updateFn( newValue )\n  ),\n  // jika anda perlu memanggil sesuatu diluar builder method.\n  onUpdate: (value) => print(\"Value updated: $value\"),\n  onDispose: () => print(\"Widget unmounted\"),\n),\n```\n\n#### ObxValue\n\nMirip seperti [`ValueBuilder`](#valuebuilder), tapi ini versi Reactive nya, anda bisa menaruh Rx instance (ingat .obs?) dan\nakan ter-update secara otomatis... keren kan?\n\n```dart\nObxValue((data) => Switch(\n        value: data.value,\n        onChanged: data, // Rx memiliki sebuah _callable_ function! Anda bisa menggunakan (flag) => data.value = flag,\n    ),\n    false.obs,\n),\n```\n\n## Tips berguna\n\n`.obs`ervables (juga dikenal sebagai _Rx_ Types) memiliki beragam metode dan operator internal.\n\n> Sangat umum untuk _percaya_ bahwa sebuah properti dengan `.obs` **ADALAH** nilai aktual... jangan salah!\n> Kami menghindari Type declaration dari sebuah variabel, karena compiler Dart cukup pintar, dan kode nya\n> terlihat lebih bersih, tapi:\n\n```dart\nvar message = 'Hello world'.obs;\nprint( 'Message \"$message\" has Type ${message.runtimeType}');\n```\n\nMeskipun `message` _mengeluarkan output_ nilai String aktual, tipenya adalah **RxString**!\n\nJadi, anda tidak bisa melakukan `message.substring( 0, 4 )`.\nAnda perlu mengakses `value` aslinya didalam _observable_:\nCara yang paling \"sering digunakan\" adalah `.value`, tapi, tahukah anda bahwa anda juga bisa menggunakan...\n\n```dart\nfinal name = 'GetX'.obs;\n// hanya \"memperbarui\" stream, jika nilainya berbeda dari sebelumnya.\nname.value = 'Hey';\n\n// Seluruh properti Rx \"bisa dipanggil\" dan akan mereturn nilai baru.\n// tapi cara ini tidak menerima `null`, UI-nya tidak akan rebuild.\nname('Hello');\n\n// ini seperti getter, mengeluarkan output 'Hello'.\nname();\n\n/// angka:\n\nfinal count = 0.obs;\n\n// Anda bisa menggunakan semua operasi non-mutable dari primitif num!\ncount + 1;\n\n// Hati hati! ini hanya valid jika `count` tidak final, melainkan var\ncount += 1;\n\n// Anda juga bisa melakukan komparasi antar nilai:\ncount > 2;\n\n/// boolean:\n\nfinal flag = false.obs;\n\n// bertukar nilai antara true/false\nflag.toggle();\n\n\n/// semua tipe:\n\n// Atur `value` menjadi null.\nflag.nil();\n\n// Semua operasi toString(), toJson() dikirimkan ke `value`\nprint( count ); // memanggil `toString()` didalamnya untuk RxInt\n\nfinal abc = [0,1,2].obs;\n// Mengkonversi nilai dari Array json, mengeluarkan output RxList\n// Json didukung oleh semua tipe Rx!\nprint('json: ${jsonEncode(abc)}, type: ${abc.runtimeType}');\n\n// RxMap, RxList dan RxSet adalah tipe Rx spesial, mereka meng-extends native type masing-masing.\n// tapi anda bisa bekerja menggunakan List sebagai list biasa, meskipun reactive!\nabc.add(12); // memasukkan 12 kedalam list, dan MEMPERBARUI stream.\nabc[3]; // seperti List, membaca index ke 3.\n\n\n// persamaan berfungsi dengan Rx dan value nya, namun hashCode nya selalu diambil dari value\nfinal number = 12.obs;\nprint( number == 12 ); // mengeluarkan output: true\n\n/// Model Rx Kustom:\n\n// toJson(), toString() ditangguhkan ke child, jadi anda bisa mengimplementasi override pada mereka dan print() observable nya secara langsung\n\nclass User {\n    String name, last;\n    int age;\n    User({this.name, this.last, this.age});\n\n    @override\n    String toString() => '$name $last, $age years old';\n}\n\nfinal user = User(name: 'John', last: 'Doe', age: 33).obs;\n\n// `user` memang \"reaktif\", tapi properti didalamnya TIDAK REAKTIF!\n// Jadi, jika kita mengubah variabel didalamnya...\nuser.value.name = 'Roi';\n// Widget tidak akan rebuild!,\n// `Rx` tidak mengetahui apapun ketika anda mengubah sesuatu didalam user.\n// Jadi, untuk kelas kustom, kita perlu secara manual \"memberi tahu\" perubahannya.\nuser.refresh();\n\n// atau kita bisa menggunakan `update()` method!\nuser.update((value){\n  value.name='Roi';\n});\n\nprint( user );\n```\n\n#### GetView\n\nSaya menyukai Widget ini, sangat simpel dan berguna!\n\nAdalah sebuah `const Stateless` Widget yang memiliki getter `controller` untuk `Controller` yang terdaftar, itu saja.\n\n```dart\n class AwesomeController extends GetxController {\n   final String title = 'My Awesome View';\n }\n\n  // SELALU ingat untuk memberikan `Type` yang anda gunakan untuk mendaftarkan controller anda!\n class AwesomeView extends GetView<AwesomeController> {\n   @override\n   Widget build(BuildContext context) {\n     return Container(\n       padding: EdgeInsets.all(20),\n       child: Text(controller.title), // cukup panggil `controller.something`\n     );\n   }\n }\n```\n\n#### GetResponsiveView\n\nExtend widget ini untuk membuat responsive view.\nwidget ini mengandung properti `screen` yang memiliki semua\ninformasi tentang ukuran layar dan tipenya.\n\n##### Cara pakai\n\nAnda memiliki dua opsi untuk mem-buildnya.\n\n- dengan `builder` method yang anda return ke widget yang akan di-build.\n- dengan metode `desktop`, `tablet`,`phone`, `watch`. method\nspesifik akan dibuat ketika tipe layar cocok dengan method.\nketika layarnya adalah [ScreenType.Tablet] maka method `tablet`\nakan di eksekusi dan seterusnya.\n**Catatan:** Jika anda menggunakan metode ini, mohon atur properti `alwaysUseBuilder` ke `false`\n\nDengan properti `settings` anda bisa mengatur batasan lebar untuk tipe layar.\n\n![example](https://github.com/SchabanBo/get_page_example/blob/master/docs/Example.gif?raw=true)\nCode to this screen\n[code](https://github.com/SchabanBo/get_page_example/blob/master/lib/pages/responsive_example/responsive_view.dart)\n\n#### GetWidget\n\nKebanyakan orang tidak tahu untuk apa Widget ini, atau benar benar membingungkan penggunaannya.\nKasus penggunaannya sangat langka, namun sangat spesifik: Melakukan `cache` terhadap Controller.\nKarena _cache_, tidak bisa dijadikan `const Stateless`.\n\n> Lalu, kapan anda harus men-\"cache\" sebuah Controller?\n\nJika anda menggunakan, fitur \"tidak terlalu umum\" dari **GetX**: `Get.create()`.\n\n`Get.create(()=>Controller())` akan men-generate `Controller` baru setiap kali anda memanggil\n`Get.find<Controller>()`,\n\nItulah dimana `GetWidget` bercahaya... karena anda bisa menggunakannya, sebagai contoh,\nuntuk menyimpan list dari sebuah Todo item. Jadi, jika widget ter-\"rebuild\", dia akan meyimpan controller yang sama.\n\n#### GetxService\n\nKelas ini mirip seperti `GetxController`, dia berbagi lifecycle ( `onInit()`, `onReady()`, `onClose()`).\nTetapi tidak memiliki \"logic\" didalamnya. Dia hanya memberi tahu Sistem Dependency Injection **GetX**, bahwa subclass\nini **TIDAK BISA** dihapus dari memori.\n\nJadi ini sangat berguna untuk memastikan \"Service\" anda selalu dapat dijangkau dan aktif dengan `Get.find()`. Seperti:\n`ApiService`, `StorageService`, `CacheService`.\n\n```dart\nFuture<void> main() async {\n  await initServices(); /// AWAIT SERVICES INITIALIZATION.\n  runApp(SomeApp());\n}\n\n/// Adalah gerakan yang cerdas untuk membuat Service anda menginisialisasi sebelum anda menjalankan aplikasi Flutter\n/// seperti anda bisa mengontrol flow eksekusi (mungkin anda perlu memuat beberapa konfigurasi tema,\n/// apiKey, bahasa yang ditentukan oleh user...) jadi, load SettingSerice sebelum menjalankan ApiService.\n/// supaya GetMaterialApp() tidak perlu rebuild, dan mengambil nilainya secara langsung.\nvoid initServices() async {\n  print('starting services ...');\n  /// Disini adalah dimana anda meletakkan get_storage, hive, inisialisasi shared_pref.\n  /// atau koneksi moor, atau apapun yang sifatnya async.\n  await Get.putAsync(() => DbService().init());\n  await Get.putAsync(SettingsService()).init();\n  print('All services started...');\n}\n\nclass DbService extends GetxService {\n  Future<DbService> init() async {\n    print('$runtimeType delays 2 sec');\n    await 2.delay();\n    print('$runtimeType ready!');\n    return this;\n  }\n}\n\nclass SettingsService extends GetxService {\n  void init() async {\n    print('$runtimeType delays 1 sec');\n    await 1.delay();\n    print('$runtimeType ready!');\n  }\n}\n\n```\n\nThe only way to actually delete a `GetxService`, is with `Get.reset()` which is like a\n\"Hot Reboot\" of your app. So remember, if you need absolute persistence of a class instance during the\nlifetime of your app, use `GetxService`.\n\nSatu-satunya cara untuk benar benar menghapus sebuah `GetxService`, adalah dengan `Get.reset()` dimana ini seperti\n\"Hot Reboot\" dari aplikasi anda. Jadi ingat, jika anda butuh persistensi absolut dari sebuah instance kelas selama\nmasa hidup aplikasi anda, gunakan `GetxService`.\n\n# Breaking change dari 2.0\n\n1- Tipe Rx:\n\n| Sebelum | Sesudah    |\n| ------- | ---------- |\n| StringX | `RxString` |\n| IntX    | `RxInt`    |\n| MapX    | `RxMap`    |\n| ListX   | `RxList`   |\n| NumX    | `RxNum`    |\n| DoubleX | `RxDouble` |\n\nRxController dan GetBuilder sekarang digabungkan, anda tidak lagi perlu mengingat kontroler mana yang ingin anda gunakan, cukup gunakan GetxController, ini akan bekerja untuk simple state management dan reactive juga.\n\n2- NamedRoutes\nSebelumnya:\n\n```dart\nGetMaterialApp(\n  namedRoutes: {\n    '/': GetRoute(page: Home()),\n  }\n)\n```\n\nSekarang:\n\n```dart\nGetMaterialApp(\n  getPages: [\n    GetPage(name: '/', page: () => Home()),\n  ]\n)\n```\n\nMengapa berubah?\nSeringkali, mungkin diperlukan untuk memutuskan halaman mana yang akan ditampilkan melalui sebuah parameter, atau login token, cara sebelumnya sangat tidak fleksibel dan tidak memungkinkan untuk melakukan hal ini.\nMemasukkan data kedalam fungsi mengurangi konsumsi RAM secara signifikan, mengingat route tidak akan di alokasikan ke memori sejak aplikasi dimulai, dan ini memungkinkan kita melakukan ini:\n\n```dart\n\nGetStorage box = GetStorage();\n\nGetMaterialApp(\n  getPages: [\n    GetPage(name: '/', page:(){\n      return box.hasData('token') ? Home() : Login();\n    })\n  ]\n)\n```\n\n# Mengapa Getx?\n\n1- Seringkali setelah Flutter update, banyak package anda yang akan berhenti bekerja. Terkadang compilation error terjadi, error yang sering muncul dan belum ada jawabannya, dan developer perlu mengetahui dimana errornya berasal, mencari errornya, lalu kemudian mencoba membuka sebuah isu di repository yang bersangkutan, dan melihat apakah problemnya terselesaikan. Get memusatkan resource utama untuk development (State, dependency dan route management), memungkinkan anda untuk menambahkan satu package kedalam pubspec, dan mulai bekerja. Setelah Flutter update, satu-satunya hal yang anda perlu lakukan adalah memperbarui dependensi Get, dan kembali bekerja. Get juga menyelesaikan isu kompatibilitas. Berapa kali sebuah versi dari sebuah package tidak kompatibel dengan versi lainnya, karena yang satu menggunakan sebuah dependensi dalam satu versi, dan yang lain menggunakan versi lainnya? Ini juga bukan sebuah masalah menggunakan Get, yang mana semua berada di package yang sama dan kompatibel secara penuh.\n\n2- Flutter mudah digunakan, Flutter luar biasa, tetapi Flutter masih memiliki beberapa boilerplate yang mungkin tidak diinginkan untuk kebanyakan developer, seperti `Navigator.of(context).push(context builder [...]`. Get menyederhanakan proses development. Daripada menulis 8 baris kode hanya untuk memanggil route, anda bisa menggunakan: `Get.to(Home())` dan selesai, anda akan pergi ke halaman selanjutnya. URL web dinamis adalah hal yang sangat menyakitkan untuk dilakukan dengan Flutter saat ini, dan dengan GetX sangat sederhana. Mengelola state di Flutter, dan megelola dependensi juga suatu hal yang menghasilkan banyak diskusi, dengan ratusan jenis pattern di pub. Tetapi tidak ada yang semudah menambahkan \".obs\" di akhir variabel anda, dan meletakkan widget didalam Obx, dan selesai, semua update terhadap variabel tersebut akan secara otomatis terupdate di layar.\n\n3- Meringankan tanpa mengkhawatirkan performa. Performa Flutter sudah luar biasa, tetapi bayangkan anda menggunakan state manager, dan sebuah locator untuk mendistribusikan bloc/store/controller dsb, kelas. Anda perlu secara manual memanggil pengecualian terhadap dependensi ketika anda tidak membutuhkannya. Namun apakah anda pernah terfikirkan ketika simpelnya, anda menggunakan controller, dan tidak lagi digunakan oleh siapapun, akan dihapus dari memori? Itu yang GetX lakukan. Dengan SmartManagement, semua yang tidak digunakan akan dihapus dari memori, dan anda tidak perlu khawatir tentang apapun selain programming. Anda akan terjamin bahwa anda mengkonsumsi resource minimum yang diperlukan, bahkan tanpa harus membuat logic untuk hal ini.\n\n4- Actual decoupling. Anda mungkin pernah mendengar konsep \"pisahkan view dari business logic\". Ini bukanlah sebuah keanehan dari BLoC, MVC, MVVM, dan standard lainnya dalam market yang memiliki konsep ini. Namun, konsep ini terkadang termitigasi di Flutter karena penggunaan konteks.\nJika anda memerlukan konteks untuk menemukan InheritedWidget, anda membutuhkannya di view, atau mengirim konteks melalui parameter. Saya menemukan bahwa solusi ini sangat jelek, dan untuk bekerja dalam tim kami harus selalu memiliki sebuah ketergantungan pada business logic di dalam view. GetX adalah cara yang tidak lazim dengan metode standard, dan sementara itu tidak benar-benar secara penuh melarang penggunaan StatefulWidgets, InitState, dsb., ini selalu memiliki metode yang mirip dan bisa lebih bersih. Controller memiliki life cycle, dan ketika anda perlu membuat APIREST request sebagai contoh, anda tidak bergantung pada apapun didalam view. Anda bisa menggunakan onInit untuk menginisiasi pemanggilan http dan ketika datanya sampai, variabel akan dipopulasikan. GetX juga secara penuh reaktif (serius, dan bekerja dibawah stream), sekali items terisi, semua widget yang menggunakan variabel itu akan secara otomatis diperbarui didalam view. Ini memungkinkan orang orang dengan keahlian di bagian UI untuk bekerja hanya dengan widget, dan tidak perlu mengirim apapun ke business logic selain user event (seperti meng-klik sebuah tombol), sementara orang yang bekerja dengan business logic akan bebas membuat dan melakukan test terhadap business logic secara terpisah.\n\nLibrary ini akan terus diperbarui dan mengimplementasikan fitur baru. Jangan ragu untuk menawarkan PR dan berkontribusi ke mereka.\n\n# Komunitas\n\n## Channel Komunitas\n\nGetX memiliki komunitas yang sangat aktif dan membantu. Jika anda memiliki pertanyaan, atau membutuhkan bantuan mengenai penggunaan framework ini, bergabunglah dengan kanal komunitas kami, pertanyaan anda akan dijawab lebih cepat, dan akan menjadi tempat yang paling cocok. Repositori ini eksklusif untuk pembukaan isu dan permintaan resource, tapi jangan ragu untuk menjadi bagian dari Komunitas GetX.\n\n| **Slack**                                                                                                                   | **Discord**                                                                                                                 | **Telegram**                                                                                                          |\n| :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------- |\n| [![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) |\n\n## Cara berkontribusi\n\n_Ingin berkontribusi kedalam proyek? Kami akan sangat bangga untuk menyorot anda sebagai salah satu dari kolaborator kami. Ini adalah beberapa point dimana anda bisa berkontribusi dan membuat Get (dan Flutter) jadi lebih baik_\n\n- Membantu menerjemahkan readme ke dalam bahasa lain.\n- Menambahkan dokumentasi ke dalam readme (banyak fungsi dari Get yang masih belum terdokumentasi).\n- Menulis artikel atau membuat video mengajarkan tentang penggunaan Get (akan dimasukkan kedalam readme dan Wiki kami di masa yang akan datang).\n- Menawarkan PR untuk kode/test.\n- Menambahkan fungsi baru.\n\nKontribusi dalam bentuk apapun dipersilahkan!\n\n## Artikel dan Video\n\n- [Dynamic Themes in 3 lines using GetX™](https://medium.com/swlh/flutter-dynamic-themes-in-3-lines-c3b375f292e3) - Tutorial oleh [Rod Brown](https://github.com/RodBr).\n- [Complete GetX™ Navigation](https://www.youtube.com/watch?v=RaqPIoJSTtI) - Route management video oleh Amateur Coder.\n- [Complete GetX State Management](https://www.youtube.com/watch?v=CNpXbeI_slw) - State management video oleh Amateur Coder.\n- [GetX™ Other Features](https://youtu.be/ttQtlX_Q0eU) - Utils, storage, bindings and other features video oleh Amateur Coder.\n- [Firestore User with GetX | Todo App](https://www.youtube.com/watch?v=BiV0DcXgk58) - Video oleh Amateur Coder.\n- [Firebase Auth with GetX | Todo App](https://www.youtube.com/watch?v=-H-T_BSgfOE) - Video oleh Amateur Coder.\n- [The Flutter GetX™ Ecosystem ~ State Management](https://medium.com/flutter-community/the-flutter-getx-ecosystem-state-management-881c7235511d) - State management oleh [Aachman Garg](https://github.com/imaachman).\n- [The Flutter GetX™ Ecosystem ~ Dependency Injection](https://medium.com/flutter-community/the-flutter-getx-ecosystem-dependency-injection-8e763d0ec6b9) - Dependency Injection oleh [Aachman Garg](https://github.com/imaachman).\n- [GetX, the all-in-one Flutter package](https://www.youtube.com/watch?v=IYQgtu9TM74) - A brief tutorial covering State Management and Navigation oleh Thad Carnevalli.\n- [Build a To-do List App from scratch using Flutter and GetX](https://www.youtube.com/watch?v=EcnqFasHf18) - UI + State Management + Storage video oleh Thad Carnevalli.\n- [GetX Flutter Firebase Auth Example](https://medium.com/@jeffmcmorris/getx-flutter-firebase-auth-example-b383c1dd1de2) - Article oleh Jeff McMorris.\n- [Flutter State Management with GetX – Complete App](https://www.appwithflutter.com/flutter-state-management-with-getx/) - oleh App With Flutter.\n- [Flutter Routing with Animation using Get Package](https://www.appwithflutter.com/flutter-routing-using-get-package/) - oleh App With Flutter.\n"
  },
  {
    "path": "README.ja-JP.md",
    "content": "![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png)\n\n[![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)\n[![popularity](https://badges.bar/get/popularity)](https://pub.dev/packages/sentry/score)\n[![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)\n[![pub points](https://badges.bar/get/pub%20points)](https://pub.dev/packages/get/score)\n![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)\n[![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart)\n[![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N)\n[![Get on Slack](https://img.shields.io/badge/slack-join-orange.svg)](https://communityinviter.com/apps/getxworkspace/getx)\n[![Telegram](https://img.shields.io/badge/chat-on%20Telegram-blue.svg)](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g)\n<a href=\"https://github.com/Solido/awesome-flutter\">\n<img alt=\"Awesome Flutter\" src=\"https://img.shields.io/badge/Awesome-Flutter-blue.svg?longCache=true&style=flat-square\" />\n</a>\n<a href=\"https://www.buymeacoffee.com/jonataslaw\" target=\"_blank\"><img src=\"https://i.imgur.com/aV6DDA7.png\" alt=\"Buy Me A Coffee\" style=\"height: 41px !important;width: 174px !important; box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;\" > </a>\n\n![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/getx.png)\n\n\n<div align=\"center\">\n\n**言語**\n\n\n[![英語](https://img.shields.io/badge/Language-English-blueviolet?style=for-the-badge)](README.md)\n[![ベトナム語](https://img.shields.io/badge/Language-Vietnamese-blueviolet?style=for-the-badge)](README-vi.md)\n[![インドネシア語](https://img.shields.io/badge/Language-Indonesian-blueviolet?style=for-the-badge)](README.id-ID.md)\n[![ウルドゥー語](https://img.shields.io/badge/Language-Urdu-blueviolet?style=for-the-badge)](README.ur-PK.md)\n[![中国語](https://img.shields.io/badge/Language-Chinese-blueviolet?style=for-the-badge)](README.zh-cn.md)\n[![ポルトガル語](https://img.shields.io/badge/Language-Portuguese-blueviolet?style=for-the-badge)](README.pt-br.md)\n[![スペイン語](https://img.shields.io/badge/Language-Spanish-blueviolet?style=for-the-badge)](README-es.md)\n[![ロシア語](https://img.shields.io/badge/Language-Russian-blueviolet?style=for-the-badge)](README.ru.md)\n[![ポーランド語](https://img.shields.io/badge/Language-Polish-blueviolet?style=for-the-badge)](README.pl.md)\n[![韓国語](https://img.shields.io/badge/Language-Korean-blueviolet?style=for-the-badge)](README.ko-kr.md)\n[![フランス語](https://img.shields.io/badge/Language-French-blueviolet?style=for-the-badge)](README-fr.md)\n[![日本語](https://img.shields.io/badge/Language-Japanese-blueviolet?style=for-the-badge)](README-ja.md)\n\n</div>\n\n- [Getとは](#Getとは)\n- [インストール方法](#インストール方法)\n- [GetXによるカウンターアプリ](#GetXによるカウンターアプリ)\n- [三本柱](#三本柱)\n  - [状態管理](#状態管理)\n    - [リアクティブな状態管理](#リアクティブな状態管理)\n    - [状態管理に関する詳細ドキュメント](#状態管理に関する詳細ドキュメント)\n  - [Route管理](#Route管理)\n    - [Route管理に関する詳細ドキュメント](#Route管理に関する詳細ドキュメント)\n  - [依存オブジェクト管理](#依存オブジェクト管理)\n    - [依存オブジェクト管理に関する詳細ドキュメント](#依存オブジェクト管理に関する詳細ドキュメント)\n- [ユーティリティ](#ユーティリティ)\n  - [多言語対応](#多言語対応)\n    - [翻訳ファイル](#翻訳ファイル)\n      - [翻訳ファイルの利用](#翻訳ファイルの利用)\n    - [ロケール](#ロケール)\n      - [ロケールの変更](#ロケールの変更)\n      - [システムのロケールを読み込む](#システムのロケールを読み込む)\n  - [Themeの変更](#Themeの変更)\n  - [GetConnect](#getconnect)\n    - [デフォルト設定](#デフォルト設定)\n    - [カスタム設定](#カスタム設定)\n  - [GetPageにミドルウェアを設定](#GetPageにミドルウェアを設定)\n    - [実行優先度](#実行優先度)\n    - [redirect](#redirect)\n    - [onPageCalled](#onpagecalled)\n    - [onBindingsStart](#onbindingsstart)\n    - [onPageBuildStart](#onpagebuildstart)\n    - [onPageBuilt](#onpagebuilt)\n    - [onPageDispose](#onpagedispose)\n  - [その他API](#その他API)\n    - [オプションのグローバル設定と手動設定](#オプションのグローバル設定と手動設定)\n    - [ローカルステートWidget](#ローカルステートWidget)\n      - [ValueBuilder](#valuebuilder)\n      - [ObxValue](#obxvalue)\n  - [お役立ちTIPS](#お役立ちTIPS)\n    - [StateMixin](#statemixin)\n    - [GetView](#getview)\n    - [GetResponsiveView](#getresponsiveview)\n      - [使い方](#使い方])\n    - [GetWidget](#getwidget)\n    - [GetxService](#getxservice)\n  - [テストの実行](#テストの実行)\n    - [mockitoやmocktailを使う場合](#mockitoやmocktailを使う場合)\n    - [Get.reset()](#Get.reset())\n    - [Get.testMode](#Get.testMode)\n- [バージョン2.0からの破壊的変更](#バージョン2.0からの破壊的変更)\n- [なぜGetXなのか](#なぜGetXなのか)\n- [コミュニティ](#コミュニティ)\n  - [コミュニティチャンネル](#コミュニティチャンネル)\n  - [コントリビュート方法](#コントリビュート方法)\n  - [GetXに関する記事と動画](#GetXに関する記事と動画)\n\n# Getとは\n\n- GetXはFlutterのための超軽量でパワフルなソリューションです。高パフォーマンスな状態管理機能、インテリジェントな依存オブジェクト管理機能、そしてRoute管理機能の三本柱を軽量かつ実用的な形で組み合わせています。\n\n- GetXは3つの基本原則を念頭に開発されています。 **【生産性、パフォーマンス、コードの分離性】** これらはライブラリ内のすべてのリソースに優先適用されている原則です。\n\n  - **パフォーマンス:** GetXは高いパフォーマンスと最小限のリソース消費を目標にしています。GetXはでは Stream および ChangeNotifier を利用しなくて済みます。\n\n  - **生産性:** GetXはシンプルで使い心地のいいシンタックスを採用しています。あなたの実現したい機能がどんなものであれ、GetXを使えばより簡単に実現できる方法が見つかるでしょう。開発にかかる時間を短縮し、あなたのアプリケーションのパフォーマンスを最大限引き出してくれます。\n\n    開発者はメモリリソースの管理に気を配るのが常です。しかしGetXでは、リソースが使用されていないときはメモリから削除されるのがデフォルト動作のため、過度に気にかける必要はありません。（逆にメモリに残しておきたい場合は、依存オブジェクトをインスタンス化するメソッドを使う際に「permanent: true」と宣言してください）これにより時間が節約できますし、不要な依存オブジェクトがメモリ上に残るリスクも少なくなります。メモリへの読み込みについてもデフォルトは遅延読み込みであり、使用するときに初めてメモリ上に読み込まれます。\n\n  - **コードの分離性:** GetXを使うと、ビュー、プレゼンテーションロジック、ビジネスロジック、依存オブジェクトの注入、およびナビゲーション周りのコードを書き分けやすくなります。Routeのナビゲーションにはcontextを必要としないため、Widgetツリーに依存することはありません。ロジックについてもInheritedWidget経由でController/BLoCにアクセスする際のcontextは必要ありません。プレゼンテーションロジックとビジネスロジックをUIクラスから完全に切り離すことができます。また、Controller/モデル/BLoCのクラスを、`MultiProvider`を使ってWidgetツリーに注入する必要もありません。GetXでは独自の依存オブジェクト注入機能を使用し、ビュークラスからビューとは無関係なコードをなくすことができるのです。\n\n    GetXを使うことでアプリケーションの各機能がどこにあるのかがわかりやすくなり、自然と見やすいコードになります。メンテナンスが容易になるだけでなく、それまでのFlutterでは考えられなかったモジュール共有が簡単に実現できるようになりました。\n    BLoCはこの分野におけるFlutterの出発点と言えるものでしたが、GetXはこれを正統進化させており、ビジネスロジックのみならずプレゼンテーションロジックも分離することができます。そのほかデータレイヤーはもちろん、依存オブジェクトやRouteの注入に関するコードも。どこに何が配置されているのか全体の見通しがしやすくなり、Hello Worldを表示させるかのように簡単にアプリの機能を利用できるようになるでしょう。\n    Flutterアプリを作るならGetXは最も簡単で実用的、かつスケーラブルなソリューションです。強力なエコシステムも存在があるため、初心者にはわかりやすさ、プロには正確性を提供することができます。そしてFlutter SDKにはない幅広い種類のAPIを提供し、セキュアで安定的な環境を構築します。\n\n- GetXは肥大化したライブラリではありません。何も気にせずすぐに開発を始められるよう多数の機能を標準で備えていますが、それぞれの機能は個別にコンテナに入っており、使用してはじめて起動します。状態管理機能しか利用していない場合はその機能だけがコンパイルされます。Route管理機能だけを利用していれば、状態管理機能がコンパイルされることはありません。\n\n- GetXには巨大なエコシステム、コミュニティ、コラボレーターの存在があるため、Flutterが存在する限りメンテナンスされ続けます。またGetXもFlutterと同様にAndroid、iOS、Web、Mac、Linux、Windows、そしてあなたのサーバー上で、単一のコードから実行することができます。\n\n**[Get Server](https://github.com/jonataslaw/get_server)を使うことで、フロントエンドで作成したコードをバックエンドで再利用することが可能です。**\n\n**さらに、[Get CLI](https://github.com/jonataslaw/get_cli)を使えば、サーバー側でもフロントエンド側でも開発プロセス全体を自動化することができます。**\n\n**また、生産性をさらに高めるためのツールとして、[VSCode用の拡張機能](https://marketplace.visualstudio.com/items?itemName=get-snippets.get-snippets) と [Android Studio/Intellij用の拡張機能](https://plugins.jetbrains.com/plugin/14975-getx-snippets)があります。**\n\n# インストール方法\n\nGetパッケージを pubspec.yaml に追加します:\n\n```yaml\ndependencies:\n  get:\n```\n\n使用するときはこのようにインポートしてください:\n\n```dart\nimport 'package:get/get.dart';\n```\n\n# GetXによるカウンターアプリ\n\nFlutterで新規プロジェクトを作成する際に表示されるカウンターアプリは、コメントを含めると100行以上あります。Getの実力を示すため、このカウンターアプリを可読性を重視した形で、コメントを含めてわずか26行のコードで作成する方法を紹介します。\n\n- ステップ1:\n  MaterialAppの前に「Get」を足して、GetMaterialAppにします。\n\n```dart\nvoid main() => runApp(GetMaterialApp(home: Home()));\n```\n\n- 注1: GetMaterialAppはFlutterのMaterialAppに手を加えたものではありません。MaterialAppをchildに持ち、諸々の追加設定をしてくれるWidgetに過ぎません。この設定は手動でも可能ですが、その必要はありません。GetMaterialAppは、Routeの作成・注入、言語翻訳の注入など、ナビゲーションに必要なものをすべて注入してくれます。Getを状態管理や依存オブジェクト管理に限定して使用する場合は、GetMaterialAppを使用する必要はありません。GetMaterialAppは、Route、SnackBar、多言語対応、BottomSheet、Dialog、contextなしの高レベルAPIを利用する場合に必要です。\n- 注2: このステップは、Route管理機能（`Get.to()`や`Get.back()`など）を使用しない場合は、必要ありません。\n\n- ステップ2:\n  ビジネスロジッククラスを作成し、そこに必要な変数、メソッド、コントローラをすべて配置します。\n  変数に \".obs\" を付け足すことで、その変数の値の変化を監視することが可能になります。\n\n```dart\nclass Controller extends GetxController{\n  var count = 0.obs;\n  increment() => count++;\n}\n```\n\n- ステップ3:\n  ビューを作成します。StatelessWidgetを使用することでRAMが節約できます。GetではStatefulWidgetを使用する必要がなくなるかもしれません。\n\n```dart\nclass Home extends StatelessWidget {\n\n  @override\n  Widget build(context) {\n\n    // Get.put()を使ってクラスをインスタンス化することですべての子Routeで利用できるようになります。\n    final Controller c = Get.put(Controller());\n\n    return Scaffold(\n      // countが変わるたびにTextを更新するにはObx(()=>)を使ってください。\n      appBar: AppBar(title: Obx(() => Text(\"Clicks: ${c.count}\"))),\n\n      // 8行使っていたNavigator.pushの代わりに短い Get.to()を使ってください。context不要です。\n      body: Center(child: ElevatedButton(\n              child: Text(\"Go to Other\"), onPressed: () => Get.to(Other()))),\n      floatingActionButton:\n          FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment));\n  }\n}\n\nclass Other extends StatelessWidget {\n  // 他のページで使われているコントローラーを見つけてきてくれます。\n  final Controller c = Get.find();\n\n  @override\n  Widget build(context){\n     // 最新のcount変数の値にアクセス\n     return Scaffold(body: Center(child: Text(\"${c.count}\")));\n  }\n}\n```\n\nResult:\n\n![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/counter-app-gif.gif)\n\nこれはシンプルな例ですが、すでにGetがいかに強力であるかがわかると思います。プロジェクトが大きければ大きいほど、この差はもっと開くでしょう。\n\nGetはチームでの作業を想定して設計されていますが、個人開発者の仕事もシンプルにしてくれます。\n\nパフォーマンスを落とさず納期までにすべて納品。Getはすべての人に向いているわけではありませんが、このフレーズにぴんと来た人には確実に向いています！\n\n# 三本柱\n\n## 状態管理\n\nGetの状態管理には、非リアクティブ（GetBuilder）と、リアクティブ（GetX/Obx）の2つのアプローチがあります。\n\n### リアクティブな状態管理\n\nリアクティブプログラミングは複雑であると言われ、多くの人に敬遠されています。GetXは、リアクティブプログラミングをシンプルなものに変えます:\n\n* StreamControllerを作る必要はありません。\n* 変数ごとにStreamBuilderをセットする必要はありません。\n* 状態ごとにクラスを作る必要はありません。\n* 初期値のためにgetを準備する必要はありません。\n- コードの自動生成をする必要がありません。\n\nGetにおけるリアクティブプログラミングはsetStateと同じように簡単です。\n\n例えば、名前の変数があって、それを変更するたびに、その名前を使っているすべてのWidgetを自動で更新したい場合。\n\n```dart\nvar name = 'Jonatas Borges';\n```\n\nこのnameをObservable(監視可能)にするには, \".obs\"を値の末尾に付けるだけです。\n\n```dart\nvar name = 'Jonatas Borges'.obs;\n```\n\nUIでその値を表示し、値が変わるたびに内容を更新したい場合は次のようにします。\n\n```dart\nObx(() => Text(\"${controller.name}\"));\n```\n\n以上です。こんなに簡単なんですよ。\n\n### 状態管理に関する詳細ドキュメント\n\n**状態管理に関するより詳細な説明を知りたい方は[こちらの日本語ドキュメント](./documentation/ja_JP/state_management.md)をご覧ください。多くの事例や、非リアクティブな状態管理とリアクティブな状態管理の違いについても説明されています。**\n\nGetXパワーがもたらす利点をより理解していただけると思います。\n\n## Route管理\n\nGetXはcontextなしでRoute/SnackBar/Dialog/BottomSheetを使用することができます。具体的に見ていきましょう。\n\nいつものMaterialAppの前に「Get」を付け足して、GetMaterialAppにしましょう。\n\n```dart\nGetMaterialApp( // MaterialApp の前に Get\n  home: MyHome(),\n)\n```\n\n新しいRouteに画面遷移するにはこのシンタックス。\n\n```dart\nGet.to(NextScreen());\n```\n\n名前付きRouteに画面遷移するにはこのシンタックス。名前付きRouteの詳細は[こちらの日本語ドキュメント](./documentation/ja_JP/route_management.md#navigation-with-named-routes)\n\n```dart\nGet.toNamed('/details');\n```\n\nSnackBar、Dialog、BottomSheetなど、Navigator.pop(context)で閉じられるRouteはこれで閉じます。\n\n```dart\nGet.back();\n```\n\n次の画面に移動した後、前の画面に戻れないようにする場合（スプラッシュスクリーンやログイン画面など）はこちら。\n\n```dart\nGet.off(NextScreen());\n```\n\n次の画面に進み、前のRouteをすべてキャンセルする場合（ショッピングカート、アンケート、テストなど）はこちら。\n\n```dart\nGet.offAll(NextScreen());\n```\n\n以上、contextを一度も使わなかったことに気付きましたか？これがGetでRoute管理を行う最大のメリットのひとつです。contextを使わないので、たとえばcontrollerクラスの中でも、これらのメソッドを実行することができます。\n\n### Route管理に関する詳細ドキュメント\n\n**Getは名前付きRouteでも動作し、Routeの下位レベルの制御も可能です。詳細なドキュメントは[こちらの日本語ドキュメント](./documentation/ja_JP/route_management.md)にあります。**\n\n## 依存オブジェクト管理\n\nGetにはシンプルで強力な依存オブジェクト注入機能があります。わずか1行のコードで、Provider contextやinheritedWidgetも使わず、BLoCやControllerのようなクラスのインスタンスを取得することができます。\n\n```dart\nController controller = Get.put(Controller()); // controller = Controller() とする代わりに\n```\n\n- 注: Getの状態管理機能を使用している場合は、Bindings APIにもご注目を。BindingsはビューとControllerを結びつけるのをより便利にしてくれます。\n\n一つのクラスの中でControllerクラスをインスタンス化するのではなく、Getインスタンスの中でインスタンス化することで、アプリ全体でControllerが利用できるようになります。\n\n**ヒント:** Getの依存オブジェクト注入機能の部分は、パッケージ全体の中でも他の部分と切り離されているので、たとえば、あなたのアプリがすでに状態管理機能を一部で使用していたとしても、それらを書き直す必要はなく、この依存オブジェクト注入機能をそのまま使用することができます。\n\n```dart\ncontroller.fetchApi();\n```\n\n色々なRouteを行き来した後に、あるControllerクラスのデータにアクセスする必要が生じたとしましょう。ProviderやGet_itなら再びそのクラスに依存オブジェクトを注入する必要がありますよね？Getの場合は違います。Getでは「find」と依頼するだけで、追加の依存オブジェクトの注入は必要ありません。\n\n```dart\nController controller = Get.find();\n//マジックみたいですね。Getは正しいcontrollerをきちんと探してきてくれますよ。100万のcontrollerのインスタンスがあっても、Getは必ず正しいcontrollerを探し当てます。\n```\n\nそして、findで取得したコントローラーのデータをこのように呼び出すことができます。\n\n```dart\nText(controller.textFromApi);\n```\n\n### 依存オブジェクト管理に関する詳細ドキュメント\n\n**依存オブジェクト管理に関するより詳細な説明は[こちらの日本語ドキュメント](./documentation/ja_JP/dependency_management.md)をご覧ください。**\n\n# ユーティリティ\n\n## 多言語対応\n\n### 翻訳ファイル\n\n翻訳ファイルはシンプルなキーと値のMapとして保持されます。\n翻訳を追加するには、クラスを作成して `Translations` を継承します。\n\n```dart\nimport 'package:get/get.dart';\n\nclass Messages extends Translations {\n  @override\n  Map<String, Map<String, String>> get keys => {\n        'en_US': {\n          'hello': 'Hello World',\n        },\n        'de_DE': {\n          'hello': 'Hallo Welt',\n        }\n      };\n}\n```\n\n#### 翻訳ファイルの利用\n\n指定されたキーに `.tr` （translateのtr）を追加するだけで、`Get.locale` と `Get.fallbackLocale` の現在の値をに沿って適切な言語に翻訳されます。\n\n```dart\nText('title'.tr);\n```\n\n#### 単数系と複数形に対応\n\n```dart\nvar products = [];\nText('singularKey'.trPlural('pluralKey', products.length, Args));\n```\n\n#### パラメーターに対応\n\n```dart\nimport 'package:get/get.dart';\n\n\nMap<String, Map<String, String>> get keys => {\n    'en_US': {\n        'logged_in': 'logged in as @name with email @email',\n    },\n    'es_ES': {\n       'logged_in': 'iniciado sesión como @name con e-mail @email',\n    }\n};\n\nText('logged_in'.trParams({\n  'name': 'Jhon',\n  'email': 'jhon@example.com'\n  }));\n```\n\n### ロケール\n\nロケールと翻訳を定義するため、`GetMaterialApp`にパラメータを渡します。\n\n```dart\nreturn GetMaterialApp(\n    translations: Messages(), // Translationsを継承したクラスのインスタンス\n    locale: Locale('en', 'US'), // このロケール設定に沿って翻訳が表示される\n    fallbackLocale: Locale('en', 'UK'), // 無効なロケールだったときのフォールバックを指定\n);\n```\n\n#### ロケールの変更\n\nロケールを変更するには、`Get.updateLocale(locale)`を呼び出します。翻訳は新しいロケールに沿ってなされます。\n\n```dart\nvar locale = Locale('en', 'US');\nGet.updateLocale(locale);\n```\n\n#### システムのロケールを読み込む\n\nシステムのロケールを読み込むには、`Get.deviceLocale`を使用します。\n\n```dart\nreturn GetMaterialApp(\n    locale: Get.deviceLocale,\n);\n```\n\n## Themeの変更\n\n`GetMaterialApp`より上位のWidgetを使ってThemeを変更しないでください。Keyの重複を引き起こす可能性があります。アプリのThemeを変更するためには「ThemeProvider」Widgetを作成するという前時代的なアプローチが採られることが多いですが、**GetX™**ではこのようなことは必要ありません。\n\nカスタムのThemeDataを作成したら、それを`Get.changeTheme`内に追加するだけです。\n\n```dart\nGet.changeTheme(ThemeData.light());\n```\n\nもし、`onTap`でThemeを変更するボタンを作りたいのであれば、以下の2つの**GetX™** APIを組み合わせることができます。\n\n- Dark Theme が使われているかどうかをチェックするAPI\n- Theme を変えるAPI（ボタンの`onPressed`の中に設置できます）\n\n```dart\nGet.changeTheme(Get.isDarkMode? ThemeData.light(): ThemeData.dark());\n```\n\nDarkモードが有効であれば、_light theme_に切り替わり、Lightモードが有効なら、_dark theme_に切り替わります。\n\n## GetConnect\n\nGetConnect は、http または websocket を使用してバックエンドとフロントエンド間の通信を行う機能です。\n\n### デフォルト設定\n\nGetConnectを拡張することで、GET/POST/PUT/DELETE/SOCKETメソッドを使用して、Rest APIやウェブソケットと通信することができます。\n\n```dart\nclass UserProvider extends GetConnect {\n  // Get リクエスト\n  Future<Response> getUser(int id) => get('http://youapi/users/$id');\n  // Post リクエスト\n  Future<Response> postUser(Map data) => post('http://youapi/users', body: data);\n  // File付き Post リクエスト\n  Future<Response<CasesModel>> postCases(List<int> image) {\n    final form = FormData({\n      'file': MultipartFile(image, filename: 'avatar.png'),\n      'otherFile': MultipartFile(image, filename: 'cover.png'),\n    });\n    return post('http://youapi/users/upload', form);\n  }\n\n  GetSocket userMessages() {\n    return socket('https://yourapi/users/socket');\n  }\n}\n```\n\n### カスタム設定\n\nGetConnect は高度なカスタマイズが可能です。ベースUrlの定義はもちろん、リクエストヘッダーを足したり、レスポンスボディに変更を加えたり、認証情報を追加したり、認証回数の制限を設けたりすることができるほか、リクエストをModelに変換するデコーダを定義することもできます。\n\n```dart\nclass HomeProvider extends GetConnect {\n  @override\n  void onInit() {\n    // デフォルトデコーダーをセット\n    httpClient.defaultDecoder = CasesModel.fromJson;\n    httpClient.baseUrl = 'https://api.covid19api.com';\n    // baseUrlをセット\n\n    // リクエストヘッダーに 'apikey' プロパティを付け足しています。\n    httpClient.addRequestModifier((request) {\n      request.headers['apikey'] = '12345678';\n      return request;\n    });\n\n    // サーバーが\"Brazil\"を含むデータを送ってきてもユーザーに表示されることはありません。\n    // レスポンスがUIレイヤーに届けられる前にデータが取り除かれているからです。\n    httpClient.addResponseModifier<CasesModel>((request, response) {\n      CasesModel model = response.body;\n      if (model.countries.contains('Brazil')) {\n        model.countries.remove('Brazilll');\n      }\n    });\n\n    httpClient.addAuthenticator((request) async {\n      final response = await get(\"http://yourapi/token\");\n      final token = response.body['token'];\n      // ヘッダーをセット\n      request.headers['Authorization'] = \"$token\";\n      return request;\n    });\n\n    // HttpStatus が HttpStatus.unauthorized である限り、\n    // 3回まで認証が試みられます。\n    httpClient.maxAuthRetries = 3;\n  }\n  }\n\n  @override\n  Future<Response<CasesModel>> getCases(String path) => get(path);\n}\n```\n\n## GetPageにミドルウェアを設定\n\nGetPageに新しいプロパティが追加され、GetMiddleWareのListを設定することができるようになりました。GetMiddleWareは設定した任意の順序で実行されます。\n\n**注**: GetPageにミドルウェアを設定すると、そのページの子ページはすべて同じミドルウェアを自動的に持つことになります。\n\n### 実行優先度\n\nGetMiddlewareに設定したpriority(優先度)の若い順にミドルウェアが実行されます。\n\n```dart\nfinal middlewares = [\n  GetMiddleware(priority: 2),\n  GetMiddleware(priority: 5),\n  GetMiddleware(priority: 4),\n  GetMiddleware(priority: -8),\n];\n```\n\nこの場合の実行順序は **-8 => 2 => 4 => 5**\n\n### redirect\n\nredirect関数は、Routeを呼び出してページが検索されると実行されます。リダイレクト先のRouteSettingsが戻り値となります。もしくはnullを与えれば、リダイレクトは行われません。\n\n```dart\nRouteSettings redirect(String route) {\n  final authService = Get.find<AuthService>();\n  return authService.authed.value ? null : RouteSettings(name: '/login')\n}\n```\n\n### onPageCalled\n\nonPageCalled関数は、ページが呼び出された直後に実行されます。\nこの関数を使ってページの内容を変更したり、新しいページを作成したりすることができます。\n\n```dart\nGetPage onPageCalled(GetPage page) {\n  final authService = Get.find<AuthService>();\n  return page.copyWith(title: 'Welcome ${authService.UserName}');\n}\n```\n\n### onBindingsStart\n\nonBindingsStart関数は、Bindingsが初期化される直前に実行されます。\nたとえば、ページのBindingsを変更することもできます。\n\n```dart\nList<Bindings> onBindingsStart(List<Bindings> bindings) {\n  final authService = Get.find<AuthService>();\n  if (authService.isAdmin) {\n    bindings.add(AdminBinding());\n  }\n  return bindings;\n}\n```\n\n### onPageBuildStart\n\nonPageBuildStart関数は、Bindingsが初期化された直後、ページWidgetが作成される前に実行されます。\n\n```dart\nGetPageBuilder onPageBuildStart(GetPageBuilder page) {\n  print('bindings are ready');\n  return page;\n}\n```\n\n### onPageBuilt\n\nonPageBuilt関数は、GetPage.page(ページのビルダー)が呼び出された直後に実行され、表示されるWidgetを結果として受け取ることができます。\n\n### onPageDispose\n\nonPageDispose関数は、ページに関するすべてのオブジェクト（Controller、ビューなど）が破棄された直後に実行されます。\n\n## その他API\n\n```dart\n// 現在の画面に渡されているargs(引数)を取得\nGet.arguments\n\n// 直前のRouteの名前(\"/\" など)を取得\nGet.previousRoute\n\n// 現在のRouteオブジェクトを取得\nGet.rawRoute\n\n// GetObserverからRoutingを取得\nGet.routing\n\n// SnackBarが開いているかチェック\nGet.isSnackbarOpen\n\n// Dialogが開いているかチェック\nGet.isDialogOpen\n\n// BottomSheetが開いているかチェック\nGet.isBottomSheetOpen\n\n// Routeを削除\nGet.removeRoute()\n\n// 引数のRoutePredicateがtrueを返すまで画面を戻る\nGet.until()\n\n// 引数で指定したRouteに進み、RoutePredicateがtrueを返すまで画面を戻る\nGet.offUntil()\n\n// 引数で指定した名前付きRouteに進み、RoutePredicateがtrueを返すまで画面を戻る\nGet.offNamedUntil()\n\n// アプリがどのプラットフォームで実行されているかのチェック\nGetPlatform.isAndroid\nGetPlatform.isIOS\nGetPlatform.isMacOS\nGetPlatform.isWindows\nGetPlatform.isLinux\nGetPlatform.isFuchsia\n\n// アプリがどのデバイスで実行されているかのチェック\nGetPlatform.isMobile\nGetPlatform.isDesktop\n// プラットフォームとデバイスのチェックは独立\n// 同じOSでもウェブで実行されているのか、ネイティブで実行されているのか区別\nGetPlatform.isWeb\n\n\n// MediaQuery.of(context).size.height と同じ\n// ただしimmutable\nGet.height\nGet.width\n\n// Navigatorの現在のcontextを取得\nGet.context\n\n// SnackBar/Dialog/BottomSheet などフォアグラウンドのcontextを取得\nGet.overlayContext\n\n// 注: 以降のメソッドはcontextの拡張メソッドです。\n// contextと同じくUIのどこからでもアクセスできます。\n\n// ウィンドウサイズの変更などに合わせて変わる height/width を取得\ncontext.width\ncontext.height\n\n// 画面の半分のサイズ,1/3のサイズなどを取得\n// レスポンシブなデザインの場合に便利\n// オプションのパラメーター dividedBy で割る数を指定\n// オプションのパラメーター reducedBy でパーセンテージを指定\ncontext.heightTransformer()\ncontext.widthTransformer()\n\n/// MediaQuery.of(context).size とほぼ同じ\ncontext.mediaQuerySize()\n\n/// MediaQuery.of(context).padding とほぼ同じ\ncontext.mediaQueryPadding()\n\n/// MediaQuery.of(context).viewPadding とほぼ同じ\ncontext.mediaQueryViewPadding()\n\n/// MediaQuery.of(context).viewInsets とほぼ同じ\ncontext.mediaQueryViewInsets()\n\n/// MediaQuery.of(context).orientation とほぼ同じ\ncontext.orientation()\n\n/// デバイスがランドスケープ(横長)モードかどうかチェック\ncontext.isLandscape()\n\n/// デバイスがポートレート(縦長)モードかどうかチェック\ncontext.isPortrait()\n\n/// MediaQuery.of(context).devicePixelRatio とほぼ同じ\ncontext.devicePixelRatio()\n\n/// MediaQuery.of(context).textScaleFactor とほぼ同じ\ncontext.textScaleFactor()\n\n/// 画面の短辺の長さを取得\ncontext.mediaQueryShortestSide()\n\n/// 画面の横幅が800より大きい場合にtrueを返す\ncontext.showNavbar()\n\n/// 画面の短辺が600より小さい場合にtrueを返す\ncontext.isPhone()\n\n/// 画面の短辺が600より小さい場合にtrueを返す\ncontext.isSmallTablet()\n\n/// 画面の短辺が720より大きい場合にtrueを返す\ncontext.isLargeTablet()\n\n/// デバイスがタブレットの場合にtrueを返す\ncontext.isTablet()\n\n/// 画面サイズに合わせて value<T> を返す\n/// たとえば:\n/// 短辺が300より小さい → watchパラメーターの値を返す\n/// 短辺が600より小さい → mobileパラメーターの値を返す\n/// 短辺が1200より小さい → tabletパラメーターの値を返す\n/// 横幅が1200より大きい → desktopパラメーターの値を返す\ncontext.responsiveValue<T>()\n```\n\n### オプションのグローバル設定と手動設定\n\nGetMaterialApp はすべてあなたの代わりに設定してくれますが、手動で設定を施したい場合は MaterialApp の navigatorKey と navigatorObservers の値を指定してください。\n\n```dart\nMaterialApp(\n  navigatorKey: Get.key,\n  navigatorObservers: [GetObserver()],\n);\n```\n\n`GetObserver`内で独自のミドルウェアを使用することもできます。これは他に影響を及ぼすことはありません。\n\n```dart\nMaterialApp(\n  navigatorKey: Get.key,\n  navigatorObservers: [\n    GetObserver(MiddleWare.observer) // ここ\n  ],\n);\n```\n\n`Get` クラスに_グローバル設定_を施すことができます。Routeをプッシュする前のコードに `Get.config` を追加するだけです。もしくは、`GetMaterialApp` 内で直接設定することもできます。\n\n```dart\nGetMaterialApp(\n  enableLog: true,\n  defaultTransition: Transition.fade,\n  opaqueRoute: Get.isOpaqueRouteDefault,\n  popGesture: Get.isPopGestureEnable,\n  transitionDuration: Get.defaultDurationTransition,\n  defaultGlobalState: Get.defaultGlobalState,\n);\n\nGet.config(\n  enableLog = true,\n  defaultPopGesture = true,\n  defaultTransition = Transitions.cupertino\n)\n```\n\nオプションで、すべてのログメッセージを `Get` からリダイレクトさせることができます。\nお好みのロギングパッケージを使ってログを取得したい場合はこのようにしてください。\n\n```dart\nGetMaterialApp(\n  enableLog: true,\n  logWriterCallback: localLogWriter,\n);\n\nvoid localLogWriter(String text, {bool isError = false}) {\n  // ここでお好みのロギングパッケージにメッセージを渡してください\n  // enableLog: false にしても、ログメッセージはこのコールバックでプッシュされる点ご注意を\n  // ログが有効かどうかのチェックは Get.isLogEnable で可能\n}\n\n```\n\n### ローカルステートWidget\n\nローカルステートWidgetは、1つの変数の状態を一時的かつローカルに管理したい場合に便利です。\nシンプルなValueBuilderとリアクティブなObxValueの2種類があります。\nたとえば、`TextField` Widgetの obscureText プロパティを切り替えたり、折りたたみ可能なパネルをカスタムで作成したり、`BottomNavigation` の現在のインデックス値を変更して内容を変更したりといった用途に最適です。\n\n#### ValueBuilder\n\nsetStateでお馴染みの `StatefulWidget` をシンプルにしたビルダーWidgetです。\n\n```dart\nValueBuilder<bool>(\n  initialValue: false,\n  builder: (value, updateFn) => Switch(\n    value: value,\n    onChanged: updateFn, // ( newValue ) => updateFn( newValue ) も可\n  ),\n  // builderメソッドの外で何か実行する場合\n  onUpdate: (value) => print(\"Value updated: $value\"),\n  onDispose: () => print(\"Widget unmounted\"),\n),\n```\n\n#### ObxValue\n\n[`ValueBuilder`](#valuebuilder)に似ていますが、これはそのリアクティブバージョンです。Rxインスタンス(.obsを付けたときに戻る値です)を渡すと自動で更新されます。すごいでしょ？\n\n```dart\nObxValue((data) => Switch(\n        value: data.value,\n        onChanged: data,\n        // Rxには_呼び出し可能な_関数が備わっているのでこれだけでOK\n        // (flag) => data.value = flag も可能\n    ),\n    false.obs,\n),\n```\n\n## お役立ちTIPS\n\n`.obs`が付いた型(_Rx_型とも呼ばれる)には、さまざまな内部メソッドや演算子が用意されています。\n\n> `.obs`が付いたプロパティが **実際の値** だと信じてしまいがちですが...間違えないように！\n> 我々がcontrollerにおける変数の型宣言を省略してvarとしているのはDartのコンパイラが賢い上に、\n> そのほうがコードがすっきる見えるからですが…\n\n```dart\nvar message = 'Hello world'.obs;\nprint( 'Message \"$message\" has Type ${message.runtimeType}');\n```\n\n`message`を _print_ することで実際の文字列が取り出されはしますが、型は **RxString** です！\n\nそのため `message.substring( 0, 4 )` などといったことはできません。\nStringのメソッドにアクセスするには _observable_ の中にある実際の値 `value` にアクセスします。\nアクセスには `.value`を使うのが通常ですが、他の方法もあるのでご紹介します。\n\n```dart\nfinal name = 'GetX'.obs;\n// 新しい値が現在のものと異なる場合のみ Stream が更新されます。\nname.value = 'Hey';\n\n// すべてのRxプロパティは「呼び出し可能」で、valueを返してくれます。\n// ただし `null` は受付不可。nullの場合はUIが更新されない。\nname('Hello');\n\n// これはgetterみたいなものです。'Hello' を返します。\nname() ;\n\n/// num型の場合\n\nfinal count = 0.obs;\n\n// num型の非破壊的な演算子はすべて使えます。\ncount + 1;\n\n// 注意！ この場合は`count`がfinalなら有効ではないです。varなら有効。\ncount += 1;\n\n// 比較演算子も使用可能\ncount > 2;\n\n/// bool型の場合\n\nfinal flag = false.obs;\n\n// true/false を入れ替えることができます。\nflag.toggle();\n\n\n/// すべての型\n\n// `value` を null にセット。\nflag.nil();\n\n// toString(), toJson() などの操作はすべて `value` が対象になります。\nprint( count ); // RxIntの `toString()` が呼び出されて数字がprintされる。\n\nfinal abc = [0,1,2].obs;\n// json配列に変換した値と、'RxList' がprintされます。\n// JsonはすべてのRx型でサポートされています！\nprint('json: ${jsonEncode(abc)}, type: ${abc.runtimeType}');\n\n// RxMap、RxList、RxSetはそれぞれの元の型を拡張した特別なRx型です。\n// たとえばRxListは通常のListとして扱うことができる上にリアクティブです。\nabc.add(12); // 12をListにプッシュし、Streamを更新してくれます。\nabc[3]; // Listと同様にインデックス番号3の値を取得してくれます。\n\n\n// 等価演算子はRx型と元の型でも動作しますが、.hashCode は常にvalueから取得します。\nfinal number = 12.obs;\nprint( number == 12 ); // true\n\n/// カスタムのRxモデル\n\n// toJson()やtoString()をモデルクラスに設定すれば、.obsからでもprintされるように実装可能。\n\nclass User {\n    String name, last;\n    int age;\n    User({this.name, this.last, this.age});\n\n    @override\n    String toString() => '$name $last, $age years old';\n}\n\nfinal user = User(name: 'John', last: 'Doe', age: 33).obs;\n\n// `user` 自体はリアクティブですが、その中のプロパティはリアクティブではありません。\n// そのため、このようにプロパティの値を変更してもWidgetは更新されません。\nuser.value.name = 'Roi';\n// `Rx` には自ら変更を検知する手段がないからです。\n// そのため、カスタムクラスの場合はこのようにWidgetに変更を知らせる必要があります。\nuser.refresh();\n\n// もしくは `update()` メソッドを使用してください。\nuser.update((value){\n  value.name='Roi';\n});\n\nprint( user );\n```\n#### StateMixin\n\n`UI`の状態を管理するもう一つの手法として、`StateMixin<T>`を利用する方法があります。\ncontrollerクラスに`with`を使って`StateMixin<T>`を追加することで実装可能です。\n\n``` dart\nclass Controller extends GetController with StateMixin<User>{}\n```\n\n`change()`メソッドにより好きなタイミングで状態を変更することができます。\nこのようにデータと状態を渡すだけです。\n\n```dart\nchange(data, status: RxStatus.success());\n```\n\nRxStatus には以下のステータスが存在します。\n\n``` dart\nRxStatus.loading();\nRxStatus.success();\nRxStatus.empty();\nRxStatus.error('message');\n```\n\nステータスごとにUIを設定するにはこのようにします。\n\n```dart\nclass OtherClass extends GetView<Controller> {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n\n      body: controller.obx(\n        (state)=>Text(state.name),\n\n        // ローディング中はカスタムのインジケーターの設定も可能ですが、\n        // デフォルトで Center(child:CircularProgressIndicator()) となります。\n        onLoading: CustomLoadingIndicator(),\n        onEmpty: Text('No data found'),\n\n        // 同様にエラーWidgetはカスタム可能ですが、\n        // デフォルトは Center(child:Text(error)) です。\n        onError: (error)=>Text(error),\n      ),\n    );\n}\n```\n\n#### GetView\n\nこのWidgetは私のお気に入りです。とてもシンプルで扱いやすいですよ！\n\nこのWidgetを一言で表現すると、「controllerをgetterに持つ `const` な StatelessWidget」です。\n\n```dart\n class AwesomeController extends GetController {\n   final String title = 'My Awesome View';\n }\n\n  // controllerの `型` を渡すのを忘れずに！\n class AwesomeView extends GetView<AwesomeController> {\n   @override\n   Widget build(BuildContext context) {\n     return Container(\n       padding: EdgeInsets.all(20),\n       child: Text(controller.title), // `controller.なんとか` でアクセス\n     );\n   }\n }\n```\n\n#### GetResponsiveView\n\nGetViewをレスポンシブデザインに対応させたい場合はこのWidgetを継承してください。\n画面サイズやデバイスタイプなどの情報を持つ `screen` プロパティを保持しています。\n\n##### 使い方\n\nWidgetをビルドする方法は2つあります。\n\n- `builder` メソッドを使う。\n- `desktop`, `tablet`, `phone`, `watch` メソッドを使う。\n  画面サイズ、デバイスタイプに応じたWidgetがビルドされます。\n  たとえば画面が [ScreenType.Tablet] なら `tablet` メソッドが実行されます。\n  **注:** `alwaysUseBuilder` プロパティをfalseにする必要があります。\n\n`settings` プロパティでブレイクポイントを設定することもできます。\n\n![例](https://github.com/SchabanBo/get_page_example/blob/master/docs/Example.gif?raw=true)\nこの画面のコード\n[コード](https://github.com/SchabanBo/get_page_example/blob/master/lib/pages/responsive_example/responsive_view.dart)\n\n#### GetWidget\n\nこのWidgetはあまり知られておらず、使用するケースは稀です。\nGetViewとの違いは、Controllerを`キャッシュ`してくれる点です。\nこのキャッシュがあるため `const` にはできません。\n\n> それでは一体いつControllerをキャッシュする必要があるのかって？\n\nそれは **GetX** のこれまた使う機会の少ない `Get.create()` を使うときです。\n\n`Get.create(()=>Controller())` は `Get.find<Controller>()` を実行するたびに\n新しいControllerインスタンスを生成します。\n\nそこで `GetWidget` の出番です。たとえば、Todoアイテムのリスト内容を保持したいとき。\nWidgetが更新されてもアイテムはControllerのキャッシュを参照してくれます。\n\n#### GetxService\n\nこのクラスは `GetxController` に似ており、同様のライフサイクル（`onInit()`, `onReady()`, `onClose()`）を共有しますが、そこに「ロジック」はありません。**GetX**の依存オブジェクト注入システムに、このサブクラスがメモリから **削除できない** ということを知らせるだけです。\n\nそのため `Get.find()` で `ApiService`, `StorageService`, `CacheService` のようなサービス系クラスにいつでもアクセスできるようにしておくと非常に便利です。\n\n```dart\nFuture<void> main() async {\n  await initServices(); /// サービスクラスの初期化をawait\n  runApp(SomeApp());\n}\n\n/// Flutterアプリ実行前にサービスクラスを初期化してフローをコントロールするのは賢いやり方です。\n/// たとえば GetMaterialAppを更新する必要がないようにUser別の\n/// Theme、apiKey、言語設定などをApiサービス実行前にロードしたり。\nvoid initServices() async {\n  print('starting services ...');\n  /// get_storage, hive, shared_pref の初期化はここで行います。\n  /// あるいは moor の connection など非同期のメソッドならなんでも。\n  await Get.putAsync(() => DbService().init());\n  await Get.putAsync(SettingsService()).init();\n  print('All services started...');\n}\n\nclass DbService extends GetxService {\n  Future<DbService> init() async {\n    print('$runtimeType delays 2 sec');\n    await 2.delay();\n    print('$runtimeType ready!');\n    return this;\n  }\n}\n\nclass SettingsService extends GetxService {\n  void init() async {\n    print('$runtimeType delays 1 sec');\n    await 1.delay();\n    print('$runtimeType ready!');\n  }\n}\n\n```\n\n`GetxService` を破棄する唯一の方法は `Get.reset()` メソッドを使うことです。\nこれはアプリにおける「ホットリブート」のようなものです。あるクラスのインスタンスを\nライフサイクルの間ずっと残しておきたい場合は `GetxService` を使うというのを覚えておいてください。\n\n\n## テストの実行\n\nControllerのライフサイクル含め、他のクラスと同様にテストを実行することができます。\n\n```dart\nclass Controller extends GetxController {\n  @override\n  void onInit() {\n    super.onInit();\n    // 値を name2 に変更\n    name.value = 'name2';\n  }\n\n  @override\n  void onClose() {\n    name.value = '';\n    super.onClose();\n  }\n\n  final name = 'name1'.obs;\n\n  void changeName() => name.value = 'name3';\n}\n\nvoid main() {\n  test('''\nTest the state of the reactive variable \"name\" across all of its lifecycles''',\n      () {\n    /// ライフサイクルごとのテストは必ずしも行う必要はありませんが、\n    /// GetXの依存オブジェクト注入機能を使用しているのであれば実行をおすすめします。\n    final controller = Controller();\n    expect(controller.name.value, 'name1');\n\n    /// このようにライフサイクル経過ごとの状態をテスト可能です。\n    Get.put(controller); // onInit が実行される\n    expect(controller.name.value, 'name2');\n\n    /// 関数もテストしましょう\n    controller.changeName();\n    expect(controller.name.value, 'name3');\n\n    /// onClose が実行される\n    Get.delete<Controller>();\n\n    expect(controller.name.value, '');\n  });\n}\n```\n\n#### mockitoやmocktailを使う場合\nGetxController/GetxService をモックする場合 Mock をミックスインしてください。\n\n```dart\nclass NotificationServiceMock extends GetxService with Mock implements NotificationService {}\n```\n\n#### Get.reset()\nWidgetやGroupのテスト時に、テストの最後かtearDownの中で Get.reset() を実行することで設定をリセットすることができます。\n\n#### Get.testMode\nControllerの中でナビゲーションを使用している場合は、`Get.testMode = true`をmainの開始で実行してください。\n\n\n# バージョン2.0からの破壊的変更\n\n1- Rx型の名称\n\n| 変更前  | 変更後     |\n| ------- | ---------- |\n| StringX | `RxString` |\n| IntX    | `RxInt`    |\n| MapX    | `RxMap`    |\n| ListX   | `RxList`   |\n| NumX    | `RxNum`    |\n| DoubleX | `RxDouble` |\n\nRxControllerとGetBuilderが統合され、Controllerにどれを使うか覚えておく必要がなくなりました。GetxControllerを使うだけで、リアクティブと非リアクティブな状態管理の両方に対応できるようになりました。\n\n2- 名前付きRoute\n変更前:\n\n```dart\nGetMaterialApp(\n  namedRoutes: {\n    '/': GetRoute(page: Home()),\n  }\n)\n```\n\n変更後:\n\n```dart\nGetMaterialApp(\n  getPages: [\n    GetPage(name: '/', page: () => Home()),\n  ]\n)\n```\n\n変更の効果:\nページ表示にはパラメータやログイントークンを起点にする方法もありますが、以前のアプローチではこれができず、柔軟性に欠けていました。\nページを関数から取得するよう変更したことで、このようなアプローチを可能にし、アプリ起動直後にRouteがメモリに割り当てられることもないため、RAMの消費量を大幅に削減することもできました。\n\n```dart\n\nGetStorage box = GetStorage();\n\nGetMaterialApp(\n  getPages: [\n    GetPage(name: '/', page:(){\n      return box.hasData('token') ? Home() : Login();\n    })\n  ]\n)\n```\n\n# なぜGetXなのか\n\n1- Flutterのアップデートが重なると、依存パッケージがうまく動かなくなることがあります。コンパイルエラーを起こしたり、その時点で解決方法がないようなエラーが発生したり。開発者はそのエラーを追跡し、該当リポジトリにissueを提起し、問題が解決されるのを待つ必要があります。Getは開発に必要な主要リソース（状態管理、依存オブジェクト管理、Route管理）を一元化し、Pubspecにパッケージを1つ追加するだけでコーディングを開始することができます。Flutterがアップデートしたときに必要なことは、Getも併せてアップデートすることだけです。それですぐに作業を再開できます。またGetはパッケージ間の互換性の問題も解消します。互いに依存するパッケージAの最新バージョンとBの最新バージョンの間に互換性がない、ということが何度あったでしょうか。Getを使えばすべてが同じパッケージ内にあるため、互換性の心配はありません。\n\n2- Flutterは手軽で素晴らしいフレームワークですが、`Navigator.of(context).push (context, builder [...]`のように、ほとんどの開発者にとって不要な定型文が一部にあります。Getを使えばそのような定型文を簡素化できます。Routeを呼ぶためだけに8行のコードを書く代わりに、`Get.to(Home())`を実行すれば、次の画面に遷移することができるのです。またウェブURLを動的なものにすることは現在Flutterでは本当に骨の折れる作業ですが、GetXを使えば非常に簡単です。そしてFlutterにおける状態管理と依存オブジェクト管理については、たくさんのパターンやパッケージがあるので多くの議論を生んでいます。しかしGetXのアプローチは大変シンプルです。これは一例ですが、変数の最後に「.obs」を追加して「Obx()」の中にWidgetを配置するだけで、その変数の状態変化が自動でWidgetに反映されます。\n\n3- GetXではパフォーマンスのことをあまり気にせず開発ができます。Flutterのパフォーマンスはそれだけで素晴らしいものですが、状態管理と併せて BLoC / データストア / Controller などを届けるためのサービスロケーターを使用することを想像してみてください。そのインスタンスが必要ないときはリソースを解放するイベントを明示的に呼び出さなければなりません。そんなとき、使用されなくなったら自動でメモリから削除してくれればいいのに、と考えたことはありませんか？それを実現してくれるのがGetXです。SmartManagement機能により未使用のリソースはすべて自動でメモリから破棄されるので、本来の開発作業に集中することができます。メモリ管理のためのロジックを作らなくても、常に必要最小限のリソースを使っていることが保証されるのです。\n\n4- コードのデカップリング（分離）がしやすい。「ビューをビジネスロジックから分離する」というコンセプトを聞いたことがあるかもしれません。これはなにもBLoC、MVC、MVVMに限ったことではなく、どのアーキテクチャパターンもこのコンセプトが考え方の基本にあると言っていいでしょう。しかし、Flutterではcontextの使用によりこのコンセプトが薄まってしまいがちです。\nInheritedWidgetを参照するためにcontextが必要なとき、ビューの中でそれを使用するか、引数としてcontextを渡しますよね？私はこの方法は美しくないと感じます。常にビュー内のビジネスロジックに依存しなければならないのは、特にチームで仕事をする場面においては不便だと感じます。GetXによるアプローチでは、StatefulWidgetやinitStateなどの使用を禁止しているわけではありませんが、それらよりもずっとスッキリ書けるようになっています。Controller自体にライフサイクルがあるため、たとえばREST APIのリクエストを行うときも、ビューの中の何かに依存するということがありません。Controllerのライフサイクルの一つである onInit を使用してhttpを呼び出し、データが到着すると変数にセットされます。GetXはリアクティブな変数を扱うことができるので、インスタンス変数が変わりし次第、その変数に依存するWidgetがすべて自動更新されます。これによりUIの担当者はWidgetの見た目に注力することができ、ボタンクリックなどのユーザーイベント以外のものをビジネスロジックに渡す必要がなくなります。その一方でビジネスロジックの担当者はビジネスロジックだけに集中し、個別のテストを簡単に行うことができます。\n\nGetXライブラリは今後も更新され続け、新しい機能を実装していきます。気軽にプルリクエストを出していただき、ライブラリの成長に貢献していただけるとうれしいです。\n\n# コミュニティ\n\n## コミュニティチャンネル\n\nGetXコミュニティは非常に活発で有益な情報であふれています。ご質問がある場合や、このフレームワークの使用に関して支援が必要な場合は、ぜひコミュニティチャンネルにご参加ください。このリポジトリは、issueの提起およびリクエスト専用ですが、気軽にコミュニティにご参加いただければ幸いです。\n\n| **Slack**                                                                                                                   | **Discord**                                                                                                                 | **Telegram**                                                                                                          |\n| :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------- |\n| [![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) |\n\n## コントリビュート方法\n\n_GetXプロジェクトに貢献してみませんか？あなたをコントリビューターの一人としてご紹介できるのを楽しみにしています。GetおよびFlutterをより良いものにするためのコントリビュート例をご紹介します。_\n\n- Readmeの多言語対応。\n- Readmeの追加ドキュメント執筆 (ドキュメントで触れられていない機能がまだまだたくさんあります)。\n- Getの使い方を紹介する記事やビデオの作成（Readmeに掲載させていただきます。将来的にWikiができればそこにも掲載予定）。\n- コードやテストのプルリクエスト。\n- 新機能の提案。\n\nどのような形の貢献であれ歓迎しますので、ぜひコミュニティにご参加ください！\n\n## GetXに関する記事と動画\n\n- [Flutter Getx EcoSystem package for arabic people](https://www.youtube.com/playlist?list=PLV1fXIAyjeuZ6M8m56zajMUwu4uE3-SL0) - Tutorial by [Pesa Coder](https://github.com/UsamaElgendy).\n- [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).\n- [Complete GetX™ Navigation](https://www.youtube.com/watch?v=RaqPIoJSTtI) - Route management video by Amateur Coder.\n- [Complete GetX State Management](https://www.youtube.com/watch?v=CNpXbeI_slw) - State management video by Amateur Coder.\n- [GetX™ Other Features](https://youtu.be/ttQtlX_Q0eU) - Utils, storage, bindings and other features video by Amateur Coder.\n- [Firestore User with GetX | Todo App](https://www.youtube.com/watch?v=BiV0DcXgk58) - Video by Amateur Coder.\n- [Firebase Auth with GetX | Todo App](https://www.youtube.com/watch?v=-H-T_BSgfOE) - Video by Amateur Coder.\n- [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).\n- [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).\n- [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.\n- [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.\n- [GetX Flutter Firebase Auth Example](https://medium.com/@jeffmcmorris/getx-flutter-firebase-auth-example-b383c1dd1de2) - Article by Jeff McMorris.\n- [Flutter State Management with GetX – Complete App](https://www.appwithflutter.com/flutter-state-management-with-getx/) - by App With Flutter.\n- [Flutter Routing with Animation using Get Package](https://www.appwithflutter.com/flutter-routing-using-get-package/) - by App With Flutter.\n- [A minimal example on dartpad](https://dartpad.dev/2b3d0d6f9d4e312c5fdbefc414c1727e?) - by [Roi Peker](https://github.com/roipeker)\n"
  },
  {
    "path": "README.ko-kr.md",
    "content": "![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png)\n\n[![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)\n[![popularity](https://badges.bar/get/popularity)](https://pub.dev/packages/sentry/score)\n[![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)\n[![pub points](https://badges.bar/get/pub%20points)](https://pub.dev/packages/get/score)\n![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)\n[![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart)\n[![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N)\n[![Get on Slack](https://img.shields.io/badge/slack-join-orange.svg)](https://communityinviter.com/apps/getxworkspace/getx)\n[![Telegram](https://img.shields.io/badge/chat-on%20Telegram-blue.svg)](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g)\n<a href=\"https://github.com/Solido/awesome-flutter\">\n<img alt=\"Awesome Flutter\" src=\"https://img.shields.io/badge/Awesome-Flutter-blue.svg?longCache=true&style=flat-square\" />\n</a>\n<a href=\"https://www.buymeacoffee.com/jonataslaw\" target=\"_blank\"><img src=\"https://i.imgur.com/aV6DDA7.png\" alt=\"Buy Me A Coffee\" style=\"height: 41px !important;width: 174px !important; box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;\" > </a>\n\n![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/getx.png)\n\n\n<div align=\"center\">\n\n**Languages:**\n\n  \n[![영어](https://img.shields.io/badge/Language-English-blueviolet?style=for-the-badge)](README.md)\n[![베트남어](https://img.shields.io/badge/Language-Vietnamese-blueviolet?style=for-the-badge)](README-vi.md)\n[![인도네시아어](https://img.shields.io/badge/Language-Indonesian-blueviolet?style=for-the-badge)](README.id-ID.md)\n[![우르두어](https://img.shields.io/badge/Language-Urdu-blueviolet?style=for-the-badge)](README.ur-PK.md)\n[![중국어](https://img.shields.io/badge/Language-Chinese-blueviolet?style=for-the-badge)](README.zh-cn.md)\n[![포르투칼어](https://img.shields.io/badge/Language-Portuguese-blueviolet?style=for-the-badge)](README.pt-br.md)\n[![스페인어](https://img.shields.io/badge/Language-Spanish-blueviolet?style=for-the-badge)](README-es.md)\n[![러시아어](https://img.shields.io/badge/Language-Russian-blueviolet?style=for-the-badge)](README.ru.md)\n[![폴란드어](https://img.shields.io/badge/Language-Polish-blueviolet?style=for-the-badge)](README.pl.md)\n[![한국어](https://img.shields.io/badge/Language-Korean-blueviolet?style=for-the-badge)](README.ko-kr.md)\n[![프랑스어](https://img.shields.io/badge/Language-French-blueviolet?style=for-the-badge)](README-fr.md)\n\n</div>\n\n- [Get에 대하여](#get에-대하여)\n- [설치](#설치)\n- [GetX를 사용한 Counter 앱](#getx를-사용한-counter-앱)\n- [세가지 주요점](#세가지-주요점)\n  - [상태 관리](#상태-관리)\n    - [반응형 상태 관리자](#반응형-상태-관리자)\n    - [상태 관리에 대한 자세한 내용](#상태-관리에-대한-자세한-내용)\n  - [라우트 관리](#라우트-관리)\n    - [라우트 관리에 대한 자세한 내용](#라우트-관리에-대한-자세한-내용)\n  - [종속성 관리](#종속성-관리)\n    - [종속성 관리에 대한 자세한 내용](#종속성-관리에-대한-자세한-내용)\n- [기능들](#기능들)\n  - [국제화](#국제화)\n    - [번역](#번역)\n      - [번역 사용법](#번역-사용법)\n    - [지역화](#지역화)\n      - [지역 변경](#지역-변경)\n      - [시스템 지역](#시스템-지역)\n  - [테마 변경](#테마-변경)\n  - [GetConnect](#getconnect)\n    - [기본 구성](#기본-구성)\n    - [커스텀 구성](#커스텀-구성)\n  - [GetPage Middleware](#getpage-middleware)\n    - [Priority](#priority)\n    - [Redirect](#redirect)\n    - [onPageCalled](#onpagecalled)\n    - [OnBindingsStart](#onbindingsstart)\n    - [OnPageBuildStart](#onpagebuildstart)\n    - [OnPageBuilt](#onpagebuilt)\n    - [OnPageDispose](#onpagedispose)\n  - [기타 고급 API](#기타-고급-api)\n    - [선택적 전역 설정과 수동 구성](#선택적-전역-설정과-수동-구성)\n    - [지역 상태 위젯들](#지역-상태-위젯들)\n      - [ValueBuilder](#valuebuilder)\n      - [ObxValue](#obxvalue)\n  - [유용한 팁](#유용한-팁)\n      - [GetView](#getview)\n      - [GetResponsiveView](#getresponsiveview)\n        - [사용 방법](#사용-방법)\n      - [GetWidget](#getwidget)\n      - [GetxService](#getxservice)\n- [2.0의 주요 변경점](#20의-주요-변경점)\n- [왜 Getx인가?](#왜-getx인가)\n- [커뮤니티](#커뮤니티)\n  - [커뮤니티 채널](#커뮤니티-채널)\n  - [기여하는 방법](#기여하는-방법)\n  - [기사 및 비디오](#기사-및-비디오)\n\n# Get에 대하여\n\n- GetX는 Flutter를 위한 매우 가볍고 강력한 솔루션입니다. 고성능 상태 관리, 지능형 종속성 주입 및 빠르고 실용적인 라우트 관리가 결합되어 있습니다.\n\n- GetX는 라이브러리의 모든 사항에 대해서 **생산성, 성능, 조직화**의 3 가지 기본 원칙을 가지고 있습니다.\n\n  - **성능:** GetX는 성능과 최소한의 리소스 소비에 중점을 둡니다. GetX는 Streams나 ChangeNotifier를 사용하지 않습니다.\n  \n  - **생산성:** GetX는 쉽고 친숙한 구문을 사용합니다. 원하시는 것보다 Getx에는 항상 더 쉬운 방법이 있습니다. 개발 시간을 아끼고 애플리케이션을 최대 성능으로 제공할 수 있습니다. \n\n  일반적으로 개발자는 메모리에서 컨트롤러들을 제거하는 데 관심을 가져야합니다. GetX에서는 리소스가 기본적으로 사용되지 않으면 메모리에서 제거되므로 필요하지 않습니다. 만약 메모리에 유지하려면 종속성에서 \"permanent : true\"를 명시적으로 선언해야합니다. 이렇게하면 시간을 절약 할 수있을뿐만 아니라 불필요한 메모리 종속성이 발생할 위험이 줄어 듭니다. 종속성은 기본적으로 lazy로 로드됩니다.\n  \n  - **조직화:** GetX는 화면, 프레젠테이션 로직, 비즈니스 로직, 종속성 주입 및 네비게이션을 완전히 분리 할 수 있습니다. 라우트간 전환을 하는데에 컨텍스트가 필요하지 않아 위젯 트리(시각객체)에 독립적입니다. inheritedWidget을 통해 컨트롤러/블록에 접근하는 데 컨텍스트가 필요하지 않아 시각화 계층에서 프레젠테이션 로직과 비즈니스 로직을 완전히 분리됩니다. 이 GetX는 자체 종속성 주입 기능을 사용하여 DI를 뷰에서 완전히 분리하기 때문에 다중 Provider를 통해 위젯 트리에서 컨트롤러/모델/블록으로 주입 할 필요가 없습니다.\n\n  GetX를 사용하면 기본적으로 클린 코드를 가지게 되어 애플리케이션의 각 기능을 쉽게 찾을 수 있습니다. 이것은 유지 보수를 용이하게 하며 모듈의 공유가 가능하고 Flutter에서는 생각할 수 없었던 것들도 전부 가능합니다.\n  BLoC은 Flutter에서 코드를 구성하기 위한 시작점으로 비즈니스 로직과 시각객체를 분리합니다. Getx는 비즈니스 로직 뿐만 아니라 프레젠테이션 로직을 분리하는 자연스러운 진화입니다. 추가로 종속성 주입과 라우트 또한 분리되고 데이터 계층이 모두로부터 분리됩니다. Hello World를 구현하는 것보다 더 쉽게 모든 것이 어디 있는지 알수 있습니다.  \n  Flutter SDK와 함께 GetX를 사용하면 가장 쉽고 실용적이며 확장 가능한 고성능 어플리케이션을 만들수 있습니다. 초보자에게는 쉬우며 전문가에게는 정확하고 완벽하게 동작하는 대규모 생태계가 함께합니다. 안전하고 안정적이며 업데이트되고 기본 Flutter SDK에 없는 광범위한 API 빌드를 제공합니다.\n\n- GetX는 비대하지 않습니다. 아무 걱정없이 프로그래밍을 시작할 수 있는 다양한 기능이 있지만 각 기능은 별도의 컨테이너에 있으며 사용한 후에만 시작됩니다. 만약 상태 관리만 사용하면 오직 상태 관리만 컴파일 됩니다. 라우트만 사용하는 경우 상태 관리는 컴파일되지 않습니다.\n\n- GetX는 거대한 생태계, 대규모 커뮤니티, 수많은 공동 작업자를 보유하고 있으며 Flutter가 존재하는 한 유지됩니다. GetX도 Android, iOS, 웹, Mac, Linux, Windows 및 서버에서 동일한 코드로 실행할 수 있습니다.\n**[Get Server](https://github.com/jonataslaw/get_server)를 사용한 백엔드에는 프런트엔드에서 만든 코드를 완전히 재사용 할 수 있습니다.**\n\n**추가로 [Get CLI](https://github.com/jonataslaw/get_cli)를 프런트엔드와 서버 양쪽에서 사용하면 전체 개발 프로세스를 자동화 할 수 있습니다.**\n\n**추가로 생산성 향상을 위해 \n[VSCode 확장](https://marketplace.visualstudio.com/items?itemName=get-snippets.get-snippets)과 [Android Studio/Intellij 확장](https://plugins.jetbrains.com/plugin/14975-getx-snippets)이 있습니다.**\n\n# 설치\n\npubspec.yaml 파일에 Get 추가:\n\n```yaml\ndependencies:\n  get:\n```\n\n사용할 파일에 Import get:\n\n```dart\nimport 'package:get/get.dart';\n```\n\n# GetX를 사용한 Counter 앱\n\nFlutter의 새 프로젝트에서 기본적으로 생성 되는 \"counter\" 프로젝트는 100줄이 넘습니다 (코멘트 포함). Get의 강력함을 보여주기 위해 클릭 할 때마다 상태를 변경하고, 페이지 사이를 전환하고, 화면 사이의 상태를 공유하는 \"counter\"를 만드는 방법을 주석이 포함된 26줄의 코드로 보여줄 것입니다.\n\n- 1 단계:\n  MaterialApp 에 \"Get\"을 추가하여 GetMaterialApp 으로 변경합니다.\n\n```dart\nvoid main() => runApp(GetMaterialApp(home: Home()));\n```\n\n- 주석: 이는 Flutter의 MaterialApp을 변경하지 않으며 GetMaterialApp 또한 수정 된 MaterialApp이 아니고, 기본 MaterialApp을 자식으로 갖는 사전 구성된 위젯 일뿐입니다. 수동으로 구성 할 수 있지만 반드시 필요한 것은 아닙니다. GetMaterialApp은 라우트를 생성하고 추가하며, 번역을 추가하고, 라우트 탐색에 필요한 모든 것을 추가합니다. 만약 상태 관리 또는 종속성 관리에만 Get을 사용하는 경우 GetMaterialApp을 사용할 필요가 없습니다. GetMaterialApp은 라우트, 스택바, 국제화, bottomSheets, 다이얼로그 및 컨텍스트 부재와 라우트에 연관된 상위 api들에 필요합니다.\n- 주석²: 이 단계는 라우트 관리 (`Get.to ()`,`Get.back ()` 등)를 사용하려는 경우에만 필요합니다. 사용하지 않을 경우 1 단계를 수행 할 필요가 없습니다.\n\n- 2 단계:\n  비즈니스 로직 클래스를 만들고 모든 변수, 함수, 컨트롤러를 포함하십시오.\n  \".obs\"를 이용하면 간단히 모든 변수를 observable로 만들수 있습니다.\n\n```dart\nclass Controller extends GetxController{\n  var count = 0.obs;\n  increment() => count++;\n}\n```\n\n- 3 단계:\n  StatelessWidget를 이용해 View를 만들어 RAM을 아끼고 StatefulWidget은 더 이상 사용하지 않아도 됩니다.\n\n```dart\nclass Home extends StatelessWidget {\n\n  @override\n  Widget build(context) {\n\n    // Get.put()을 사용하여 클래스를 인스턴스화하여 모든 \"child'에서 사용가능하게 합니다.\n    final Controller c = Get.put(Controller());\n    \n    return Scaffold(\n      // count가 변경 될 때마다 Obx(()=> 를 사용하여 Text()에 업데이트합니다.\n      appBar: AppBar(title: Obx(() => Text(\"Clicks: ${c.count}\"))),\n\n      // 8줄의 Navigator.push를 간단한 Get.to()로 변경합니다. context는 필요없습니다.\n      body: Center(child: ElevatedButton(\n              child: Text(\"Go to Other\"), onPressed: () => Get.to(Other()))),\n      floatingActionButton:\n          FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment));\n  }\n}\n\nclass Other extends StatelessWidget {\n  // 다른 페이지에서 사용되는 컨트롤러를 Get으로 찾아서 redirect 할 수 있습니다.\n  final Controller c = Get.find();\n\n  @override\n  Widget build(context){\n     // 업데이트된 count 변수에 연결\n     return Scaffold(body: Center(child: Text(\"${c.count}\")));\n  }\n}\n```\n\n결론:\n\n![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/counter-app-gif.gif)\n\n이것은 간단한 프로젝트 이지만 Get이 얼마나 강력한지 명확히 보여줍니다. 프로젝트가 성장하면 차이점이 더 커질 것 입니다.\n\nGet은 팀단위 업무에 맞춰 디자인되었지만 개별 개발자의 작업도 단순화합니다.\n\n마감일을 개선하고 성능의 손실 없이 재시간에 제공하십시오. Get은 모두를 위한 것은 아니지만 위의 설명에 해당사항이 있으면 당신을 위한 것입니다!\n\n# 세가지 주요점\n\n## 상태 관리\n\nGet은 두가지 상태 관리자가 있습니다: 단순 상태관리자(GetBuilder라고 함)와 반응형 상태관리자(GetX/Obx)\n\n### 반응형 상태 관리자\n\n반응형 프로그래밍은 복잡하다고 알려져있기 때문에 많은 사람들에게 소외될 수 있습니다. GetX가 매우 단순하게 반응형 프로그래밍을 바꿉니다:\n\n- StreamControllers를 만들 필요가 없습니다.\n- 각 변수에 대해 StreamBuilder를 만들 필요가 없습니다.\n- 각각의 상태(state)를 위한 클래스를 만들 필요가 없습니다.\n- 초기값을 위한 get이 필요하지 않습니다.\n- 코드 생성기를 사용할 필요가 없습니다.\n\nGet의 반응형 프로그램은 setState를 사용하는 것 만큼 쉽습니다.\n\n매번 변경되기를 원하고 모든 위젯에서 자동적으로 반영되는 변수가 있다고 가정해봅시다.\n\n여기 name 변수가 있습니다:\n\n```dart\nvar name = 'Jonatas Borges';\n```\n\n\".obs\"만 끝에 추가하여 observable로 만듭니다:\n\n```dart\nvar name = 'Jonatas Borges'.obs;\n```\n\n아래와 같이 간단히 보여주고 싶은 UI에 추가하면 값이 변경될때마다 화면에 업데이트 됩니다:\n\n```dart\nObx(() => Text(\"${controller.name}\"));\n```\n\n이게 다 입니다. _정말_ 간단하죠.\n\n### 상태 관리에 대한 자세한 내용\n\n**상태 관리에 대한 자세한 설명은 [여기](./documentation/kr_KO/state_management.md)를 보십시오. 여기에서 더 많은 예제와 단순 상태 관리자와 반응형 상태 관리자의 차이점을 볼 수 있습니다.**\n\nGetX 능력에 대한 좋은 아이디어를 얻을 수 있습니다.\n\n## 라우트 관리\n\n만약 라우트/스낵바/다이얼로그/bottomsheets을 context 없이 사용하려면 GetX는 훌륭한 대안입니다. 여기를 보십시오:\n\nMaterialApp 앞에 \"Get\"을 추가해서 GetMaterialApp으로 변경합니다.\n\n```dart\nGetMaterialApp( // Before: MaterialApp(\n  home: MyHome(),\n)\n```\n\n새로운 화면으로 이동합니다:\n\n```dart\n\nGet.to(NextScreen());\n```\n\n명칭으로 새로운 화면으로 이동합니다. 명칭으로 라우트하는 더 자세한 사항은 [여기](./documentation/kr_KO/route_management.md#이름있는-라우트-탐색) 있습니다.\n\n```dart\n\nGet.toNamed('/details');\n```\n\n스낵바, 다이얼로그, bottomsheets 또는 Navigator.pop(context);로 닫아야 하는 어떤것도 닫게 합니다:\n\n```dart\nGet.back();\n```\n\n다음 화면으로 이동하고 이전 화면으로 돌아갈 필요가 없는 경우 (스플래시, 로그인화면 등..)\n\n```dart\nGet.off(NextScreen());\n```\n\n다음 화면으로 이동하고 이전 화면들 모두 닫는 경우 (쇼핑카트, 투표, 테스트에 유용)\n\n```dart\nGet.offAll(NextScreen());\n```\n\n이러한 작업을 수행하기 위해 컨텍스트를 사용할 필요가 없다는 것을 보셨나요? 이것이 Get 라우트 관리를 사용하는 가장 큰 장점 중 하나입니다. 이를 통해 걱정없이 컨트롤러 클래스 내에서 이러한 모든 메서드를 실행할 수 있습니다.\n\n### 라우트 관리에 대한 자세한 내용\n\n**Get은 명명된 라우트로 작업하고 더 쉬운 방식으로 라우트의 제어를 제공합니다! [여기](./documentation/kr_KO/route_management.md)에 더 자세한 문서가 있습니다.**\n\n## 종속성 관리\n\nGet은 간단하고 강력한 종속성 관리자를 가지고 있어 Bloc나 Controller와 유사한 클래스를 Provide context, inheritedWidget 없이 1줄의 코드로 끌어낼 수 있습니다:\n\n```dart\nController controller = Get.put(Controller()); // Rather Controller controller = Controller();\n```\n\n- 주석: Get의 상태 관리자를 사용중이면 뷰를 controller에 더 쉽게 연결할 수 있는 바인딩 api에 더 주의를 기울이십시오.\n\n사용 중인 클래스에서 클래스를 인스턴스화하는 대신에 Get 인스턴스에서 인스턴스화하면 앱에서 해당 클래스를 사용할 수 있습니다.\n그래서 controller(또는 Bloc)를 정상적으로 사용할 수 있습니다.\n\n**팁:** Get 종속성 관리는 패키지의 다른 부분과 분리되어서 예제 앱이 이미 상태 관리자(하나여도 상관없음)를 사용중이면 모두 다시 작성할 필요 없이 아무 문제 없이 종속성 주입을 사용할 수 있습니다.\n\n```dart\ncontroller.fetchApi();\n```\n\n여러 경로들을 탐색했고 controller에 남아있는 데이터가 필요가 있다고 가정하십시오. Get_it이나 Provider와 조합된 상태 관리자가 필요합니다. 맞습니까? Get은 아닙니다. 다른 추가적인 종속성이 필요없이 controller를 Get의 \"find\"로 찾으면 됩니다:\n\n```dart\nController controller = Get.find();\n//마법처럼 Get이 controller를 찾아서 가져올 것 입니다. 백만개의 인스턴스화 contrller를 가질수 있고 Get은 올바른 controller를 항상 가져다 줄 것입니다.\n```\n\n그리고나서 가져온 controller 데이터를 사용할 수 있습니다:\n\n```dart\nText(controller.textFromApi);\n```\n\n### 종속성 관리에 대한 자세한 내용\n\n**종속성 관리에 대한 더 자세한 사항은 [여기](./documentation/kr_KO/dependency_management.md)에 있습니다.**\n\n# 기능들\n\n## 국제화\n\n### 번역\n\n번역은 간단한 key-value 맵으로 유지됩니다.\n커스텀 번역을 추가하려면 `Translations`으로 확장하여 클래스를 만드세요.\n\n```dart\nimport 'package:get/get.dart';\n\nclass Messages extends Translations {\n  @override\n  Map<String, Map<String, String>> get keys => {\n        'en_US': {\n          'hello': 'Hello World',\n        },\n        'de_DE': {\n          'hello': 'Hallo Welt',\n        }\n      };\n}\n```\n\n#### 번역 사용법\n\n단지 `.tr`로 명시된 키만 추가하면 `Get.locale`과 `Get.fallbackLocale`의 현재값을 사용해서 번역될 것 입니다.\n\n```dart\nText('title'.tr);\n```\n\n#### 단수와 복수의 번역 사용법\n\n```dart\nvar products = [];\nText('singularKey'.trPlural('pluralKey', products.length, Args));\n```\n\n#### 파라미터로 번역 사용하는 방법\n\n```dart\nimport 'package:get/get.dart';\n\n\nMap<String, Map<String, String>> get keys => {\n    'en_US': {\n        'logged_in': 'logged in as @name with email @email',\n    },\n    'es_ES': {\n       'logged_in': 'iniciado sesión como @name con e-mail @email',\n    }\n};\n\nText('logged_in'.trParams({\n  'name': 'Jhon',\n  'email': 'jhon@example.com'\n  }));\n```\n\n### 지역화\n\n`GetMaterialApp`의 파라미터를 전달하여 지역과 번역어를 정의합니다.\n\n```dart\nreturn GetMaterialApp(\n    translations: Messages(), // 번역들\n    locale: Locale('en', 'US'), // 해당 지역의 번역이 표시\n    fallbackLocale: Locale('en', 'UK'), // 잘못된 지역이 선택된 경우 복구될 지역을 지정\n);\n```\n\n#### 지역 변경\n\n지역을 업데이트할때 `Get.updateLocale(locale)`를 콜하십시오. 새로운 지역을 사용하여 자동적으로 번역합니다.\n\n```dart\nvar locale = Locale('en', 'US');\nGet.updateLocale(locale);\n```\n\n#### 시스템 지역\n\n`Get.deviceLocale`를 사용해서 시스템 지역을 읽어옵니다.\n\n```dart\nreturn GetMaterialApp(\n    locale: Get.deviceLocale,\n);\n```\n\n## 테마 변경\n\n테마를 업데이트하기 위해 `GetMaterialApp` 보다 더 상위 위젯을 사용하지 말아 주십시오. 이러면 중복 키가 트리거 될 수 있습니다. 많은 사람들이 테마를 바꾸기 위해 \"ThemeProvider\" 위젯을 사용하고 있는데 **GetX**는 이런 방식이 필요 없습니다.\n\n다른 표준사항은 없이 `Get.changeTheme`로 추가하고 간단하게 커스텀 테마를 만들수 있습니다:\n\n```dart\nGet.changeTheme(ThemeData.light());\n```\n\n`onTap`에 테마 변경이 있는 버튼 같은 무언가를 만들고 싶다면 두개의 **GetX™** API를 조합하여 가능합니다:\n\n- 다크`테마`를 사용중인지 확인합니다.\n- 그리고 `테마` 변경 API 를 `onPressed`에 넣으면 됩니다:\n\n```dart\nGet.changeTheme(Get.isDarkMode? ThemeData.light(): ThemeData.dark());\n```\n\n`.darkmode`가 활성화 될때 _light theme_ 로 바뀔것 이고 _light theme_ 가 활성화되면 _dark theme_ 로 변경될 것입니다.\n\n## GetConnect\n\nGetConnect는 http나 websockets으로 프론트와 백엔드의 통신을 위한 쉬운 방법입니다.\n\n### 기본 구성\n\nGetConnect를 간단하게 확장하고 Rest API나 websockets의 GET/POST/PUT/DELETE/SOCKET 메서드를 사용할 수 있습니다.\n\n```dart\nclass UserProvider extends GetConnect {\n  // Get request\n  Future<Response> getUser(int id) => get('http://youapi/users/$id');\n  // Post request\n  Future<Response> postUser(Map data) => post('http://youapi/users', body: data);\n  // Post request with File\n  Future<Response<CasesModel>> postCases(List<int> image) {\n    final form = FormData({\n      'file': MultipartFile(image, filename: 'avatar.png'),\n      'otherFile': MultipartFile(image, filename: 'cover.png'),\n    });\n    return post('http://youapi/users/upload', form);\n  }\n\n  GetSocket userMessages() {\n    return socket('https://yourapi/users/socket');\n  }\n}\n```\n\n### 커스텀 구성\n\nGetConnect는 고도로 커스텀화 할 수 있습니다. base Url을 정의하고 응답자 및 요청을 수정하고 인증자를 정의할 수 있습니다. 그리고 인증 횟수까지 정의 할 수 있습니다. 더해서 추가 구성없이 모델로 응답을 변형시킬 수 있는 표준 디코더 정의도 가능합니다.\n\n```dart\nclass HomeProvider extends GetConnect {\n  @override\n  void onInit() {\n    // 모든 요청은 jsonEncode로 CasesModel.fromJson()를 거칩니다.\n    httpClient.defaultDecoder = CasesModel.fromJson;\n    httpClient.baseUrl = 'https://api.covid19api.com';\n    // baseUrl = 'https://api.covid19api.com';\n    // [httpClient] 인스턴트 없이 사용하는경우 Http와 websockets의 baseUrl 정의\n    \n    // 모든 요청의 헤더에 'apikey' 속성을 첨부합니다.\n    httpClient.addRequestModifier((request) {\n      request.headers['apikey'] = '12345678';\n      return request;\n    });\n\n    // 서버가 \"Brazil\"이란 데이터를 보내더라도\n    // 응답이 전달되기 전에 응답의 데이터를 지우기 때문에 \n    // 사용자에게 표시되지 않을 것입니다.\n    httpClient.addResponseModifier<CasesModel>((request, response) {\n      CasesModel model = response.body;\n      if (model.countries.contains('Brazil')) {\n        model.countries.remove('Brazilll');\n      }\n    });\n\n    httpClient.addAuthenticator((request) async {\n      final response = await get(\"http://yourapi/token\");\n      final token = response.body['token'];\n      // 헤더 설정\n      request.headers['Authorization'] = \"$token\";\n      return request;\n    });\n\n    // 인증자가 HttpStatus가 HttpStatus.unauthorized이면\n    // 3번 호출됩니다.\n    httpClient.maxAuthRetries = 3;\n  }\n  }\n\n  @override\n  Future<Response<CasesModel>> getCases(String path) => get(path);\n}\n```\n\n## GetPage Middleware\n\nGetPage는 GetMiddleWare의 목록을 특정 순서로 실행하는 새로운 프로퍼티를 가집니다.\n\n**주석**: GetPage가 Middleware를 가질때 페이지의 모든 하위는 같은 Middleware를 자동적으로 가지게 됩니다.\n\n### Priority\n\nMiddleware의 실행 순서는 GetMiddleware안의 priority에 따라서 설정할 수 있습니다.\n\n```dart\nfinal middlewares = [\n  GetMiddleware(priority: 2),\n  GetMiddleware(priority: 5),\n  GetMiddleware(priority: 4),\n  GetMiddleware(priority: -8),\n];\n```\n\n이 Middleware는 다음 순서로 실행됩니다. **-8 => 2 => 4 => 5**\n\n### Redirect\n\n이 함수는 호출된 라우트의 페이지를 검색할때 호출됩니다. 리다이렉트한 결과로 RouteSettings을 사용합니다. 또는 null을 주면 리다이렉트 하지 않습니다.\n\n```dart\nRouteSettings redirect(String route) {\n  final authService = Get.find<AuthService>();\n  return authService.authed.value ? null : RouteSettings(name: '/login')\n}\n```\n\n### onPageCalled\n\n이 함수는 생성되지 않은 페이지가 호출될 때 호출됩니다.\n페이지에 대한 어떤것을 변경하는데 사용하거나 새로운 페이지를 줄 수 있습니다.\n\n```dart\nGetPage onPageCalled(GetPage page) {\n  final authService = Get.find<AuthService>();\n  return page.copyWith(title: 'Welcome ${authService.UserName}');\n}\n```\n\n### OnBindingsStart\n\n이 함수는 Bindings가 초기화되기 바로 직전에 호출됩니다.\n여기에서 이 페이지를 위해 Bindings을 변경할 수 있습니다.\n\n```dart\nList<Bindings> onBindingsStart(List<Bindings> bindings) {\n  final authService = Get.find<AuthService>();\n  if (authService.isAdmin) {\n    bindings.add(AdminBinding());\n  }\n  return bindings;\n}\n```\n\n### OnPageBuildStart\n\n이 함수는 Bindings가 초기화된 직후에 호출됩니다.\n여기에서 bindings를 생성한 후 페이지 위젯을 생성하기 전에 무엇이든 할 수 있습니다.\n\n```dart\nGetPageBuilder onPageBuildStart(GetPageBuilder page) {\n  print('bindings are ready');\n  return page;\n}\n```\n\n### OnPageBuilt\n\n이 함수는 GetPage.page 함수가 호출된 직후에 호출며 함수의 결과를 제공합니다. 그리고 표시될 위젯을 가져옵니다.\n\n### OnPageDispose\n\n이 함수는 페이지의 연관된 모든 오브젝트들(Controllers, views, ...)이 해제된 직후에 호출됩니다.\n\n## 기타 고급 API\n\n```dart\n// currentScreen에서 현재 인수들을 제공\nGet.arguments\n\n// 이전 경로의 이름을 제공\nGet.previousRoute\n\n// rawRoute.isFirst()와 같은 접근에 필요한 원시 경로를 제공\nGet.rawRoute\n\n// GetObserver로 부터 Rounting API의 접근을 제공\nGet.routing\n\n// snackbar가 열려 있는지 확인\nGet.isSnackbarOpen\n\n// dialog가 열려 있는지 확인\nGet.isDialogOpen\n\n// bottomsheet가 열려 있는지 확인\nGet.isBottomSheetOpen\n\n// 1개의 경로 제거\nGet.removeRoute()\n\n// 값이 true가 될때까지 반복적으로 되돌림\nGet.until()\n\n// 다음 경로로 이동하고 값이 true가 될때까지 이전 모든 경로를 제거\nGet.offUntil()\n\n// 명명된 다음 경로로 이동하고 값이 true가 될때까지 이전 모든 경로를 제거\nGet.offNamedUntil()\n\n// 앱이 구동중인 플랫폼을 확인\nGetPlatform.isAndroid\nGetPlatform.isIOS\nGetPlatform.isMacOS\nGetPlatform.isWindows\nGetPlatform.isLinux\nGetPlatform.isFuchsia\n\n// 장치 타입을 확인\nGetPlatform.isMobile\nGetPlatform.isDesktop\n// 모든 플랫폼은 독립적으로 웹을 제공합니다!\n// Windows, iOS, OSX, Android 등의\n// 브러우저에서 구동중이면 알 수 있습니다.\nGetPlatform.isWeb\n\n\n// MediaQuery.of(context).size.height 과 동일\n// 하지만 불변함.\nGet.height\nGet.width\n\n// Navigator의 현재 context를 제공\nGet.context\n\n// 코드 어디에서든지 foreground에서 snackbar/dialog/bottomsheet의 context를 제공\nGet.contextOverlay\n\n// 주석: 다음 메서드는 context의 확장입니다.\n// UI의 모든 위치에서 컨텍스트에 액세스 할 수 있으므로 UI 코드의 어느 곳에서나 사용할 수 있습니다.\n\n// 변경되는 height/width(데스크탑이나 브라우저와 같이 늘어날 수 있는 것)가 필요하면 context를 사용해야함\ncontext.width\ncontext.height\n\n// 화면의 절반, 1/3 등을 정의할 수 있는 기능을 제공합니다.\n// 반응성이 높은 앱에 유용합니다.\n// param dividedBy (double) optional - default: 1\n// param reducedBy (double) optional - default: 0\ncontext.heightTransformer()\ncontext.widthTransformer()\n\n/// MediaQuery.of(context).size 와 유사함\ncontext.mediaQuerySize()\n\n/// MediaQuery.of(context).padding 와 유사함\ncontext.mediaQueryPadding()\n\n/// MediaQuery.of(context).viewPadding 와 유사함\ncontext.mediaQueryViewPadding()\n\n/// MediaQuery.of(context).viewInsets; 와 유사함\ncontext.mediaQueryViewInsets()\n\n/// MediaQuery.of(context).orientation; 와 유사함\ncontext.orientation()\n\n/// 장치의 가로 모드 확인\ncontext.isLandscape()\n\n/// 장치의 세로 모드 확인\ncontext.isPortrait()\n\n/// MediaQuery.of(context).devicePixelRatio; 와 유사함\ncontext.devicePixelRatio()\n\n/// MediaQuery.of(context).textScaleFactor; 와 유사함\ncontext.textScaleFactor()\n\n/// 화면에서 shortestSide를 제공\ncontext.mediaQueryShortestSide()\n\n/// True if width be larger than 800\ncontext.showNavbar()\n\n/// shortestSide가 600p 미만이면 True\ncontext.isPhone()\n\n/// shortestSide가 600p 이상이면 True\ncontext.isSmallTablet()\n\n/// shortestSide가 720p 이상이면 True\ncontext.isLargeTablet()\n\n/// 현재 장치가 Tablet이면 True\ncontext.isTablet()\n\n/// 화면 사이즈에 따라 value<T>를 반환\n/// 반환될 수 있는 값들:\n/// watch: shortestSide가 300 미만일 때\n/// mobile: shortestSide가 600 미만일 때\n/// tablet: shortestSide가 1200 미만일 때\n/// desktop: shortestSide가 1200 이상일 때\ncontext.responsiveValue<T>()\n```\n\n### 선택적 전역 설정과 수동 구성\n\nGetMaterialApp은 모든 것이 구성되어 있지만 원한다면 수동으로 Get을 구성할 수 있습니다.\n\n```dart\nMaterialApp(\n  navigatorKey: Get.key,\n  navigatorObservers: [GetObserver()],\n);\n```\n\n`GetObserver`안에 Middleware를 사용할 수 있고 이로 인한 어떤 영향도 없습니다.\n\n```dart\nMaterialApp(\n  navigatorKey: Get.key,\n  navigatorObservers: [\n    GetObserver(MiddleWare.observer) // Here\n  ],\n);\n```\n\n`Get`을 위한 _Global Settings_ 을 만들수 있습니다. 어떠한 라우트도 포함되기 전에 `Get.config`에 추가하십시오.\n또는 `GetMaterialApp`에 직접 추가 하십시오.\n\n```dart\nGetMaterialApp(\n  enableLog: true,\n  defaultTransition: Transition.fade,\n  opaqueRoute: Get.isOpaqueRouteDefault,\n  popGesture: Get.isPopGestureEnable,\n  transitionDuration: Get.defaultDurationTransition,\n  defaultGlobalState: Get.defaultGlobalState,\n);\n\nGet.config(\n  enableLog = true,\n  defaultPopGesture = true,\n  defaultTransition = Transitions.cupertino\n)\n```\n\n선택적으로 `Get`으로 모든 로그 메세지를 리다이렉트 할 수 있습니다.\n만약 유명한 로그 패키지를 사용하고 싶으면\n여기에서 원하는 로그가 있습니다:\n\n```dart\nGetMaterialApp(\n  enableLog: true,\n  logWriterCallback: localLogWriter,\n);\n\nvoid localLogWriter(String text, {bool isError = false}) {\n  // pass the message to your favourite logging package here\n  // please note that even if enableLog: false log messages will be pushed in this callback\n  // you get check the flag if you want through GetConfig.isLogEnable\n}\n\n```\n\n### 지역 상태 위젯들\n\n이러한 위젯은 단일값을 관리하고 지역적이고 임시적인 상태를 유지합니다.\n우리는 반응적이고 단순함을 위해 추가할 수 있습니다.\n예를 들어 `TextField`의 obscureText의 전환으로 사용하거나 \n커스텀된 확장되는 패널을 만들거나 \n`Scaffold`의 body가 변경되는 동안 `BottomNavigationBar`의 현재 index를 수정할 수 있습니다.\n\n#### ValueBuilder\n\n업데이트된 값을 되돌려 받는 `.setState`로 작동하는 `StatefulWidget`의 단순화 입니다.\n\n```dart\nValueBuilder<bool>(\n  initialValue: false,\n  builder: (value, updateFn) => Switch(\n    value: value,\n    onChanged: updateFn, // same signature! you could use ( newValue ) => updateFn( newValue )\n  ),\n  // if you need to call something outside the builder method.\n  onUpdate: (value) => print(\"Value updated: $value\"),\n  onDispose: () => print(\"Widget unmounted\"),\n),\n```\n\n#### ObxValue\n\n[`ValueBuilder`](#valuebuilder)와 비슷하지만 Rx 인스턴스(마법같은 .obs를 기억하세요)를 전달하고 \n자동적으로 업데이트되는 반응형 버전입니다... 놀랍지 않습니까?\n\n```dart\nObxValue((data) => Switch(\n        value: data.value,\n        onChanged: data, // Rx에는 호출가능한 함수가 있습니다! (flag) => data.value = flag, 가 사용가능 합니다.\n    ),\n    false.obs,\n),\n```\n\n## 유용한 팁\n\n`.obs`(_Rx_ 타입이라고 알려진)는 다양한 내부 메서드와 연산자가 있습니다.\n\n> `.obs`프로퍼티가 **실제 값**이라고 _믿는_ 것은 일반적이지만 실수하지 마십시오!\n> 다트의 컴파일러는 충분히 똑똑하고 코드가 깔끔하기 때문에 변수의 타입 선언을 하지 않습니다.\n> 하지만:\n\n```dart\nvar message = 'Hello world'.obs;\nprint( 'Message \"$message\" has Type ${message.runtimeType}');\n```\n\n`message`가 실제 String 값을 _출력_ 하더라도 타입은 **RxString**입니다!\n\n그래서 `message.substring( 0, 4 )`은 사용하지 못합니다.\n_observable(.obs)_ 안의 실제 값에 접근해야 합니다:\n가장 많이 사용되는 방법은 `.value`지만 사용할 수 있었는지 알고 있었나요...\n\n```dart\nfinal name = 'GetX'.obs;\n// 현재 값과 다른 값이면 stream을 업데이트만 합니다.\nname.value = 'Hey';\n\n// 모든 Rx 프로퍼티가 \"호출 가능\"하고 새로운 값을 반환합니다.\n// 하지만 이 접근방식은 `null`를 허용하지 않고 UI가 재구축하지 않습니다.\nname('Hello');\n\n// getter와 과 같이 'Hello'를 출력합니다.\nname() ;\n\n/// 숫자 타입들:\n\nfinal count = 0.obs;\n\n// 기존 숫자 타입으로 모든 변형 불가 작업을 사용할수 있습니다.\ncount + 1;\n\n// 주의하세요! 아래는 `count`가 final이 아닌 경우에만 유효합니다.\ncount += 1;\n\n// 값들을 비교할 수도 있습니다:\ncount > 2;\n\n/// booleans:\n\nfinal flag = false.obs;\n\n// true/false 사이의 전환이 됩니다.\nflag.toggle();\n\n\n/// 모든 타입들:\n\n// `값`을 null로 셋합니다.\nflag.nil();\n\n//  모든 toString(), toJson() 함수들은 `값`으로 전달됩니다.\nprint( count ); // RxInt 내부에서 `toString()`이 호출됩니다.\n\nfinal abc = [0,1,2].obs;\n// 값을 json 배열로 바꾸고 RxList를 출력합니다.\n// Json은 모든 Rx 타입들을 지원합니다!\nprint('json: ${jsonEncode(abc)}, type: ${abc.runtimeType}');\n\n// RxMap, RxList 그리고 RxSet은 그들의 native 타입들을 확장한 특별한 Rx 타입들입니다.\n// 반응형이긴 하지만 일반 list로서 RxList가 동작합니다!\nabc.add(12); // list에 12가 들어가고 stream을 업데이트합니다.\nabc[3]; // List와 같이 인덱스 3을 읽습니다.\n\n\n// 동등비교는 Rx와 값에서 동작하지만 해시코드는 항상 값으로부터 받습니다.\nfinal number = 12.obs;\nprint( number == 12 ); // prints > true\n\n/// 커스텀 Rx 모델들:\n\n// toJson(), toString()은 child에게 지연됩니다. 그래서 이것들을 재정의 하고 직접 관찰하여 print() 할수 있습니다.\n\nclass User {\n    String name, last;\n    int age;\n    User({this.name, this.last, this.age});\n\n    @override\n    String toString() => '$name $last, $age years old';\n}\n\nfinal user = User(name: 'John', last: 'Doe', age: 33).obs;\n\n// `user`는 \"반응형\"이지만 내부 프로퍼티들은 아닙니다!\n// 그래서 만약 내부의 변수를 바꾸면...\nuser.value.name = 'Roi';\n// 위젯은 재구성 되지 않을것 입니다!\n// user의 내부의 무언가가 바뀌어도 `Rx`는 알 수가 않습니다.\n// 그래서 커스텀 클래스들은 수동으로 바뀌었다고 \"알릴\" 필요가 있습니다.\nuser.refresh();\n\n// 또는 `update()` 함수를 사용할 수 있습니다!\nuser.update((value){\n  value.name='Roi';\n});\n\nprint( user );\n```\n## StateMixin\n\n`UI` 상태를 처리하는 또 다른 방법은 `StateMixin<T>` 를 사용하는 것입니다.\n이를 구현하려면 `with`를 사용하여 `StateMixin<T>`을 추가하고\nT 모델을 허용하는 컨트롤러에 연결합니다.\n\n``` dart\nclass Controller extends GetController with StateMixin<User>{}\n```\n\n`change()` 메소드는 우리가 원할 때마다 State를 변경합니다.\n다음과 같이 데이터와 상태를 전달하면 됩니다:\n\n```dart\nchange(data, status: RxStatus.success());\n```\n\nRxStatus는 다음 상태를 허용합니다:\n\n``` dart\nRxStatus.loading();\nRxStatus.success();\nRxStatus.empty();\nRxStatus.error('message');\n```\n\nUI에서 사용하는 방법:\n\n```dart\nclass OtherClass extends GetView<Controller> {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n\n      body: controller.obx(\n        (state)=>Text(state.name),\n        \n        // 여기에 사용자 정의 로딩 표시기를 넣을 수 있지만\n        // 기본값은 Center(child:CircularProgressIndicator()) 입니다\n        onLoading: CustomLoadingIndicator(),\n        onEmpty: Text('No data found'),\n\n        // 여기에서도 자신의 오류 위젯을 설정할 수 있지만\n        // 기본값은 Center(child:Text(error)) 입니다\n        onError: (error)=>Text(error),\n      ),\n    );\n}\n```\n\n#### GetView\n\n이 위젯을 사랑합니다. 매우 간단하고 유용합니다!\n\n등록된 `Controller`인 `controller`의 getter로 가져온 `const Stateless`위젯 입니다. 이게 전부입니다.\n\n```dart\n class AwesomeController extends GetxController {\n   final String title = 'My Awesome View';\n }\n\n  // controller를 등록할때 사용한 `타입`을 전달하는 것을 항상 기억하세요!\n class AwesomeView extends GetView<AwesomeController> {\n   @override\n   Widget build(BuildContext context) {\n     return Container(\n       padding: EdgeInsets.all(20),\n       child: Text(controller.title), // 단지 `controller.something`을 호출합니다.\n     );\n   }\n }\n```\n\n#### GetResponsiveView\n\nResponsiveView 를 빌드하려면 이 위젯을 확장하세요. 이 위젯에는 화면 크기 및 유형에 대한 모든 정보가 있는 화면 속성이 포함되어 있습니다.\n\n##### 사용 방법\n\n그것을 빌드하기 위한 두가지 옵션이 있습니다.\n- `builder` method 를 사용하면 빌드 할 위젯을 반환합니다.\n- `desktop`, `tablet`, `phone`, `watch` method를 사용하면 특정 메소드는 screen type 이 일치할때 빌드됩니다. Screen type이 [ScreenType.Tablet] 일때, tablet method 가 스며나옵니다. 참고: 만약 이 method 를 사용할 경우, `alwaysUseBuilder` 프로퍼티를 `false` 로 설정해주세요.   \n \n`settings` 프로퍼티를 사용하면 screen types 를 위한 width limit 를 설정할 수 있습니다.\n\n![example](https://github.com/SchabanBo/get_page_example/blob/master/docs/Example.gif?raw=true)\nCode to this screen\n[code](https://github.com/SchabanBo/get_page_example/blob/master/lib/pages/responsive_example/responsive_view.dart)\n\n#### GetWidget\n\n대부분의 사람들이 이 위젯에대해 모르거나 사용법을 완전히 혼동합니다.\n사용 사례는 매우 드물지만 매우 구체적입니다: Controller를 `caches`합니다.\n_cache_ 이기 때문에 `const Stateless`가 될 수 없습니다.\n\n> 그러면 언제 Controller를 \"cache\"할 필요가 있을까요?\n\n만약 **GetX**의 기능 중 또 다른 \"흔하지 않은\" 기능을 사용하는 경우:`Get.create()`\n\n`Get.create(()=>Controller())`가 `Get.find<Controller>()`을 호출할 때마다 \n새로운 `Controller`를 생성할 것 입니다.\n\n여기서 `GetWidget`이 빛나게 됩니다... 예를 들어 Todo 리스트를 유지하려고 사용할 때 입니다.\n위젯이 \"재구성\"될때 동일한 controller 인스턴스를 유지할 것입니다.\n\n#### GetxService\n\n이 클래스틑 `GetxController`와 같이 동일한 생성주기(`onInit()`, `onReady()`, `onClose()`)를 공유합니다.\n하지만 이안에 \"로직\"은 없습니다. 단지 **GetX** 종속성 주입 시스템이 하위클래스를 메모리에서 \n**삭제할 수 없음**을 알립니다.\n\n그래서 `Get.find()`로 활성화하고 항상 접근하는 \"서비스들\"을 유지하는데 매우 유용합니다. :\n`ApiService`, `StorageService`, `CacheService`.\n\n```dart\nFuture<void> main() async {\n  await initServices(); /// 서비스들 초기화를 기다림.\n  runApp(SomeApp());\n}\n\n/// 플러터 앱이 실행되기 전에 서비스들을 초기화하는 현명한 방법입니다.\n/// 실행 흐름을 제어 할수 있으므로(테마 구성, apiKey, 사용자가 정의한 언어등을 로드해야 할 필요가 있으므로 \n/// ApiService의 구동전에 SettingService를 로드해야 합니다.\n/// 그래서 GetMaterialApp()은 재구성하지 않고 직접적으로 값을 가져옵니다.\nFuture<void> initServices() async {\n  print('starting services ...');\n  /// 여기에서 get_storage, hive, shared_pref 초기화를 하세요.\n  /// 또는 연결 고정 또는 비동기적인 무엇이든 하세요.\n  await Get.putAsync(() => DbService().init());\n  await Get.putAsync(SettingsService()).init();\n  print('All services started...');\n}\n\nclass DbService extends GetxService {\n  Future<DbService> init() async {\n    print('$runtimeType delays 2 sec');\n    await 2.delay();\n    print('$runtimeType ready!');\n    return this;\n  }\n}\n\nclass SettingsService extends GetxService {\n  void init() async {\n    print('$runtimeType delays 1 sec');\n    await 1.delay();\n    print('$runtimeType ready!');\n  }\n}\n\n```\n\n`GetxService`를 실질적으로 지우는 한가지 방법은 앱의 \"Hot Reboot\"과 같은 `Get.reset()`뿐 입니다.\n따라서 앱 실행중 절대로 유지되어야 하는 클래스 인스턴스가 필요하면 \n`GetxService`를 사용하세요.\n\n### 테스트\n\n당신은 당신의 컨트롤러들을 생성주기를 포함하여 다른 어떤 클래스처럼 테스트할 수 있습니다 : \n\n```dart\nclass Controller extends GetxController {\n  @override\n  void onInit() {\n    super.onInit();\n    //name2로 값 변경\n    name.value = 'name2';\n  }\n\n  @override\n  void onClose() {\n    name.value = '';\n    super.onClose();\n  }\n\n  final name = 'name1'.obs;\n\n  void changeName() => name.value = 'name3';\n}\n\nvoid main() {\n  test('''\nTest the state of the reactive variable \"name\" across all of its lifecycles''',\n      () {\n    /// 당신은 생성주기를 제외하고 컨트롤러를 테스트할 수 있습니다,\n    /// 그러나 당신이 사용하지 않는다면 추천되지 않습니다\n    ///  GetX 종속성 주입 \n    final controller = Controller();\n    expect(controller.name.value, 'name1');\n\n    /// 당신이 그것을 사용한다면, 당신은 모든 것을 테스트할 수 있습니다,\n    /// 각각의 생성주기 이후 어플리케이션의 상태를 포함하여.\n    Get.put(controller); // onInit was called\n    expect(controller.name.value, 'name2');\n\n    /// 당신의 함수를 테스트하세요\n    controller.changeName();\n    expect(controller.name.value, 'name3');\n\n    /// onClose 호출됨\n    Get.delete<Controller>();\n\n    expect(controller.name.value, '');\n  });\n}\n```\n\n#### 팁들\n\n##### Mockito 또는 mocktail\n당신이 당신의 GetxController/GetxService를 모킹하려고 한다면, 당신은 GetxController를 extend 하고, Mock과 mixin 하라, 그렇게 되면 \n\n```dart\nclass NotificationServiceMock extends GetxService with Mock implements NotificationService {}\n```\n\n##### Get.reset() 사용하기\n당신이 위젯 또는 테스트 그룹을 테스트하고 있다면, 당신의 테스트의 마지막 또는 해제 때 당신의 이전 테스트에서 모든 설정을 리셋하기 위해 Get.rest을 사용하십시오\n\n##### Get.testMode \n당신이 당신의 컨트롤러에서 당신의 네비게이션을 사용하고 있다면, 당신의 메인의 시작에 `Get.testMode = true` 를 사용하십시오.\n\n\n# 2.0의 주요 변경점\n\n1- Rx 타입들:\n\n| 이전    | 이후       |\n| ------- | ---------- |\n| StringX | `RxString` |\n| IntX    | `RxInt`    |\n| MapX    | `RxMap`    |\n| ListX   | `RxList`   |\n| NumX    | `RxNum`    |\n| DoubleX | `RxDouble` |\n\nRxController와 GetBuilder는 합쳐졌습니다. 더이상 사용할 controller를 기억시킬 필요가 없습니다. GetxController를 사용하세요. 단순 및 반응형 상태관리 모두에서 잘 동작합니다.\n\n2- 명명된 라우트\n이전:\n\n```dart\nGetMaterialApp(\n  namedRoutes: {\n    '/': GetRoute(page: Home()),\n  }\n)\n```\n\n지금:\n\n```dart\nGetMaterialApp(\n  getPages: [\n    GetPage(name: '/', page: () => Home()),\n  ]\n)\n```\n\n무엇이 달라졌습니까?\n종종 매개 변수 또는 로그인 토큰에 의해 표시 할 페이지를 결정해야 할 수 있습니다. 이전 접근 방식은 이를 허용하지 않았기 때문에 유연하지 않았습니다.\n페이지를 함수에 삽입하면 앱이 시작된 이후 라우트가 메모리에 할당되지 않고 이러한 유형의 접근 방식이 가능하기 때문에 RAM 소비가 크게 감소했습니다:\n\n```dart\n\nGetStorage box = GetStorage();\n\nGetMaterialApp(\n  getPages: [\n    GetPage(name: '/', page:(){\n      return box.hasData('token') ? Home() : Login();\n    })\n  ]\n)\n```\n\n# 왜 Getx인가?\n\n1- 플러터가 업데이트된 이후 자주 많은 패키지가 깨졌을 것입니다. 때때로 컴파일중 에러가 발생하고 종종 이에 대해 답변을 해줄 사람이 없었을 겁니다. 그리고 개발자는 에러가 어디에서 발생했는지 추적해서 알아야합니다. 그리고 오직 리포지트리를 통해서 이슈를 오픈하고 해결책을 찾아야합니다. Get은 개발을 위한 주 리소스들(상태, 종속성, 라우트 관리)을 중앙화합니다. pubspec에 단일 패키지를 추가하고 작업을 시작 할 수 있습니다. 플러터가 업데이트 된 이후에도 Get 의존을 업데이트하면 작업할 수 있습니다. Get은 호환성 이슈도 해결합니다. 한 버전에서 종속적으로 사용하여 다른 버전에서 다른 버전을 사용할때 패키지 버전이 다른 버전과 호환되지 않는 경우가 몇 번입니까? 모든 것이 동일한 패키지에 있고 완벽하게 호환되므로 Get을 사용하면 문제가 되지 않습니다.\n\n2- 플러터는 쉽고 놀랍지만 대다수의 개발자들이 원하지 않는 몇가지 상용구가 있습니다. `Navigator.of(context).push (context, builder [...]` 같은 것들 입니다. Get은 개발을 단순화합니다. 라우트를 위해 8줄의 코드를 작성하고 `Get.to(Home())`만 하면 다음 페이지로 갈 수 있습니다. 동적 웹 url은 현재 플러터에서 정말로 고통스러운 것이고 GetX로 하는 것은 정말 간단합니다. 플러터에서 상태와 종속성을 관리하는 것은 pub에서 수백가지의 패턴이라 많은 논의를 생산합니다. 그러나 변수 끝에 \".obs\"를 추가하고 위젯을 Obx 안에 배치하는 것만큼 쉬운 것은 없습니다. 이것으로 해당 변수가 업데이트되면 화면에 자동으로 업데이트됩니다.\n\n3- 성능에 대하여 걱정하지 않아도 됩니다. 플러터의 성능은 이미 놀랍습니다. 하지만 상태관리자를 사용하고 blocs/stores/controllers 등의 클래스들을 로케이터로 배포하는 것을 상상해보십시오. 종속성이 필요 없는 경우 종속성 제외를 수동으로 호출해야 합니다. 하지만 간단하게 controller를 사용하고 이것들을 더이상 사용하지 않을때 간단하게 메모리에서 삭제될수 있을까요? 이것이 GetX가 하는 일입니다. SmartManagement를 사용하면 사용하지 않는 모든것이 메모리에서 삭제되기 때문에 프로그래밍 말고 다른 걱정을 할 필요가 없습니다. 이러한 로직을 만들지 않고도 최소한의 리소스만 사용함을 보장합니다.\n\n4- 실질적으로 분리됨. \"비즈니스 로직으로부터 뷰를 분리\"라는 개념을 들어보셨을 겁니다. 이것은 BLoC, MVC, MVVM의 특징이 아니며 이미 나와 있는 또 다른 표준 개념입니다. 그러나 이 개념은 context의 사용으로 인해 플러터에서 종종 완화됩니다.\n만약 InheritedWidget을 찾기 위해 context가 필요하면 뷰나 파라미터로 context를 전달해야 합니다. 저는 특히 이 방식이 매우 별로이고 팀의 작업이 항상 뷰의 비즈니스 로직에 의존하게 됩니다. GetX는 표준 접근에서 비정통적이고 StatefulWidgets, InitState 등의 사용을 완전 배제하지 않지만 항상 깔끔하게 유사한 접근을 제공합니다. 예를 들어 Controllers의 수명주기에서 APIREST 요청이 필요할 때 뷰에 어떤 것도 의존할 필요가 없습니다. http 호출의 초기화를 onInit 에서 사용가능 하고 데이터가 도착하면 변수들이 채워집니다. GetX는 완전히 반응형이며(실제 스트림으로 동작) 아이탬중 하나가 채워지면 이 변수를 사용중인 모든 위젯이 자동적으로 화면에서 갱신됩니다. 이를 통해 UI 전문가는 위젯으로만 작업하고 사용자 이벤트(예 : 버튼 클릭) 이외의 비즈니스 로직에 아무것도 보낼 필요가 없으며 비즈니스 로직을 개발하는 사람들은 비즈니스 로직을 별도로 만들고 테스트 할 수 있습니다.\n\n이 라이브러리는 항상 업데이트되고 새로운 기능이 포함됩니다. 자유롭게 PR을 제공하고 여기에 기여하세요.\n\n# 커뮤니티\n\n## 커뮤니티 채널\n\nGetX에는 매우 활동적이고 유용한 커뮤니티가 있습니다. 이 프레임워크의 사용과 관련하여 질문이 있거나 도움이 필요한 경우 커뮤니티 채널에 가입하십시오. 질문에 대한 답변이 더 빨리 제공되며 가장 적합한 장소가 될 것입니다. 이 저장소는 이슈오픈 및 리소스 요청 전용이지만 GetX 커뮤니티의 일부에 속해있습니다.\n\n| **Slack**                                                                                                                   | **Discord**                                                                                                                 | **Telegram**                                                                                                          |\n| :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------- |\n| [![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) |\n\n## 기여하는 방법\n\n_프로젝트에 기여하고 싶으신가요? 우리는 귀하를 우리의 협력자 중 한 명으로 부각시켜 자랑스럽게 생각합니다. 다음은 Get(그리고 플러터)을 더욱 향상시키고 기여할 수 있는 몇 가지 사항입니다._\n\n- readme을 다른 언어로 번역하는 데 도움이 됩니다.\n- readme에 문서를 추가합니다(Get의 많은 기능이 아직 문서화되지 않았습니다).\n- Get 사용법을 설명하는 기사를 쓰거나 비디오를 만듭니다(읽기 및 향후 위키에 삽입될 예정).\n- 코드/테스트에 대한 PR을 제공합니다.\n- 새로운 기능을 포함합니다.\n\n어떤 기여도 환영합니다!\n\n## 기사 및 비디오\n\n- [Flutter Getx EcoSystem package for arabic people](https://www.youtube.com/playlist?list=PLV1fXIAyjeuZ6M8m56zajMUwu4uE3-SL0) - Tutorial by [Pesa Coder](https://github.com/UsamaElgendy).\n- [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).\n- [Complete GetX™ Navigation](https://www.youtube.com/watch?v=RaqPIoJSTtI) - Route management video by Amateur Coder.\n- [Complete GetX State Management](https://www.youtube.com/watch?v=CNpXbeI_slw) - State management video by Amateur Coder.\n- [GetX™ Other Features](https://youtu.be/ttQtlX_Q0eU) - Utils, storage, bindings and other features video by Amateur Coder.\n- [Firestore User with GetX | Todo App](https://www.youtube.com/watch?v=BiV0DcXgk58) - Video by Amateur Coder.\n- [Firebase Auth with GetX | Todo App](https://www.youtube.com/watch?v=-H-T_BSgfOE) - Video by Amateur Coder.\n- [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).\n- [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).\n- [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.\n- [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.\n- [GetX Flutter Firebase Auth Example](https://medium.com/@jeffmcmorris/getx-flutter-firebase-auth-example-b383c1dd1de2) - Article by Jeff McMorris.\n- [Flutter State Management with GetX – Complete App](https://www.appwithflutter.com/flutter-state-management-with-getx/) - by App With Flutter.\n- [Flutter Routing with Animation using Get Package](https://www.appwithflutter.com/flutter-routing-using-get-package/) - by App With Flutter.\n- [A minimal example on dartpad](https://dartpad.dev/2b3d0d6f9d4e312c5fdbefc414c1727e?) - by [Roi Peker](https://github.com/roipeker)\n"
  },
  {
    "path": "README.md",
    "content": "![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png)\n\n[![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)\n[![popularity](https://img.shields.io/pub/popularity/get?logo=dart)](https://pub.dev/packages/get/score)\n[![likes](https://img.shields.io/pub/likes/get?logo=dart)](https://pub.dev/packages/get/score)\n[![pub points](https://img.shields.io/pub/points/sentry?logo=dart)](https://pub.dev/packages/get/score)\n![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)\n[![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart)\n[![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N)\n[![Get on Slack](https://img.shields.io/badge/slack-join-orange.svg)](https://communityinviter.com/apps/getxworkspace/getx)\n[![Telegram](https://img.shields.io/badge/chat-on%20Telegram-blue.svg)](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g)\n<a href=\"https://github.com/Solido/awesome-flutter\">\n<img alt=\"Awesome Flutter\" src=\"https://img.shields.io/badge/Awesome-Flutter-blue.svg?longCache=true&style=flat-square\" />\n</a>\n<a href=\"https://www.buymeacoffee.com/jonataslaw\" target=\"_blank\"><img src=\"https://i.imgur.com/aV6DDA7.png\" alt=\"Buy Me A Coffee\" style=\"height: 41px !important;width: 174px !important; box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;\" > </a>\n\n![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/getx.png)\n\n<div align=\"center\">\n\n**Languages:**\n\n[![English](https://img.shields.io/badge/Language-English-blueviolet?style=for-the-badge)](README.md)\n[![Vietnamese](https://img.shields.io/badge/Language-Vietnamese-blueviolet?style=for-the-badge)](README-vi.md)\n[![Indonesian](https://img.shields.io/badge/Language-Indonesian-blueviolet?style=for-the-badge)](README.id-ID.md)\n[![Urdu](https://img.shields.io/badge/Language-Urdu-blueviolet?style=for-the-badge)](README.ur-PK.md)\n[![Chinese](https://img.shields.io/badge/Language-Chinese-blueviolet?style=for-the-badge)](README.zh-cn.md)\n[![Portuguese](https://img.shields.io/badge/Language-Portuguese-blueviolet?style=for-the-badge)](README.pt-br.md)\n[![Spanish](https://img.shields.io/badge/Language-Spanish-blueviolet?style=for-the-badge)](README-es.md)\n[![Russian](https://img.shields.io/badge/Language-Russian-blueviolet?style=for-the-badge)](README.ru.md)\n[![Polish](https://img.shields.io/badge/Language-Polish-blueviolet?style=for-the-badge)](README.pl.md)\n[![Korean](https://img.shields.io/badge/Language-Korean-blueviolet?style=for-the-badge)](README.ko-kr.md)\n[![French](https://img.shields.io/badge/Language-French-blueviolet?style=for-the-badge)](README-fr.md)\n[![Japanese](https://img.shields.io/badge/Language-Japanese-blueviolet?style=for-the-badge)](README.ja-JP.md)\n[![Hindi](https://img.shields.io/badge/Language-Hindi-blueviolet?style=for-the-badge)](README-hi.md)\n[![Bangla](https://img.shields.io/badge/Language-Bangla-blueviolet?style=for-the-badge)](README-bn.md)\n[![Nepali](https://img.shields.io/badge/Language-Nepali-blueviolet?style=for-the-badge)](README-ne.md)\n\n</div>\n\n- [About Get](#about-get)\n- [Installing](#installing)\n- [Counter App with GetX](#counter-app-with-getx)\n- [The Three pillars](#the-three-pillars)\n  - [State management](#state-management)\n    - [Reactive State Manager](#reactive-state-manager)\n    - [More details about state management](#more-details-about-state-management)\n  - [Route management](#route-management)\n    - [More details about route management](#more-details-about-route-management)\n  - [Dependency management](#dependency-management)\n    - [More details about dependency management](#more-details-about-dependency-management)\n- [Utils](#utils)\n  - [Internationalization](#internationalization)\n    - [Translations](#translations)\n      - [Using translations](#using-translations)\n    - [Locales](#locales)\n      - [Change locale](#change-locale)\n      - [System locale](#system-locale)\n  - [Change Theme](#change-theme)\n  - [GetConnect](#getconnect)\n    - [Default configuration](#default-configuration)\n    - [Custom configuration](#custom-configuration)\n  - [GetPage Middleware](#getpage-middleware)\n    - [Priority](#priority)\n    - [Redirect](#redirect)\n    - [onPageCalled](#onpagecalled)\n    - [OnBindingsStart](#onbindingsstart)\n    - [OnPageBuildStart](#onpagebuildstart)\n    - [OnPageBuilt](#onpagebuilt)\n    - [OnPageDispose](#onpagedispose)\n  - [Other Advanced APIs](#other-advanced-apis)\n    - [Optional Global Settings and Manual configurations](#optional-global-settings-and-manual-configurations)\n    - [Local State Widgets](#local-state-widgets)\n      - [ValueBuilder](#valuebuilder)\n      - [ObxValue](#obxvalue)\n  - [Useful tips](#useful-tips)\n    - [GetView](#getview)\n    - [GetResponsiveView](#getresponsiveview)\n      - [How to use it](#how-to-use-it)\n    - [GetWidget](#getwidget)\n    - [GetxService](#getxservice)\n- [Breaking changes from 2.0](#breaking-changes-from-20)\n- [Why Getx?](#why-getx)\n- [Community](#community)\n  - [Community channels](#community-channels)\n  - [How to contribute](#how-to-contribute)\n  - [Articles and videos](#articles-and-videos)\n\n# About Get\n\n- 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.\n\n- GetX has 3 basic principles. This means that these are the priority for all resources in the library: **PRODUCTIVITY, PERFORMANCE AND ORGANIZATION.**\n  - **PERFORMANCE:** GetX is focused on performance and minimum consumption of resources. GetX does not use Streams or ChangeNotifier.\n\n  - **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.\n\n    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.\n\n  - **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.\n\n    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.\n    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.\n    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.\n\n- 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.\n\n- 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.\n  **It is possible to fully reuse your code made on the frontend on your backend with [Get Server](https://github.com/jonataslaw/get_server)**.\n\n**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)**.\n\n**In addition, to further increase your productivity, we have the\n[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)**\n\n# Installing\n\nAdd Get to your pubspec.yaml file:\n\n```yaml\ndependencies:\n  get:\n```\n\nImport get in files that it will be used:\n\n```dart\nimport 'package:get/get.dart';\n```\n\n# Counter App with GetX\n\nThe \"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.\n\n- Step 1:\n  Add \"Get\" before your MaterialApp, turning it into GetMaterialApp\n\n```dart\nvoid main() => runApp(GetMaterialApp(home: Home()));\n```\n\n- 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.\n- 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\n\n- Step 2:\n  Create your business logic class and place all variables, methods and controllers inside it.\n  You can make any variable observable using a simple \".obs\".\n\n```dart\nclass Controller extends GetxController{\n  var count = 0.obs;\n  increment() => count++;\n}\n```\n\n- Step 3:\n  Create your View, use StatelessWidget and save some RAM, with Get you may no longer need to use StatefulWidget.\n\n```dart\nclass Home extends StatelessWidget {\n\n  @override\n  Widget build(context) {\n\n    // Instantiate your class using Get.put() to make it available for all \"child\" routes there.\n    final Controller c = Get.put(Controller());\n\n    return Scaffold(\n      // Use Obx(()=> to update Text() whenever count is changed.\n      appBar: AppBar(title: Obx(() => Text(\"Clicks: ${c.count}\"))),\n\n      // Replace the 8 lines Navigator.push by a simple Get.to(). You don't need context\n      body: Center(child: ElevatedButton(\n              child: Text(\"Go to Other\"), onPressed: () => Get.to(Other()))),\n      floatingActionButton:\n          FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment));\n  }\n}\n\nclass Other extends StatelessWidget {\n  // You can ask Get to find a Controller that is being used by another page and redirect you to it.\n  final Controller c = Get.find();\n\n  @override\n  Widget build(context){\n     // Access the updated count variable\n     return Scaffold(body: Center(child: Text(\"${c.count}\")));\n  }\n}\n```\n\nResult:\n\n![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/counter-app-gif.gif)\n\nThis is a simple project but it already makes clear how powerful Get is. As your project grows, this difference will become more significant.\n\nGet was designed to work with teams, but it makes the job of an individual developer simple.\n\nImprove 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!\n\n# The Three pillars\n\n## State management\n\nGet has two different state managers: the simple state manager (we'll call it GetBuilder) and the reactive state manager (GetX/Obx)\n\n### Reactive State Manager\n\nReactive programming can alienate many people because it is said to be complicated. GetX turns reactive programming into something quite simple:\n\n- You won't need to create StreamControllers.\n- You won't need to create a StreamBuilder for each variable\n- You will not need to create a class for each state.\n- You will not need to create a get for an initial value.\n- You will not need to use code generators\n\nReactive programming with Get is as easy as using setState.\n\nLet's imagine that you have a name variable and want that every time you change it, all widgets that use it are automatically changed.\n\nThis is your count variable:\n\n```dart\nvar name = 'Jonatas Borges';\n```\n\nTo make it observable, you just need to add \".obs\" to the end of it:\n\n```dart\nvar name = 'Jonatas Borges'.obs;\n```\n\nAnd in the UI, when you want to show that value and update the screen whenever the values changes, simply do this:\n\n```dart\nObx(() => Text(\"${controller.name}\"));\n```\n\nThat's all. It's _that_ simple.\n\n### More details about state management\n\n**See an more in-depth explanation of state management [here](./documentation/en_US/state_management.md). There you will see more examples and also the difference between the simple state manager and the reactive state manager**\n\nYou will get a good idea of GetX power.\n\n## Route management\n\nIf you are going to use routes/snackbars/dialogs/bottomsheets without context, GetX is excellent for you too, just see it:\n\nAdd \"Get\" before your MaterialApp, turning it into GetMaterialApp\n\n```dart\nGetMaterialApp( // Before: MaterialApp(\n  home: MyHome(),\n)\n```\n\nNavigate to a new screen:\n\n```dart\n\nGet.to(NextScreen());\n```\n\nNavigate to new screen with name. See more details on named routes [here](./documentation/en_US/route_management.md#navigation-with-named-routes)\n\n```dart\n\nGet.toNamed('/details');\n```\n\nTo close snackbars, dialogs, bottomsheets, or anything you would normally close with Navigator.pop(context);\n\n```dart\nGet.back();\n```\n\nTo go to the next screen and no option to go back to the previous screen (for use in SplashScreens, login screens, etc.)\n\n```dart\nGet.off(NextScreen());\n```\n\nTo go to the next screen and cancel all previous routes (useful in shopping carts, polls, and tests)\n\n```dart\nGet.offAll(NextScreen());\n```\n\nNoticed 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.\n\n### More details about route management\n\n**Get works with named routes and also offers lower-level control over your routes! There is in-depth documentation [here](./documentation/en_US/route_management.md)**\n\n## Dependency management\n\nGet 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:\n\n```dart\nController controller = Get.put(Controller()); // Rather Controller controller = Controller();\n```\n\n- 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.\n\nInstead 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.\nSo you can use your controller (or class Bloc) normally\n\n**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\n\n```dart\ncontroller.fetchApi();\n```\n\nImagine 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:\n\n```dart\nController controller = Get.find();\n//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.\n```\n\nAnd then you will be able to recover your controller data that was obtained back there:\n\n```dart\nText(controller.textFromApi);\n```\n\n### More details about dependency management\n\n**See a more in-depth explanation of dependency management [here](./documentation/en_US/dependency_management.md)**\n\n# Utils\n\n## Internationalization\n\n### Translations\n\nTranslations are kept as a simple key-value dictionary map.\nTo add custom translations, create a class and extend `Translations`.\n\n```dart\nimport 'package:get/get.dart';\n\nclass Messages extends Translations {\n  @override\n  Map<String, Map<String, String>> get keys => {\n        'en_US': {\n          'hello': 'Hello World',\n        },\n        'de_DE': {\n          'hello': 'Hallo Welt',\n        }\n      };\n}\n```\n\n#### Using translations\n\nJust append `.tr` to the specified key and it will be translated, using the current value of `Get.locale` and `Get.fallbackLocale`.\n\n```dart\nText('title'.tr);\n```\n\n#### Using translation with singular and plural\n\n```dart\nvar products = [];\nText('singularKey'.trPlural('pluralKey', products.length, Args));\n```\n\n#### Using translation with parameters\n\n```dart\nimport 'package:get/get.dart';\n\n\nMap<String, Map<String, String>> get keys => {\n    'en_US': {\n        'logged_in': 'logged in as @name with email @email',\n    },\n    'es_ES': {\n       'logged_in': 'iniciado sesión como @name con e-mail @email',\n    }\n};\n\nText('logged_in'.trParams({\n  'name': 'Jhon',\n  'email': 'jhon@example.com'\n  }));\n```\n\n### Locales\n\nPass parameters to `GetMaterialApp` to define the locale and translations.\n\n```dart\nreturn GetMaterialApp(\n    translations: Messages(), // your translations\n    locale: Locale('en', 'US'), // translations will be displayed in that locale\n    fallbackLocale: Locale('en', 'UK'), // specify the fallback locale in case an invalid locale is selected.\n);\n```\n\n#### Change locale\n\nCall `Get.updateLocale(locale)` to update the locale. Translations then automatically use the new locale.\n\n```dart\nvar locale = Locale('en', 'US');\nGet.updateLocale(locale);\n```\n\n#### System locale\n\nTo read the system locale, you could use `Get.deviceLocale`.\n\n```dart\nreturn GetMaterialApp(\n    locale: Get.deviceLocale,\n);\n```\n\n## Change Theme\n\nPlease 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™**.\n\nYou can create your custom theme and simply add it within `Get.changeTheme` without any boilerplate for that:\n\n```dart\nGet.changeTheme(ThemeData.light());\n```\n\nIf you want to create something like a button that changes the Theme in `onTap`, you can combine two **GetX™** APIs for that:\n\n- The api that checks if the dark `Theme` is being used.\n- And the `Theme` Change API, you can just put this within an `onPressed`:\n\n```dart\nGet.changeTheme(Get.isDarkMode? ThemeData.light(): ThemeData.dark());\n```\n\nWhen `.darkmode` is activated, it will switch to the _light theme_, and when the _light theme_ becomes active, it will change to _dark theme_.\n\n## GetConnect\n\nGetConnect is an easy way to communicate from your back to your front with http or websockets\n\n### Default configuration\n\nYou can simply extend GetConnect and use the GET/POST/PUT/DELETE/SOCKET methods to communicate with your Rest API or websockets.\n\n```dart\nclass UserProvider extends GetConnect {\n  // Get request\n  Future<Response> getUser(int id) => get('http://youapi/users/$id');\n  // Post request\n  Future<Response> postUser(Map data) => post('http://youapi/users', body: data);\n  // Post request with File\n  Future<Response<CasesModel>> postCases(List<int> image) {\n    final form = FormData({\n      'file': MultipartFile(image, filename: 'avatar.png'),\n      'otherFile': MultipartFile(image, filename: 'cover.png'),\n    });\n    return post('http://youapi/users/upload', form);\n  }\n\n  GetSocket userMessages() {\n    return socket('https://yourapi/users/socket');\n  }\n}\n```\n\n### Custom configuration\n\nGetConnect 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.\n\n```dart\nclass HomeProvider extends GetConnect {\n  @override\n  void onInit() {\n    // All request will pass to jsonEncode so CasesModel.fromJson()\n    httpClient.defaultDecoder = CasesModel.fromJson;\n    httpClient.baseUrl = 'https://api.covid19api.com';\n    // baseUrl = 'https://api.covid19api.com'; // It define baseUrl to\n    // Http and websockets if used with no [httpClient] instance\n\n    // It's will attach 'apikey' property on header from all requests\n    httpClient.addRequestModifier((request) {\n      request.headers['apikey'] = '12345678';\n      return request;\n    });\n\n    // Even if the server sends data from the country \"Brazil\",\n    // it will never be displayed to users, because you remove\n    // that data from the response, even before the response is delivered\n    httpClient.addResponseModifier<CasesModel>((request, response) {\n      CasesModel model = response.body;\n      if (model.countries.contains('Brazil')) {\n        model.countries.remove('Brazilll');\n      }\n    });\n\n    httpClient.addAuthenticator((request) async {\n      final response = await get(\"http://yourapi/token\");\n      final token = response.body['token'];\n      // Set the header\n      request.headers['Authorization'] = \"$token\";\n      return request;\n    });\n\n    //Autenticator will be called 3 times if HttpStatus is\n    //HttpStatus.unauthorized\n    httpClient.maxAuthRetries = 3;\n  }\n\n  @override\n  Future<Response<CasesModel>> getCases(String path) => get(path);\n}\n```\n\n## GetPage Middleware\n\nThe GetPage has now new property that takes a list of GetMiddleWare and run them in the specific order.\n\n**Note**: When GetPage has a Middlewares, all the children of this page will have the same middlewares automatically.\n\n### Priority\n\nThe Order of the Middlewares to run can be set by the priority in the GetMiddleware.\n\n```dart\nfinal middlewares = [\n  GetMiddleware(priority: 2),\n  GetMiddleware(priority: 5),\n  GetMiddleware(priority: 4),\n  GetMiddleware(priority: -8),\n];\n```\n\nthose middlewares will be run in this order **-8 => 2 => 4 => 5**\n\n### Redirect\n\nThis 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.\n\n```dart\nRouteSettings redirect(String route) {\n  final authService = Get.find<AuthService>();\n  return authService.authed.value ? null : RouteSettings(name: '/login')\n}\n```\n\n### onPageCalled\n\nThis function will be called when this Page is called before anything created\nyou can use it to change something about the page or give it new page\n\n```dart\nGetPage onPageCalled(GetPage page) {\n  final authService = Get.find<AuthService>();\n  return page.copyWith(title: 'Welcome ${authService.UserName}');\n}\n```\n\n### OnBindingsStart\n\nThis function will be called right before the Bindings are initialize.\nHere you can change Bindings for this page.\n\n```dart\nList<Bindings> onBindingsStart(List<Bindings> bindings) {\n  final authService = Get.find<AuthService>();\n  if (authService.isAdmin) {\n    bindings.add(AdminBinding());\n  }\n  return bindings;\n}\n```\n\n### OnPageBuildStart\n\nThis function will be called right after the Bindings are initialize.\nHere you can do something after that you created the bindings and before creating the page widget.\n\n```dart\nGetPageBuilder onPageBuildStart(GetPageBuilder page) {\n  print('bindings are ready');\n  return page;\n}\n```\n\n### OnPageBuilt\n\nThis 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.\n\n### OnPageDispose\n\nThis function will be called right after disposing all the related objects (Controllers, views, ...) of the page.\n\n## Other Advanced APIs\n\n```dart\n// give the current args from currentScreen\nGet.arguments\n\n// give name of previous route\nGet.previousRoute\n\n// give the raw route to access for example, rawRoute.isFirst()\nGet.rawRoute\n\n// give access to Routing API from GetObserver\nGet.routing\n\n// check if snackbar is open\nGet.isSnackbarOpen\n\n// check if dialog is open\nGet.isDialogOpen\n\n// check if bottomsheet is open\nGet.isBottomSheetOpen\n\n// remove one route.\nGet.removeRoute()\n\n// back repeatedly until the predicate returns true.\nGet.until()\n\n// go to next route and remove all the previous routes until the predicate returns true.\nGet.offUntil()\n\n// go to next named route and remove all the previous routes until the predicate returns true.\nGet.offNamedUntil()\n\n//Check in what platform the app is running\nGetPlatform.isAndroid\nGetPlatform.isIOS\nGetPlatform.isMacOS\nGetPlatform.isWindows\nGetPlatform.isLinux\nGetPlatform.isFuchsia\n\n//Check the device type\nGetPlatform.isMobile\nGetPlatform.isDesktop\n//All platforms are supported independently in web!\n//You can tell if you are running inside a browser\n//on Windows, iOS, OSX, Android, etc.\nGetPlatform.isWeb\n\n\n// Equivalent to : MediaQuery.of(context).size.height,\n// but immutable.\nGet.height\nGet.width\n\n// Gives the current context of the Navigator.\nGet.context\n\n// Gives the context of the snackbar/dialog/bottomsheet in the foreground, anywhere in your code.\nGet.contextOverlay\n\n// Note: the following methods are extensions on context. Since you\n// have access to context in any place of your UI, you can use it anywhere in the UI code\n\n// If you need a changeable height/width (like Desktop or browser windows that can be scaled) you will need to use context.\ncontext.width\ncontext.height\n\n// Gives you the power to define half the screen, a third of it and so on.\n// Useful for responsive applications.\n// param dividedBy (double) optional - default: 1\n// param reducedBy (double) optional - default: 0\ncontext.heightTransformer()\ncontext.widthTransformer()\n\n/// Similar to MediaQuery.sizeOf(context);\ncontext.mediaQuerySize()\n\n/// Similar to MediaQuery.paddingOf(context);\ncontext.mediaQueryPadding()\n\n/// Similar to MediaQuery.viewPaddingOf(context);\ncontext.mediaQueryViewPadding()\n\n/// Similar to MediaQuery.viewInsetsOf(context);\ncontext.mediaQueryViewInsets()\n\n/// Similar to MediaQuery.orientationOf(context);\ncontext.orientation()\n\n/// Check if device is on landscape mode\ncontext.isLandscape()\n\n/// Check if device is on portrait mode\ncontext.isPortrait()\n\n/// Similar to MediaQuery.devicePixelRatioOf(context);\ncontext.devicePixelRatio()\n\n/// Similar to MediaQuery.textScaleFactorOf(context);\ncontext.textScaleFactor()\n\n/// Get the shortestSide from screen\ncontext.mediaQueryShortestSide()\n\n/// True if width be larger than 800\ncontext.showNavbar()\n\n/// True if the shortestSide is smaller than 600p\ncontext.isPhone()\n\n/// True if the shortestSide is largest than 600p\ncontext.isSmallTablet()\n\n/// True if the shortestSide is largest than 720p\ncontext.isLargeTablet()\n\n/// True if the current device is Tablet\ncontext.isTablet()\n\n/// Returns a value<T> according to the screen size\n/// can give value for:\n/// watch: if the shortestSide is smaller than 300\n/// mobile: if the shortestSide is smaller than 600\n/// tablet: if the shortestSide is smaller than 1200\n/// desktop: if width is largest than 1200\ncontext.responsiveValue<T>()\n```\n\n### Optional Global Settings and Manual configurations\n\nGetMaterialApp configures everything for you, but if you want to configure Get manually.\n\n```dart\nMaterialApp(\n  navigatorKey: Get.key,\n  navigatorObservers: [GetObserver()],\n);\n```\n\nYou will also be able to use your own Middleware within `GetObserver`, this will not influence anything.\n\n```dart\nMaterialApp(\n  navigatorKey: Get.key,\n  navigatorObservers: [\n    GetObserver(MiddleWare.observer) // Here\n  ],\n);\n```\n\nYou can create _Global Settings_ for `Get`. Just add `Get.config` to your code before pushing any route.\nOr do it directly in your `GetMaterialApp`\n\n```dart\nGetMaterialApp(\n  enableLog: true,\n  defaultTransition: Transition.fade,\n  opaqueRoute: Get.isOpaqueRouteDefault,\n  popGesture: Get.isPopGestureEnable,\n  transitionDuration: Get.defaultDurationTransition,\n  defaultGlobalState: Get.defaultGlobalState,\n);\n\nGet.config(\n  enableLog = true,\n  defaultPopGesture = true,\n  defaultTransition = Transitions.cupertino\n)\n```\n\nYou can optionally redirect all the logging messages from `Get`.\nIf you want to use your own, favourite logging package,\nand want to capture the logs there:\n\n```dart\nGetMaterialApp(\n  enableLog: true,\n  logWriterCallback: localLogWriter,\n);\n\nvoid localLogWriter(String text, {bool isError = false}) {\n  // pass the message to your favourite logging package here\n  // please note that even if enableLog: false log messages will be pushed in this callback\n  // you get check the flag if you want through GetConfig.isLogEnable\n}\n\n```\n\n### Local State Widgets\n\nThese Widgets allows you to manage a single value, and keep the state ephemeral and locally.\nWe have flavours for Reactive and Simple.\nFor instance, you might use them to toggle obscureText in a `TextField`, maybe create a custom\nExpandable Panel, or maybe modify the current index in `BottomNavigationBar` while changing the content\nof the body in a `Scaffold`.\n\n#### ValueBuilder\n\nA simplification of `StatefulWidget` that works with a `.setState` callback that takes the updated value.\n\n```dart\nValueBuilder<bool>(\n  initialValue: false,\n  builder: (value, updateFn) => Switch(\n    value: value,\n    onChanged: updateFn, // same signature! you could use ( newValue ) => updateFn( newValue )\n  ),\n  // if you need to call something outside the builder method.\n  onUpdate: (value) => print(\"Value updated: $value\"),\n  onDispose: () => print(\"Widget unmounted\"),\n),\n```\n\n#### ObxValue\n\nSimilar to [`ValueBuilder`](#valuebuilder), but this is the Reactive version, you pass a Rx instance (remember the magical .obs?) and\nupdates automatically... isn't it awesome?\n\n```dart\nObxValue((data) => Switch(\n        value: data.value,\n        onChanged: data, // Rx has a _callable_ function! You could use (flag) => data.value = flag,\n    ),\n    false.obs,\n),\n```\n\n## Useful tips\n\n`.obs`ervables (also known as _Rx_ Types) have a wide variety of internal methods and operators.\n\n> Is very common to _believe_ that a property with `.obs` **IS** the actual value... but make no mistake!\n> We avoid the Type declaration of the variable, because Dart's compiler is smart enough, and the code\n> looks cleaner, but:\n\n```dart\nvar message = 'Hello world'.obs;\nprint( 'Message \"$message\" has Type ${message.runtimeType}');\n```\n\nEven if `message` _prints_ the actual String value, the Type is **RxString**!\n\nSo, you can't do `message.substring( 0, 4 )`.\nYou have to access the real `value` inside the _observable_:\nThe most \"used way\" is `.value`, but, did you know that you can also use...\n\n```dart\nfinal name = 'GetX'.obs;\n// only \"updates\" the stream, if the value is different from the current one.\nname.value = 'Hey';\n\n// All Rx properties are \"callable\" and returns the new value.\n// but this approach does not accepts `null`, the UI will not rebuild.\nname('Hello');\n\n// is like a getter, prints 'Hello'.\nname() ;\n\n/// numbers:\n\nfinal count = 0.obs;\n\n// You can use all non mutable operations from num primitives!\ncount + 1;\n\n// Watch out! this is only valid if `count` is not final, but var\ncount += 1;\n\n// You can also compare against values:\ncount > 2;\n\n/// booleans:\n\nfinal flag = false.obs;\n\n// switches the value between true/false\nflag.toggle();\n\n\n/// all types:\n\n// Sets the `value` to null.\nflag.nil();\n\n// All toString(), toJson() operations are passed down to the `value`\nprint( count ); // calls `toString()` inside  for RxInt\n\nfinal abc = [0,1,2].obs;\n// Converts the value to a json Array, prints RxList\n// Json is supported by all Rx types!\nprint('json: ${jsonEncode(abc)}, type: ${abc.runtimeType}');\n\n// RxMap, RxList and RxSet are special Rx types, that extends their native types.\n// but you can work with a List as a regular list, although is reactive!\nabc.add(12); // pushes 12 to the list, and UPDATES the stream.\nabc[3]; // like Lists, reads the index 3.\n\n\n// equality works with the Rx and the value, but hashCode is always taken from the value\nfinal number = 12.obs;\nprint( number == 12 ); // prints > true\n\n/// Custom Rx Models:\n\n// toJson(), toString() are deferred to the child, so you can implement override on them, and print() the observable directly.\n\nclass User {\n    String name, last;\n    int age;\n    User({this.name, this.last, this.age});\n\n    @override\n    String toString() => '$name $last, $age years old';\n}\n\nfinal user = User(name: 'John', last: 'Doe', age: 33).obs;\n\n// `user` is \"reactive\", but the properties inside ARE NOT!\n// So, if we change some variable inside of it...\nuser.value.name = 'Roi';\n// The widget will not rebuild!,\n// `Rx` don't have any clue when you change something inside user.\n// So, for custom classes, we need to manually \"notify\" the change.\nuser.refresh();\n\n// or we can use the `update()` method!\nuser.update((value){\n  value.name='Roi';\n});\n\nprint( user );\n```\n\n## StateMixin\n\nAnother way to handle your `UI` state is use the `StateMixin<T>` .\nTo implement it, use the `with` to add the `StateMixin<T>`\nto your controller which allows a T model.\n\n```dart\nclass Controller extends GetController with StateMixin<User>{}\n```\n\nThe `change()` method change the State whenever we want.\nJust pass the data and the status in this way:\n\n```dart\nchange(data, status: RxStatus.success());\n```\n\nRxStatus allow these status:\n\n```dart\nRxStatus.loading();\nRxStatus.success();\nRxStatus.empty();\nRxStatus.error('message');\n```\n\nTo represent it in the UI, use:\n\n```dart\nclass OtherClass extends GetView<Controller> {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n\n      body: controller.obx(\n        (state)=>Text(state.name),\n\n        // here you can put your custom loading indicator, but\n        // by default would be Center(child:CircularProgressIndicator())\n        onLoading: CustomLoadingIndicator(),\n        onEmpty: Text('No data found'),\n\n        // here also you can set your own error widget, but by\n        // default will be an Center(child:Text(error))\n        onError: (error)=>Text(error),\n      ),\n    );\n}\n```\n\n#### GetView\n\nI love this Widget, is so simple, yet, so useful!\n\nIs a `const Stateless` Widget that has a getter `controller` for a registered `Controller`, that's all.\n\n```dart\n class AwesomeController extends GetController {\n   final String title = 'My Awesome View';\n }\n\n  // ALWAYS remember to pass the `Type` you used to register your controller!\n class AwesomeView extends GetView<AwesomeController> {\n   @override\n   Widget build(BuildContext context) {\n     return Container(\n       padding: EdgeInsets.all(20),\n       child: Text(controller.title), // just call `controller.something`\n     );\n   }\n }\n```\n\n#### GetResponsiveView\n\nExtend this widget to build responsive view.\nthis widget contains the `screen` property that have all\ninformation about the screen size and type.\n\n##### How to use it\n\nYou have two options to build it.\n\n- with `builder` method you return the widget to build.\n- with methods `desktop`, `tablet`,`phone`, `watch`. the specific\n  method will be built when the screen type matches the method\n  when the screen is [ScreenType.Tablet] the `tablet` method\n  will be exuded and so on.\n  **Note:** If you use this method please set the property `alwaysUseBuilder` to `false`\n\nWith `settings` property you can set the width limit for the screen types.\n\n![example](https://github.com/SchabanBo/get_page_example/blob/master/docs/Example.gif?raw=true)\nCode to this screen\n[code](https://github.com/SchabanBo/get_page_example/blob/master/lib/pages/responsive_example/responsive_view.dart)\n\n#### GetWidget\n\nMost people have no idea about this Widget, or totally confuse the usage of it.\nThe use case is very rare, but very specific: It `caches` a Controller.\nBecause of the _cache_, can't be a `const Stateless`.\n\n> So, when do you need to \"cache\" a Controller?\n\nIf you use, another \"not so common\" feature of **GetX**: `Get.create()`.\n\n`Get.create(()=>Controller())` will generate a new `Controller` each time you call\n`Get.find<Controller>()`,\n\nThat's where `GetWidget` shines... as you can use it, for example,\nto keep a list of Todo items. So, if the widget gets \"rebuilt\", it will keep the same controller instance.\n\n#### GetxService\n\nThis class is like a `GetxController`, it shares the same lifecycle ( `onInit()`, `onReady()`, `onClose()`).\nBut has no \"logic\" inside of it. It just notifies **GetX** Dependency Injection system, that this subclass\n**can not** be removed from memory.\n\nSo is super useful to keep your \"Services\" always reachable and active with `Get.find()`. Like:\n`ApiService`, `StorageService`, `CacheService`.\n\n```dart\nFuture<void> main() async {\n  await initServices(); /// AWAIT SERVICES INITIALIZATION.\n  runApp(SomeApp());\n}\n\n/// Is a smart move to make your Services intiialize before you run the Flutter app.\n/// as you can control the execution flow (maybe you need to load some Theme configuration,\n/// apiKey, language defined by the User... so load SettingService before running ApiService.\n/// so GetMaterialApp() doesnt have to rebuild, and takes the values directly.\nvoid initServices() async {\n  print('starting services ...');\n  /// Here is where you put get_storage, hive, shared_pref initialization.\n  /// or moor connection, or whatever that's async.\n  await Get.putAsync(() => DbService().init());\n  await Get.putAsync(SettingsService()).init();\n  print('All services started...');\n}\n\nclass DbService extends GetxService {\n  Future<DbService> init() async {\n    print('$runtimeType delays 2 sec');\n    await 2.delay();\n    print('$runtimeType ready!');\n    return this;\n  }\n}\n\nclass SettingsService extends GetxService {\n  void init() async {\n    print('$runtimeType delays 1 sec');\n    await 1.delay();\n    print('$runtimeType ready!');\n  }\n}\n\n```\n\nThe only way to actually delete a `GetxService`, is with `Get.reset()` which is like a\n\"Hot Reboot\" of your app. So remember, if you need absolute persistence of a class instance during the\nlifetime of your app, use `GetxService`.\n\n### Tests\n\nYou can test your controllers like any other class, including their lifecycles:\n\n```dart\nclass Controller extends GetxController {\n  @override\n  void onInit() {\n    super.onInit();\n    //Change value to name2\n    name.value = 'name2';\n  }\n\n  @override\n  void onClose() {\n    name.value = '';\n    super.onClose();\n  }\n\n  final name = 'name1'.obs;\n\n  void changeName() => name.value = 'name3';\n}\n\nvoid main() {\n  test('''\nTest the state of the reactive variable \"name\" across all of its lifecycles''',\n      () {\n    /// You can test the controller without the lifecycle,\n    /// but it's not recommended unless you're not using\n    ///  GetX dependency injection\n    final controller = Controller();\n    expect(controller.name.value, 'name1');\n\n    /// If you are using it, you can test everything,\n    /// including the state of the application after each lifecycle.\n    Get.put(controller); // onInit was called\n    expect(controller.name.value, 'name2');\n\n    /// Test your functions\n    controller.changeName();\n    expect(controller.name.value, 'name3');\n\n    /// onClose was called\n    Get.delete<Controller>();\n\n    expect(controller.name.value, '');\n  });\n}\n```\n\n#### Tips\n\n##### Mockito or mocktail\n\nIf you need to mock your GetxController/GetxService, you should extend GetxController, and mixin it with Mock, that way\n\n```dart\nclass NotificationServiceMock extends GetxService with Mock implements NotificationService {}\n```\n\n##### Using Get.reset()\n\nIf 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.\n\n##### Get.testMode\n\nif you are using your navigation in your controllers, use `Get.testMode = true` at the beginning of your main.\n\n# Breaking changes from 2.0\n\n1- Rx types:\n\n| Before  | After      |\n| ------- | ---------- |\n| StringX | `RxString` |\n| IntX    | `RxInt`    |\n| MapX    | `RxMap`    |\n| ListX   | `RxList`   |\n| NumX    | `RxNum`    |\n| DoubleX | `RxDouble` |\n\nRxController 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.\n\n2- NamedRoutes\nBefore:\n\n```dart\nGetMaterialApp(\n  namedRoutes: {\n    '/': GetRoute(page: Home()),\n  }\n)\n```\n\nNow:\n\n```dart\nGetMaterialApp(\n  getPages: [\n    GetPage(name: '/', page: () => Home()),\n  ]\n)\n```\n\nWhy this change?\nOften, 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.\nInserting 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:\n\n```dart\n\nGetStorage box = GetStorage();\n\nGetMaterialApp(\n  getPages: [\n    GetPage(name: '/', page:(){\n      return box.hasData('token') ? Home() : Login();\n    })\n  ]\n)\n```\n\n# Why Getx?\n\n1- 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.\n\n2- 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.\n\n3- 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.\n\n4- 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.\nIf 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.\n\nThis library will always be updated and implementing new features. Feel free to offer PRs and contribute to them.\n\n# Community\n\n## Community channels\n\nGetX 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.\n\n| **Slack**                                                                                                                   | **Discord**                                                                                                                 | **Telegram**                                                                                                          |\n| :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------- |\n| [![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) |\n\n## How to contribute\n\n_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._\n\n- Helping to translate the readme into other languages.\n- Adding documentation to the readme (a lot of Get's functions haven't been documented yet).\n- Write articles or make videos teaching how to use Get (they will be inserted in the Readme and in the future in our Wiki).\n- Offering PRs for code/tests.\n- Including new functions.\n\nAny contribution is welcome!\n\n## Articles and videos\n\n- [Flutter Getx EcoSystem package for arabic people](https://www.youtube.com/playlist?list=PLV1fXIAyjeuZ6M8m56zajMUwu4uE3-SL0) - Tutorial by [Pesa Coder](https://github.com/UsamaElgendy).\n- [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).\n- [Complete GetX™ Navigation](https://www.youtube.com/watch?v=RaqPIoJSTtI) - Route management video by Amateur Coder.\n- [Complete GetX State Management](https://www.youtube.com/watch?v=CNpXbeI_slw) - State management video by Amateur Coder.\n- [GetX™ Other Features](https://youtu.be/ttQtlX_Q0eU) - Utils, storage, bindings and other features video by Amateur Coder.\n- [Firestore User with GetX | Todo App](https://www.youtube.com/watch?v=BiV0DcXgk58) - Video by Amateur Coder.\n- [Firebase Auth with GetX | Todo App](https://www.youtube.com/watch?v=-H-T_BSgfOE) - Video by Amateur Coder.\n- [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).\n- [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).\n- [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.\n- [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.\n- [GetX Flutter Firebase Auth Example](https://medium.com/@jeffmcmorris/getx-flutter-firebase-auth-example-b383c1dd1de2) - Article by Jeff McMorris.\n- [Flutter State Management with GetX – Complete App](https://www.appwithflutter.com/flutter-state-management-with-getx/) - by App With Flutter.\n- [Flutter Routing with Animation using Get Package](https://www.appwithflutter.com/flutter-routing-using-get-package/) - by App With Flutter.\n- [A minimal example on dartpad](https://dartpad.dev/2b3d0d6f9d4e312c5fdbefc414c1727e?) - by [Roi Peker](https://github.com/roipeker)\n- [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)\n- [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)\n"
  },
  {
    "path": "README.pl.md",
    "content": "![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png)\n\n*Languages: [English](README.md), [Wietnamski](README-vi.md), [Indonezyjski](README.id-ID.md), [Urdu](README.ur-PK.md), [Język chiński](README.zh-cn.md), [Brazilian Portuguese](README.pt-br.md), [Spanish](README-es.md), [Russian](README.ru.md),  Polish (Jesteś tu), [Koreański](README.ko-kr.md), [French](README-fr.md)*\n\n[![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)\n[![popularity](https://badges.bar/get/popularity)](https://pub.dev/packages/sentry/score)\n[![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)\n[![pub points](https://badges.bar/get/pub%20points)](https://pub.dev/packages/get/score)\n![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)\n[![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart)\n[![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N)\n[![Get on Slack](https://img.shields.io/badge/slack-join-orange.svg)](https://communityinviter.com/apps/getxworkspace/getx)\n[![Telegram](https://img.shields.io/badge/chat-on%20Telegram-blue.svg)](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g)\n<a href=\"https://github.com/Solido/awesome-flutter\">\n   <img alt=\"Awesome Flutter\" src=\"https://img.shields.io/badge/Awesome-Flutter-blue.svg?longCache=true&style=flat-square\" />\n</a>\n<a href=\"https://www.buymeacoffee.com/jonataslaw\" target=\"_blank\"><img src=\"https://i.imgur.com/aV6DDA7.png\" alt=\"Buy Me A Coffee\" style=\"height: 41px !important;width: 174px !important; box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;\" > </a>\n\n\n![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/getx.png)\n\n- [Kanały komunikacji i wsparcia:](#kanały-komunikacji-i-wsparcia)\n- [Wprowadzenie](#wprowadzenie)\n- [Instalacja](#instalacja)\n- [Counter App z GetX](#counter-app-z-getx)\n- [Trzy filary](#trzy-filary)\n  - [Menadżer stanu](#menadżer-stanu)\n    - [Reaktywny menadżer stanu](#reaktywny-menadżer-stanu)\n    - [Bardziej szczegółowo o menadżerze stanu](#bardziej-szczegółowo-o-menadżerze-stanu)\n    - [Video tłumaczące użycie menadżera stanu](#video-tłumaczące-użycie-menadżera-stanu)\n  - [Zarządzanie routami](#zarządzanie-routami)\n    - [Więcej o routach](#więcej-o-routach)\n    - [Video tłumaczące użycie](#video-tłumaczące-użycie)\n  - [Zarządzanie dependencies](#zarządzanie-dependencies)\n    - [Bardziej szczegółowo o menadżerze dependencies](#bardziej-szczegółowo-o-menadżerze-dependencies)\n- [Jak włożyć coś od siebie](#jak-włożyć-coś-od-siebie)\n- [Narzędzia](#narzędzia)\n  - [Zmiana motywu](#zmiana-motywu)\n  - [Inne zaawansowane API](#inne-zaawansowane-api)\n    - [Opcjonalne globalne ustawienia i manualna konfiguracja](#opcjonalne-globalne-ustawienia-i-manualna-konfiguracja)\n  - [Video tłumaczące inne funkcjonalności GetX](#video-tłumaczące-inne-funkcjonalności-getx)\n- [Zmiany od 2.0](#zmiany-od-20)\n\n\n# Kanały komunikacji i wsparcia:\n\n[**Slack (English)**](https://communityinviter.com/apps/getxworkspace/getx)\n\n[**Discord (English and Portuguese)**](https://discord.com/invite/9Hpt99N)\n\n[**Telegram (Portuguese)**](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g)\n\n# Wprowadzenie\n- GetX jest bardzo lekką, a zarazem potężną biblioteką do Flattera. Łączy wysoką wydajność menadżera stanu, inteligętne dodawanie dependencies i zarządzanie routami w szybki i praktyczny sposób.\n- GetX nie jest dla wszystkich, skupia się na jak najmniejszej konsumpcji zasobów (wydajności) ([zobacz benchmarki](https://github.com/jonataslaw/benchmarks)), używaniu łatwej skłani (produktywności) i daniu możliwości pełnego rozbicia View na z logiki biznesowej (organizacja).\n- GetX da Ci supermoce i zwiększy produktywność w tworzeniu projektu. Oszczędzi godziny zarówno początkującym jak i ekspertom.\n-  Nawiguj bez podawania `context`, używaj open `dialogs`, `snackbarów` oraz `bottomsheetów` z każdego miejsca w kodzie. Zarządzaj stanami i dodawaj dependencies w prosty i praktyczny sposób!\n- Get jest bezpieczny, stabilny i aktualny. Oprócz tego oferuje szeroki zakres API, które nie są zawarte w standardowym frameworku.\n- GetX nie jest przytłaczający. Ma wiele funkcjonalności pozwalajacych na rozpoczęcie programowania bez martwienia się zupełnie nic. Wszystkie funkcjonalności są w osobnych kontenerach, które dodawane są dopiero po ich użyciu. Jeśli tylko używasz menadżera stanu, tylko on będzie kompilowany. Jeśli używasz routów, lecz nic z menadżera stanu to nie będzie on kompilowany. Możesz skompilować repozytorium benchmark i zobaczysz że używa tylko menadżera stanu. Aplikacje używajace Get są mniejsze niz inne, ponieważ wszystkie rozwiązania GetX są projektowane z myślą o lekkości i wydajności. Jest to też zasługa Flutterowego AOT, które jest niesamowite i eliminuje nieużywane zasoby jak żaden inny framework.\n\n**GetX zwiększa twoja produktywność, lecz możesz to jeszcze przyspieszyć instalując rozszerzenie [GetX extension](https://marketplace.visualstudio.com/items?itemName=get-snippets.get-snippets) do swojego VSCode**. Jeszcze nie dostępne w innych IDE.\n\n# Instalacja\n\nDodaj Get do swojego pliku pubspec.yaml:\n\n```yaml\ndependencies:\n  get:\n```\n\nZaimportuj Get do plików w których chcesz go użyć:\n\n```dart\nimport 'package:get/get.dart';\n```\n\n# Counter App z GetX\n\nPrzykładowa aplikaja tworzona domyślnie podczas kreacji nowego projektu we Flaterze ma ponad 100 lini kodu (z komentarzami). By pokazać siłę Get pokażę jak zrobić \"licznik\" ze zmianą stanu przy każdym kliknięciu, zmianą stron i udostępniajac stan pomiędzy ekranami. Wszystko w zorganizowany sposób dzieląc bussines logic z view w zaledwie 26 LINI KODU WŁĄCZAJĄC W TO KOMENTARZE.\n\n-Krok 1:\nDodaj \"Get\" przed MaterialApp, zamieniając je na GetMaterialApp\n\n\n```dart\nvoid main() => runApp(GetMaterialApp(home: Home()));\n```\n\n- Note: nie jest to modyfikaja MaterialApp, ponieważ GetMaterialApp nie jest zmodyfikowanym MaterialApp z Fluttera, jest tylko skonfigurowanym Widgetem mającym domyślnie MaterialApp jako dziecko. Możesz to konfigurować ręcznie, ale nie jest to konieczne. GetMaterialApp jest niezbędne dla działania routów, snackbarów, bootomsheetów, internacjonalizacji, dialogów i wysokopoziomowych api powiązanych z routami i nieobecnościa kontekstu. Nie jest to jednak wymagane do używania zarzadzania stanem i dependencies.\n\n-Krok 2:\nTworzymy klasę business logic i umieszczmy w niej wszystkie zmienne, metody oraz kontrolery. Możesz zmienić zmiennaą na obserwowalną używajac prostego subfixu \".obs\"\n\n```dart\nclass Controller extends GetxController{\n  var count = 0.obs;\n  increment() => count.value++;\n}\n```\n- Krok 3: \nTworzymy View. Użyj StatelessWidget oszczędzajac przy tym RAM. Z Get nie będzie Ci potrzebny StatefullWidget.\n\n\n```dart\nclass Home extends StatelessWidget {\n\n  @override\n  Widget build(context) {\n\n    // Instantiate your class using Get.put() to make it available for all \"child\" routes there.\n    final Controller c = Get.put(Controller());\n\n    return Scaffold(\n      // Use Obx(()=> to update Text() whenever count is changed.\n      appBar: AppBar(title: Obx(() => Text(\"Clicks: \" + c.count.string))),\n\n      // Replace the 8 lines Navigator.push by a simple Get.to(). You don't need context\n      body: Center(child: ElevatedButton(\n              child: Text(\"Go to Other\"), onPressed: () => Get.to(Other()))),\n      floatingActionButton:\n          FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment));\n  }\n}\n\nclass Other extends StatelessWidget {\n  // You can ask Get to find a Controller that is being used by another page and redirect you to it.\n  final Controller c = Get.find();\n\n  @override\n  Widget build(context){\n     // Access the updated count variable\n     return Scaffold(body: Center(child: Text(c.count.string)));\n  }\n}\n```\nWynik:\n\n![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/counter-app-gif.gif)\n\nJest to prosty projekt, ale już na jego przykładzie widać potęgę Get. Wraz ze wzrostem rozmiaru aplikacji ta różnica tylko się powiększa.\n\nGet był projektowany dla pracy z zespołem, ale równie dobrze sprawdza się w indywidualnych projektach.\n\nZawsze dotrzymuj deadlinów i dostarczaj swoje rozwiązania na czas bez straty na wydajności. Get nie jest dla wszystkich jak już wspominałem, ale jeśli identyfikujesz się z powyższym zdaniem Get jest właśnie dla Ciebie.\n\n# Trzy filary\n\n## Menadżer stanu\n\nObecnie istnieje kilka menadżeów dla Fluttera. Jednak większość z nich wymaga używania ChangeNotifier, po to aby zaktualizować widżety, co nie sprawdza się pod kątem wydajności w średnich i dużych aplikacach. Możesz sprawdzić w oficjalnej dokumentacji, że ChangeNotifier powinien być używany z maksimum dwoma listinerami (https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html), będąc praktycznie bezużytecznym w średnich i duzych projektach. \n\nGet nie jest ani lepszy, ani gorszy od innych menadżerów stanów, ale powinieneś rozpatrzyć te punkty jak i poniższe, aby wybrać między użyciem Get w czystej formie (Vanilla), albo używaniem go wraz z innym menadżerem. \n\nDefinitywnie Get nie jest przeciwnikiem żadnego innego menadżera, ponieważ jest on mikroframeworkiem, nie tylko menadżerem stanu. Może być użyty samodzielnie, lub w koegzystencji.\n\nGet ma bardzo lekki i prosty menadżer stanu (napisany w tylko 95 lini kodu), który nie używa ChangeNotifier. Sprosta on wymaganiom szczególnie nowych we Flutterze i nie sprawi problemu nawet w dużych aplikacjach.\n\n### Reaktywny menadżer stanu\n\nReaktywne programowanie może odtrącać niektórych, ponieważ powszechnie jest uważane za skomplikowane. GetX zamienia to w coś prostego:\n\n- Nie musisz tworzyć StreamControllerów,\n- Nie musisz tworzyć StreamBuildera dla każdej zmiennej,\n- Nie ma potrzeby tworzenia klasy dla każdego stanu,\n- Nie musisz tworzyć Get dla inicjalnej zmiennej\n\nWyobraź sobie, że masz zmienną i za każdym razem jak zmienisz ją chcesz żeby wszystkie widżety używające jej automatycznie się zmieniły\n\nPrzykładowa zmienna:\n```dart\nvar name = 'Jonatas Borges';\n```\n\nBy zamienić ją na obserwowalną dodaj \".obx\" na końcu:\n\n```dart\nvar name = 'Jonatas Borges'.obs;\n```\n\nI w UI, kiedy chcesz go zaktualizować przy modyfikacji zmiennej po prostu dodaj to:\n```dart\nObx (() => Text (controller.name));\n```\n\nTo wszystko. *Proste*, co nie?\n\n### Bardziej szczegółowo o menadżerze stanu\n**Zobacz bardziej szczegółowe wytłumaczenie menadżera stanu [tutaj](./documentation/en_US/state_management.md). Znajdują się  tam przykłady jak o różnice między prostym menadżerem stanu oraz reaktywnym**\n\n### Video tłumaczące użycie menadżera stanu\n\nTadas Petra nagrał o tym niezwykły film: \n\nLink: [Complete GetX State Management](https://www.youtube.com/watch?v=CNpXbeI_slw)\n\n## Zarządzanie routami\n\nJeśli chcesz używać routes/snackbars/dialogs/bottomsheets z GetX możesz to robić bez contextu.\n \nZamień MaterialApp na GetMaterialApp\n```dart\nGetMaterialApp( // Before: MaterialApp(\n  home: MyHome(),\n)\n```\n\nBy nawigować do nowego ekranu:\n\n```dart\nGet.to(NextScreen());\n```\n\nBy powrócić do poprzedniego ekranu\n\n```dart\nGet.back();\n```\n\nBy przejść do następnego ekranu bez możliwości powrotu do poprzedniego (do zastosowania SplashScreenów, ekranów logowania itd.)\n\n```dart\nGet.off(NextScreen());\n```\n\nBy przejść do następnego ekranu niszcząc poprzednie routy (użyteczne w koszykach, ankietach i testach)\n\n```dart\nGet.offAll(NextScreen());\n```\n\nBy nawigować do następnego routa i otrzymać, lub uaktualnić dane zaraz po tym jak z niego wrócisz:\n```dart\nvar data = await Get.to(Payment());\n```\nw innym ekranie wyślij dane z poprzedniego routa:featury\n\n```dart\nGet.back(result: 'sucess');\n```\nI użyj następujące np.:\n```dart\nif(data == 'sucess') madeAnything();\n```\nZobacz, ze do żadnej z tych operacji nie potrzebowałeś contextu. Jest to jedna z głównych zalet GetX oszczędzającego na niepotrzebnej obudowie w kod i dającego możliwość używania tych metod w klasie kontrolera.\n\n\n### Więcej o routach\n\n**Get używa named routes oraz oferuje niskopoziomową obsługę routów! Zobacz bardziej szczegółową dokumentacje [tutaj](./documentation/en_US/route_management.md)**\n\n### Video tłumaczące użycie\n\nTadas Petra nagrał o tym niezwykły film: \n\nLink: [Complete GetX Navigation](https://www.youtube.com/watch?v=RaqPIoJSTtI)\n\n## Zarządzanie dependencies\n\nGet  ma prosty, a zarazem potężny menadżer dependencies. Pozwala on na otrzymanie tych samych klas jak twoje Bloc lub Kontroler pisząc jedną linię kodu bez Provider context i inheritedWidget:\n\n```dart\nController controller = Get.put(Controller()); // Rather Controller controller = Controller();\n```\n\n- Note: Jeśli używasz menadżera stanu Get zwróć uwagę na binding api, które pozwoli Ci łatwiej połączyć twój widok z kontrolerem.\nhttps://github.com/jonataslaw/get\n**Tip:** Menadżer dependency Get jest oddzielony od innych części pakietu więc jeśli już używasz menadżera stanu(którego kolwiek, bez różnicy) nie musisz przepisywać tego wszystkiego na nowo. Możesz używać tego dodawania dependencies bez poroblemu.\n\n```dart\ncontroller.fetchApi();\n```\nWyobraź sobie, że musisz nawigować pomiędzy wieloma routami i potrzebujesz dane z kontrolerów z poprzednich ekranów. Musiałbyś użyć menadżera stanu z dodatkiem Providera albo Get_it, prawda? Otóż nie z Fet. Musisz po prostu poprosić Get o znalezienie tego kontrolera i nie potrzebujesz przy tym dodatkowych dependencies.\n\n```dart\nController controller = Get.find();\n//Tak, to wygląda jak Magia, Get znjadzie Twój kontroler i Ci go dostarczy. Możesz mieć nawet MILION kontrolerów, a Get zawsze da Ci prawidłowy kontroler.\n```\n\nI wtedy będziesz mógł otrzymać z niego dane bez żadnego problemu\n\n```dart\nText(controller.textFromApi);\n```\n### Bardziej szczegółowo o menadżerze dependencies\n\n**Zobzcz więcej w dokumentacji [tutaj](./documentation/en_US/dependency_management.md)**\n\n# Jak włożyć coś od siebie\n\nMożesz uczestniczyć w rozwoju projektu na różny sposób:\n- Pomagając w tłumaczeniu readme na inne języki.\n- Dodając dokumentację do readme (nawet połowa funkcji została jeszcze opisana).\n- Pisząc artykuły i nagrywając filmy pokazujące użycie biblioteki Get (będą zamieszczone w readme, a w przyszłości na naszej Wiki).\n- Oferując PR-y dla kodu i testów.\n- Dodając nowe funkcje.\n\nKażda współpraca jest mile widziana!\n\n# Narzędzia\n\n## Zmiana motywu\n\nNie powinno się używać innego widżetu niż GetMaterialApp by go zaktualizować. To może powodować duplikacje kluczy. Wiele osób nawykło do prehistorycznego podejścia tworzenia widżetu \"ThemeProvider\" tylko po to by zmienić motyw aplikacji. Z Get nie jest to wymagane.\n\nMożesz stworzyć customowy motyw i łatwo go dodać z Get.changeTheme bez niepotrzebnego kodu.\n\n```dart\nGet.changeTheme(ThemeData.light());\n```\n\nJeśli chcesz stworzyć coś jak przycisk zmieniający motyw aplikacji na onTap, możesz połączyć dwia Get API. Api sprawdzające czy ciemny motyw jest używany i Api zajmujące się zmianą motywu. Po prostu użyj tego w onPressed:\n\n```dart\nGet.changeTheme(Get.isDarkMode? ThemeData.light(): ThemeData.dark());featury\n```\n\nKiedy ciemny motyw jest aktywny zmieni się on na jasny, w przeciwnym wypadku zmieni się na ciemny.\n\nJeśli interesuje Cię jak zmieniać motywy podążaj za samouczkiem na Medium pokazującum zmianę motywu przy użyciu Get:\n\n- [Dynamic Themes in 3 lines using Get](https://medium.com/swlh/flutter-dynamic-themes-in-3-lines-c3b375f292e3) - Samouczek stworzony przez [Rod Brown](https://github.com/RodBr).\n\n## Inne zaawansowane API\n\n```dart\n// give the current args from currentScreen\nGet.arguments\n\n// give name of previous route\nGet.previousRoute\n\n// give the raw route to access for example, rawRoute.isFirst()\nGet.rawRoute\n\n// give access to Rounting API from GetObserver\nGet.routing\n\n// check if snackbar is open\nGet.isSnackbarOpen\n\n// check if dialog is open\nGet.isDialogOpen\n\n// check if bottomsheet is opefeaturyn\nGet.isBottomSheetOpen\n\n// remove one route.\nGet.removeRoute()\n\n// back repeatedly until the predicate returns true.\nGet.until()\n\n// go to next route and remove all the previous routes until the predicate returns true.\nGet.offUntil()\n\n// go to next named route and remove all the previous routes until the predicate returns true.\nGet.offNamedUntil()\n\n//Check in what platform the app is running\nGetPlatform.isAndroid\nGetPlatform.isIOS\nGetPlatform.isWeb\n\n// Equivalent to the method: MediaQuery.of(context).size.height, but they are immutable.\nGet.height\nGet.width\n\n// Gives the current context of navigator.\nGet.context\n\n// Gives the context of the snackbar/dialog/bottomsheet in the foreground anywhere in your code.\nGet.contextOverlay\n\n// Note: the following methods are extensions on context. Since you\n// have access to context in any place of your UI, you can use it anywhere in the UI code\n\n// If you need a changeable height/width (like browser windows that can be scfeaturyaled) you will need to use context.\ncontext.width\ncontext.height\n \n// gives you the power to define half the screen now, a third of it and so on.\n//Useful for responsive applications.\n// param dividedBy (double) optional - default: 1\n// param reducedBy (double) optional - default: 0\ncontext.heightTransformer()\ncontext.widthTransformer()\n\n/// similar to MediaQuery.of(context).size\ncontext.mediaQuerySize()\n\n/// similar to MediaQuery.of(context).padding\ncontext.mediaQueryPadding()\n\n/// similar to MediaQuery.of(context).viewPadding\ncontext.mediaQueryViewPadding()\n\n/// similar to MediaQuery.of(context).viewInsets;\ncontext.mediaQueryViewInsets()\n\n/// similar to MediaQuery.of(context).orientation;\ncontext.orientation()\n\n/// check if device is on landscape mode\ncontext.isLandscape()\n\n/// check if device is on portrait mode\ncontext.isPortrait()\n\n/// similar to MediaQuery.of(context).devicePixelRatio;\ncontext.devicePixelRatio()\n\n/// similar to MediaQuery.of(context).textScaleFactor;\ncontext.textScaleFactor()\n\n/// get the shortestSide from screen\ncontext.mediaQueryShortestSide()\n\n/// True if width be larger thfeaturyan 800\ncontext.showNavbar()\n\n/// True if the shortestSide is smaller than 600p\ncontext.isPhone()\n\n/// True if the shortestSide is largest than 600p\ncontext.isSmallTablet()\n\n/// True if the shortestSide is largest than 720p\ncontext.isLargeTablet()\n\n/// True if the current device is Tablet\ncontext.isTablet()\n```\n\n### Opcjonalne globalne ustawienia i manualna konfiguracja\n\nGetMaterialApp konfiguruje wszystko za Ciebie, ale jeśli chcesz możesz konfigurować Get manualnie.\n\n```dart\nMaterialApp(\n  navigatorKey: Get.key,\n  navigatorObservers: [GetObserver()],\n);\n```\n\nBędziesz mógł używać swojego Midware z GetObserver, nie wpływa to na nic.\n\n```dart\nMaterialApp(\n  navigatorKey: Get.key,\n  navigatorObservers: [\n    GetObserver(MiddleWare.observer) // Here\n  ],\n);\n```\n\nMozesz stworzyć globalne ustawienia dla Get. Tylko dodaj Get.config do swojego kodu przed użyciem routów, lub bezpośrednio w GetMaterialApp\n\n```dart\nGetMaterialApp(\n  enableLog: true,\n  defaultTransition: Transition.fade,\n  opaqueRoute: Get.isOpaqueRouteDefault,\n  popGesture: Get.isPopGestureEnable,\n  transitionDuration: Get.defaultDurationTransition,\n  defaultGlobalState: Get.defaultGlobalState,https://github.com/jonataslaw/ge\n);\n\nGet.config(\n  enableLog = true,\n  defaultPopGesture = true,\n  defaultTransition = Transitions.cupertino\n)\n```\n\nOpcjonalnie możesz przekierować wszystkie logi z Get by używać swojej ulubionej paczki i zbierać w niej logi.\n\n```dart\nGetMaterialApp(\n  enableLog: true,\n    logWriterCallback: localLogWriter,\n\t);\n\tvoid localLogWriter(String text, {bool isError = false}) {\n\t  // tutaj przekaż wiadomosci do ulubionej paczki\n\t    // pamiętaj że nawet jeśli \"enableLog: false\" logi i tak będą wysłane w tym callbacku\n\t\t  // Musisz sprawdzić konfiguracje flag  jeśli chcesz przez GetConfig.isLogEnable\n\t\t  }\n```\n## Video tłumaczące inne funkcjonalności GetX\n\n\nTadas Petra nagrał niezwykły film tłumaczący powyższe zagadnienia! \n\nLink: [GetX Other Features](https://youtu.be/ttQtlX_Q0eU)\n\n\n# Zmiany od 2.0\n\n1- Typy Rx:\n\n| Przed   | Po         |\n| ------- | ---------- |\n| StringX | `RxString` |\n| IntX    | `RxInt`    |\n| MapX    | `RxMax`    |\n| ListX   | `RxList`   |\n| NumX    | `RxNum`    |\n| DoubleX | `RxDouble` |\n\nRXController i GetBuilder teraz zostały połączone. Nie musisz już pamiętać którego kontrolera chcesz użyć, po prostu korzystaj z GetxController, będzie działać zarówno dla prostego jak i reaktywnego menadżera stanów.\n\n2- NamedRoutes\nWcześniej:\n\n```dart\nGetMaterialApp(\n  namedRoutes: {\n    '/': GetRoute(page: Home()),\n  }\n)\n```\n\nTeraz:\n\n```dart\nGetMaterialApp(\n  getPages: [\n    GetPage(name: '/', page: () => Home()),\n  ]\n)\n```\n\nPo co ta zmiana?\nCzęsto może być niezbędnym decydowanie która strona będzie wyświetlana w zależności od parametru, lub tokenu logowania. Wczesniejsze podejście było nieelastyczne, ponieważ na to nie pozwalało. Zawarcie strony w funkcji zmniejszyło sporzycie RAM-u, ze względu na niealokowanie routów od początku działania aplikacji. Pozwoliło to także na takie podejscie:\n\n```dart\n\nGetStorage box = GetStorage();\n\nGetMaterialApp(\n  getPages: [\n    GetPage(name: '/', page:(){  \n      return box.hasData('token') ? Home() : Login();\n    })\n  ]\n)\n```\n"
  },
  {
    "path": "README.pt-br.md",
    "content": "![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png)\n\n**Idiomas: [Inglês](README.md), [Vietnamita](README-vi.md), [Indonésia](README.id-ID.md), [Urdu](README.ur-PK.md), [Chinês](README.zh-cn.md), Português (este arquivo), [Espanhol](README-es.md), [Russo](README.ru.md), [Polonês](README.pl.md), [Coreano](README.ko-kr.md), [Francês](README-fr.md)**\n\n[![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)\n[![popularity](https://badges.bar/get/popularity)](https://pub.dev/packages/sentry/score)\n[![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)\n[![pub points](https://badges.bar/get/pub%20points)](https://pub.dev/packages/get/score)\n![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)\n[![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart)\n[![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N)\n[![Get on Slack](https://img.shields.io/badge/slack-join-orange.svg)](https://communityinviter.com/apps/getxworkspace/getx)\n[![Telegram](https://img.shields.io/badge/chat-on%20Telegram-blue.svg)](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g)\n<a href=\"https://github.com/Solido/awesome-flutter\">\n   <img alt=\"Awesome Flutter\" src=\"https://img.shields.io/badge/Awesome-Flutter-blue.svg?longCache=true&style=flat-square\" />\n</a>\n<a href=\"https://www.buymeacoffee.com/jonataslaw\" target=\"_blank\"><img src=\"https://i.imgur.com/aV6DDA7.png\" alt=\"Buy Me A Coffee\" style=\"height: 41px !important;width: 174px !important; box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;\" > </a>\n\n\n![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/getx.png)\n\n<h2> Pedimos desculpas por qualquer parte não traduzida aqui. O GetX™ é atualizado com muita frequência e as traduções podem não vir ao mesmo tempo. Então, para manter essa documentação pelo menos com tudo que a versão em inglês tem, eu vou deixar todos os textos não-traduzidos aqui (eu considero que é melhor ele estar lá em inglês do que não estar), então se alguém quiser traduzir, seria muito útil 😁</h2>\n\n- [Sobre Get](#sobre-get)\n- [Instalando](#instalando)\n- [App Counter usando GetX](#app-counter-usando-getx)\n- [Os três pilares](#os-três-pilares)\n  - [Gerenciamento de estado](#gerenciamento-de-estado)\n    - [Reactive state manager](#reactive-state-manager)\n    - [Mais detalhes sobre gerenciamento de estado](#mais-detalhes-sobre-gerenciamento-de-estado)\n    - [Explicação em video do gerenciamento de estado](#explicação-em-video-do-gerenciamento-de-estado)\n  - [Gerenciamento de rotas](#gerenciamento-de-rotas)\n    - [Mais detalhes sobre gerenciamento de rotas](#mais-detalhes-sobre-gerenciamento-de-rotas)\n    - [Explicação em video do gerenciamento de rotas](#explicação-em-video-do-gerenciamento-de-rotas)\n  - [Gerenciamento de Dependência](#gerenciamento-de-dependência)\n    - [Mais detalhes sobre gerenciamento de dependências](#mais-detalhes-sobre-gerenciamento-de-dependências)\n- [Utilidades](#utilidades)\n  - [Internacionalização](#internacionalização)\n    - [Traduções](#traduções)\n      - [Usando traduções](#usando-traduções)\n    - [Localidade](#localidade)\n      - [Alterar local](#alterar-local)\n      - [Localidade do sistema operacional](#localidade-do-sistema-operacional)\n  - [Mudar tema (changeTheme)](#mudar-tema-changetheme)\n  - [GetConnect](#getconnect)\n    - [Configuração Padrão](#configuração-padrão)\n    - [Configuração Personalizada](#configuração-personalizada)\n  - [GetPage Middleware](#getpage-middleware)\n    - [Priority](#priority)\n    - [Redirect](#redirect)\n    - [onPageCalled](#onpagecalled)\n    - [OnBindingsStart](#onbindingsstart)\n    - [OnPageBuildStart](#onpagebuildstart)\n    - [OnPageBuilt](#onpagebuilt)\n    - [OnPageDispose](#onpagedispose)\n  - [Outras APIs avançadas](#outras-apis-avançadas)\n    - [Configurações Globais opcionais e configurações manuais](#configurações-globais-opcionais-e-configurações-manuais)\n    - [Widgets de Estado Local](#widgets-de-estado-local)\n      - [ValueBuilder](#valuebuilder)\n      - [ObxValue](#obxvalue)\n    - [Explicação em vídeo sobre Outras Features do GetX](#explicação-em-vídeo-sobre-outras-features-do-getx)\n  - [Dicas Úteis](#dicas-úteis)\n      - [GetView](#getview)\n      - [GetWidget](#getwidget)\n      - [GetxService](#getxservice)\n- [Breaking Changes da versão 2 para 3](#breaking-changes-da-versão-2-para-3)\n  - [Tipagem Rx](#tipagem-rx)\n  - [RxController e GetBuilder se uniram](#rxcontroller-e-getbuilder-se-uniram)\n  - [Rotas nomeadas](#rotas-nomeadas)\n    - [Porque essa mudança?](#porque-essa-mudança)\n- [Por que GetX™?](#por-que-getx)\n- [Comunidade](#comunidade)\n  - [Canais da comunidade](#canais-da-comunidade)\n  - [Como contribuir](#como-contribuir)\n  - [Artigos e vídeos](#artigos-e-vídeos)\n\n# Sobre Get\n\n- Get é uma biblioteca poderosa e extraleve para Flutter. Ela combina um gerenciador de estado de alta performance, injeção de dependência inteligente e gerenciamento de rotas de uma forma rápida e prática.\n\n- GetX™ possui 3 princípios básicos, o que significa que esta é a prioridade para todos os recursos da biblioteca: **PRODUTIVIDADE, PERFORMANCE AND ORGANIZAÇÃO.**\n\n  - **PERFOMANCE**: GetX™ é focado em desempenho e consumo mínimo de recursos. GetX não usa Streams ou ChangeNotifier. \n\n  - **PRODUTIVIDADE**: GetX™ usa uma sintaxe fácil e agradável. Não importa o que você queira fazer, sempre há uma maneira mais fácil com GetX™. Isso economizará horas de desenvolvimento e extrairá o máximo de desempenho que seu aplicativo pode oferecer.\n  Geralmente, o desenvolvedor deve se preocupar em remover os controladores da memória. Com GetX™, isso não é necessário porque, por padrão, os recursos são removidos da memória quando não são usados. Se quiser mantê-lo na memória, você deve declarar explicitamente \"permanent: true\" em sua dependência. Dessa forma, além de economizar tempo, você corre menos risco de ter dependências desnecessárias na memória. O carregamento da dependência também é lazy por padrão.\n\n  - **ORGANIZAÇÃO**: GetX™ permite o desacoplamento total da View, lógica de apresentação, lógica de negócios, injeção de dependência e navegação. Você não precisa de contexto para navegar entre as rotas, portanto, você não depende da árvore do widget (visualização) para isso. Você não precisa de contexto para acessar seus Controllers/BLoCs por meio de um inheritedWidget, então você desacopla completamente sua lógica de apresentação e lógica de negócios de sua camada de visualização. Você não precisa injetar suas classes Controllers/Models/BLoCs em sua árvore de widgets através de multiproviders, pois GetX™ usa seu próprio recurso de injeção de dependência, desacoplando a DI de sua View completamente. \n  Com GetX™ você sabe onde encontrar cada recurso de sua aplicação, tendo o código limpo por padrão. Isso além de facilitar a manutenção, torna o compartilhamento dos módulos, algo que até então em Flutter era impensável, em algo totalmente possível.\n  O BLoC foi um ponto de partida para organizar o código no Flutter, ele separa a lógica de negócios da visualização. GetX™ é uma evolução natural disso, separando não apenas a lógica de negócios, mas a lógica de apresentação. O bônus da injeção de dependências e rotas também são dissociadas e a camada de dados está fora de tudo. Você sabe onde está tudo e tudo isso de uma maneira mais fácil do que construir um hello world. \n  GetX™ é a maneira mais fácil, prática e escalonável de construir aplicativos de alto desempenho com o Flutter SDK, com um grande ecossistema em torno dele que funciona perfeitamente em conjunto, sendo fácil para iniciantes e preciso para especialistas. É seguro, estável, atualizado e oferece uma grande variedade de APIs integradas que não estão presentes no Flutter SDK padrão.\n\n- GetX™ não é inchado. Possui uma infinidade de recursos que permitem que você comece a programar sem se preocupar com nada, mas cada um desses recursos está em contêineres separados e só são iniciados após o uso. Se você usar apenas o Gerenciamento de estado, apenas o Gerenciamento de estado será compilado. Se você usar apenas rotas, nada do gerenciamento de estado será compilado. \n\n- GetX™ possui um enorme ecossistema, uma grande comunidade, um grande número de colaboradores e será mantido enquanto o Flutter existir. Getx também é capaz de rodar com o mesmo código no Android, iOS, Web, Mac, Linux, Windows e em seu servidor.\n**É possível reutilizar totalmente seu código feito no frontend em seu backend com [Get Server](https://github.com/jonataslaw/get_server)**.\n\n**Além disso, todo o processo de desenvolvimento pode ser totalmente automatizado, tanto no servidor quanto no front-end com **[Get CLI](https://github.com/jonataslaw/get_cli)**.\n\n**Além disso, para aumentar ainda mais sua produtividade, temos a [extensão para VSCode](https://marketplace.visualstudio.com/items?itemName=get-snippets.get-snippets) e a [extensão para Android Studio/Intellij](https://plugins.jetbrains.com/plugin/14975-getx-snippets)**\n\n# Instalando\n\nAdicione Get ao seu arquivo pubspec.yaml\n\n```yaml\ndependencies:\n  get:\n```\n\nImporte o get nos arquivos que ele for usado:\n\n```dart\nimport 'package:get/get.dart';\n```\n\n# App Counter usando GetX\n\nO app 'Counter' criado por padrão no flutter com o comando `flutter create` tem mais de 100 linhas(incluindo os comentários). Para demonstrar o poder do Get, irei demonstrar como fazer o mesmo 'Counter' mudando o estado em cada toque trocando entre páginas e compartilhando o estado entre telas. Tudo de forma organizada, separando a lógica de negócio da View, COM SOMENTE 26 LINHAS INCLUINDO COMENTÁRIOS\n\n- Passo 1:\nTroque `MaterialApp` para `GetMaterialApp`\n\n```dart\nvoid main() => runApp(GetMaterialApp(home: Home()));\n```\n\n- **Obs:** Isso não modifica o `MaterialApp` do Flutter, GetMaterialApp não é uma versão modificada do MaterialApp, é só um Widget pré-configurado, que tem como child o MaterialApp padrão. Você pode configurar isso manualmente, mas definitivamente não é necessário. GetMaterialApp vai criar rotas, injetá-las, injetar traduções, injetar tudo que você precisa para navegação por rotas (gerenciamento de rotas). Se você quer somente usar o gerenciador de estado ou somente o gerenciador de dependências, não é necessário usar o GetMaterialApp. Ele somente é necessário para:\n  - Rotas\n  - Snackbars/bottomsheets/dialogs\n  - apis relacionadas a rotas e a ausência de `context`\n  - Internacionalização\n- **Obs²:** Esse passo só é necessário se você for usar o gerenciamento de rotas (`Get.to()`, `Get.back()` e assim por diante), Se você não vai usar isso então não é necessário seguir o passo 1\n\n- Passo 2:\nCria a sua classe de regra de negócio e coloque todas as variáveis, métodos e controllers dentro dela.\nVocê pode fazer qualquer variável observável usando um simples `.obs`\n\n```dart\nclass Controller extends GetxController{\n  var count = 0.obs;\n  increment() => count.value++;\n}\n```\n\n- Passo 3:\nCrie sua View usando StatelessWidget, já que, usando Get, você não precisa mais usar StatefulWidgets.\n\n```dart\nclass Home extends StatelessWidget {\n\n  @override\n  Widget build(context) { \n\n    // Instancie sua classe usando Get.put() para torná-la disponível para todas as rotas subsequentes\n    final Controller c = Get.put(Controller());\n\n    return Scaffold(\n      // Use Obx(()=> para atualizar Text() sempre que a contagem é alterada.\n      appBar: AppBar(title: Obx(() => Text(\"Total de cliques: ${c.count}\"))),\n\n      // Troque o Navigator.push de 8 linhas por um simples Get.to(). Você não precisa do 'context'\n      body: Center(child: ElevatedButton(\n              child: Text(\"Ir pra Outra tela\"), onPressed: () => Get.to(Outra()))),\n      floatingActionButton: \n          FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment));\n  } \n}\n\nclass Outra extends StatelessWidget {\n  // Você pode pedir o Get para encontrar o controller que foi usado em outra página e redirecionar você pra ele.\n  final Controller c = Get.find();\n  @override\n  Widget build(context) => Scaffold(body: Center(child: Text(\"${c.count}\")));\n}\n\n```\n\nResultado:\n\n![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/counter-app-gif.gif)\n\nEsse é um projeto simples mas já deixa claro o quão poderoso o Get é. Enquanto seu projeto cresce, essa diferença se torna bem mais significante.\n\nGet foi feito para funcionar com times, mas torna o trabalho de um desenvolvedor individual simples.\n\nMelhore seus prazos, entregue tudo a tempo sem perder performance. Get não é para todos, mas se você identificar com o que foi dito acima, Get é para você!\n\n\n# Os três pilares\n\n## Gerenciamento de estado\n\nGetX™ possui dois gerenciadores de estado diferentes: o gerenciador de estado simples (vamos chamá-lo de GetBuilder) e o gerenciador de estado reativo (GetX/Obx)\n\n### Reactive state manager\n\nProgramação reativa pode alienar muitas pessoas porque é dito que é complicado. GetX™ transforma a programação reativa em algo bem simples:\n\n* Você não precisa criar StreamControllers\n* Você não precisa criar um StreamBuilder para cada variável\n* Você não precisa criar uma classe para cada estado\n* Você não precisa criar um get para o valor inicial\n* Você não precisará usar geradores de código\n\nProgramação reativa com o Get é tão fácil quanto usar setState.\n\nVamos imaginar que você tenha uma variável e quer que toda vez que ela alterar, todos os widgets que a usam são automaticamente alterados.\n\nEssa é sua variável:\n\n```dart\nvar name = 'Jonatas Borges';\n```\n\nPara fazer dela uma variável observável, você só precisa adicionar `.obs` no final:\n\n```dart\nvar name = 'Jonatas Borges'.obs;\n```\n\nE Na UI, quando quiser mostrar a variável e escutar as mudanças dela, simplesmente faça isso:\n\n```dart\nObx (() => Text (controller.name));\n```\n\nSó isso. É *simples assim*;\n\n### Mais detalhes sobre gerenciamento de estado\n\n**Veja uma explicação mais completa do gerenciamento de estado [aqui](./documentation/pt_BR/state_management.md). Lá terá mais exemplos e também a diferença do simple state manager do reactive state manager**\n\n### Explicação em video do gerenciamento de estado\n\nAmateur Coder fez um vídeo ótimo sobre o gerenciamento de estado! (em inglês). Link: [Complete GetX State Management](https://www.youtube.com/watch?v=CNpXbeI_slw)\n\nVocê vai ter uma boa idea do poder do GetX™\n\n## Gerenciamento de rotas\n\nSe você for usar routes / snackbars / dialogs / bottomsheets sem contexto, GetX™ é excelente para você também, veja:\n\nAdicione \"Get\" antes do seu MaterialApp, transformando-o em GetMaterialApp\n\n```dart\nGetMaterialApp( // Antes: MaterialApp(\n  home: MyHome(),\n)\n```\n\nPara navegar para uma próxima tela:\n\n```dart\nGet.to(ProximaTela());\n```\n\nPara navegar para uma próxima tela com uma rota nomeada. Veja mais detalhes sobre rotas nomeadas [aqui](./documentation/pt_BR/route_management.md#navegar-com-rotas-nomeadas)\n\n```dart\nGet.toNamed('/detalhes');\n```\n\nPara fechar snackbars, dialogs, bottomsheets, ou qualquer coisa que você normalmente fecharia com o `Navigator.pop(context)` (como por exemplo fechar a View atual e voltar para a anterior):\n\n```dart\nGet.back();\n```\n\nPara ir para a próxima tela e NÃO deixar opção para voltar para a tela anterior (bom para SplashScreens, telas de login e etc.):\n\n```dart\nGet.off(ProximaTela());\n```\n\nPara ir para a próxima tela e cancelar todas as rotas anteriores (útil em telas de carrinho, votações ou testes):\n\n```dart\nGet.offAll(ProximaTela());\n```\n\nPara navegar para a próxima rota e receber ou atualizar dados assim que retornar da rota:\n\n```dart\nvar dados = await Get.to(Pagamento());\n```\n\nNotou que você não precisou usar `context` para fazer nenhuma dessas coisas? Essa é uma das maiores vantagens de usar o gerenciamento de rotas do GetX™. Com isso, você pode executar todos esse métodos de dentro da classe Controller, sem preocupações.\n\n### Mais detalhes sobre gerenciamento de rotas\n\n**GetX™ funciona com rotas nomeadas também! Veja uma explicação mais completa do gerenciamento de rotas [aqui](./documentation/pt_BR/route_management.md)**\n\n### Explicação em video do gerenciamento de rotas\n\nAmateur Coder fez um outro vídeo excelente sobre gerenciamento de rotas! Link: [Complete Getx Navigation](https://www.youtube.com/watch?v=RaqPIoJSTtI)\n\n## Gerenciamento de Dependência\n\n- Nota: Se você está usando o gerenciador de estado do Get, você não precisa se preocupar com isso, só leia a documentação, mas dê uma atenção a api `Bindings`, que vai fazer tudo isso automaticamente para você.\n\nJá está usando o Get e quer fazer seu projeto o melhor possível? Get tem um gerenciador de dependência simples e poderoso que permite você pegar a mesma classe que seu Bloc ou Controller com apenas uma linha de código, sem Provider context, sem inheritedWidget:\n\n```dart\nController controller = Get.put(Controller()); // Em vez de Controller controller = Controller();\n```\n\nEm vez de instanciar sua classe dentro da classe que você está usando, você está instanciando ele dentro da instância do Get, que vai fazer ele ficar disponível por todo o App para que então você possa usar seu controller (ou uma classe Bloc) normalmente\n\n\n**Dica:** O gerenciamento de dependência Get é desacoplado de outras partes do pacote, então se, por exemplo, seu aplicativo já estiver usando um gerenciador de estado (qualquer um, não importa), você não precisa reescrever tudo, você pode usar esta injeção de dependência sem problemas\n\n```dart\ncontroller.fetchApi();\n```\n\nAgora, imagine que você navegou por inúmeras rotas e precisa de dados que foram deixados para trás em seu controlador. Você precisaria de um gerenciador de estado combinado com o Provider ou Get_it, correto? Não com Get. Você só precisa pedir ao Get para \"procurar\" pelo seu controlador, você não precisa de nenhuma dependência adicional para isso:\n\n```dart\nController controller = Get.find();\n// Sim, parece Magia, o Get irá descobrir qual é seu controller e irá te entregar.\n// Você pode ter 1 milhão de controllers instanciados, o Get sempre te entregará o controller correto.\n// Apenas se lembre de Tipar seu controller, final controller = Get.find(); por exemplo, não irá funcionar.\n```\n\nE então você será capaz de recuperar os dados do seu controller que foram obtidos anteriormente:\n\n```dart\nText(controller.textFromApi);\n```\n\nProcurando por `lazyLoading` (carregar somente quando for usar)? Você pode declarar todos os seus controllers e eles só vão ser inicializados e chamados quando alguém precisar. Você pode fazer isso\n\n```dart\nGet.lazyPut<Service>(()=> ApiMock());\n/// ApiMock só será chamado quando alguém usar o Get.find<Service> pela primeira vez\n```\n\n### Mais detalhes sobre gerenciamento de dependências\n\n**Veja uma explicação mais completa do gerenciamento de dependência [aqui](./documentation/pt_BR/dependency_management.md)**\n\n# Utilidades\n\n## Internacionalização\n### Traduções\nNós mantemos as traduções num simples dictionary map de chave-valor.\nPara adicionar traduções personalizadas, crie uma classe e estenda `Translations`.\n\n```dart\nimport 'package:get/get.dart';\n\nclass Messages extends Translations {\n  @override\n  Map<String, Map<String, String>> get keys => {\n    'en_US': {\n      'hello': 'Hello World',\n    },\n    'de_DE': {\n      'hello': 'Hallo Welt',\n    }\n  };\n}\n```\n\n#### Usando traduções\nBasta anexar `.tr` a chave especificada e ela será traduzida, usando o valor atual de `Get.locale` ou `Get.fallbackLocale`.\n```dart\nText('hello'.tr);\n```\n\n### Localidade\nPasse parâmetros para `GetMaterialApp` definir a localidade e as traduções.\n\n```dart\nreturn GetMaterialApp(\n    translations: Messages(), // suas traduções\n    locale: Locale('en', 'US'), // as traduções serão exibidas para esta localidade\n    fallbackLocale: Locale('en', 'UK'), // especifica uma localidade em caso de falha na localidade definida\n);\n```\n\n#### Alterar local\nUse `Get.updateLocale(locale)` para atualizar a localidade. As traduções usarão automaticamente a nova localidade e a UI será atualizada.\n```dart\nvar locale = Locale('en', 'US');\nGet.updateLocale(locale);\n```\n\n#### Localidade do sistema operacional\nPara ler a localidade do sistema operacional, você pode usar `Get.deviceLocale`.\n```dart\nimport 'dart:ui' as ui;\n\nreturn GetMaterialApp(\n    locale: Get.deviceLocale,\n);\n```\n\n## Mudar tema (changeTheme)\n\nPor favor não use widget acima do GetMaterialApp para atualizar o tema. Isso pode causar keys duplicadas. Várias pessoas estão acostumadas com o jeito normal de criar um Widget `ThemeProvider` só pra alterar o tema do app, mas isso definitivamente NÃO é necessário com GetX™.\n\nVocê pode criar seu tema customizado e simplesmente adicionar dentro do `Get.changeTheme` sem nenhum boilerplate para isso:\n\n```dart\nGet.changeTheme(ThemeData.light())\n```\n\nSe você quer criar algo como um botão que muda o tema com o toque, você pode combinar duas APIs GetX™ pra isso:\n- A API que checa se o tema dark está sendo aplicado;\n- A API de mudar o tema e colocar isso no `onPressed:`\n\n```dart\nGet.changeTheme(Get.isDarkMode ? ThemeData.light() : ThemeData.dark())\n```\n\nQuando o modo Dark está ativado, ele vai trocar pro modo light e vice versa.\n\nSe você quiser saber mais como trocar o tema, você pode seguir esse tutorial no Medium que até ensina persistência do tema usando Get (e SharedPreferences):\n\n- [Dynamic Themes in 3 lines using Get](https://medium.com/swlh/flutter-dynamic-themes-in-3-lines-c3b375f292e3) - Tutorial by [Rod Brown](https://github.com/RodBr).\n\n\n## GetConnect\nGetConnect é uma maneira fácil de se comunicar de trás para a frente com http ou websockets\n\n### Configuração Padrão\nVocê pode simplesmente estender GetConnect e usar os métodos GET/POST/PUT/DELETE/SOCKET para se comunicar com sua API Rest ou websockets.\n\n```dart\nclass UserProvider extends GetConnect {\n  // Requisição Get\n  Future<Response> getUser(int id) => get('http://youapi/users/$id');\n  // Requisição Post\n  Future<Response> postUser(Map data) => post('http://youapi/users', body: data);\n  // Requisição Post com Arquivo\n  Future<Response<CasesModel>> postCases(List<int> image) {\n    final form = FormData({\n      'file': MultipartFile(image, filename: 'avatar.png'),\n      'otherFile': MultipartFile(image, filename: 'cover.png'),\n    });\n    return post('http://youapi/users/upload', form);\n  }\n\n  GetSocket userMessages() {\n    return socket('https://yourapi/users/socket');\n  }\n}\n```\n### Configuração Personalizada\nGetConnect é altamente personalizável, você pode definir uma base Url, modificadores de resposta, modificadores de Requests, definir um autenticador e até o número de tentativas em que tentará se autenticar, além de dar a possibilidade de definir um decodificador padrão que irá transformar todas as suas solicitações em seus modelos sem qualquer configuração adicional.\n\n```dart\nclass HomeProvider extends GetConnect {\n  @override\n  void onInit() {\n    // Todas as requisições passam por jsonEncode e então por CasesModel.fromJson()\n    httpClient.defaultDecoder = CasesModel.fromJson;\n    httpClient.baseUrl = 'https://api.covid19api.com';\n    // baseUrl = 'https://api.covid19api.com'; // Define baseUrl para\n    // Http e websockets se usado sem uma instância [httpClient]\n\n    // Anexa a propriedade 'apikey' no cabeçalho de todas as requisições\n    httpClient.addRequestModifier((request) {\n      request.headers['apikey'] = '12345678';\n      return request;\n    });\n\n    // Mesmo que o servidor envie dados do país \"Brasil\",\n    // eles nunca serão exibidos para os usuários, porque você removeu\n    // os dados da resposta, mesmo antes de a resposta ser entregue\n    httpClient.addResponseModifier<CasesModel>((request, response) {\n      CasesModel model = response.body;\n      if (model.countries.contains('Brazil')) {\n        model.countries.remove('Brazil');\n      }\n    });\n\n    httpClient.addAuthenticator((request) async {\n      final response = await get(\"http://yourapi/token\");\n      final token = response.body['token'];\n      // Configurando um cabeçalho\n      request.headers['Authorization'] = \"$token\";\n      return request;\n    });\n\n    // O autenticador será chamado 3 vezes se HttpStatus for \n    // HttpStatus.unauthorized\n    httpClient.maxAuthRetries = 3;\n  }\n  }\n\n  @override\n  Future<Response<CasesModel>> getCases(String path) => get(path);\n}\n```\n\n## GetPage Middleware\n\nO GetPage agora tem uma nova propriedade que recebe uma lista de GetMiddleWare e executa cada item na ordem específica.\n\n**Nota**: Quando GetPage tem Middlewares, todos os filhos desta página terão os mesmos middlewares automaticamente.\n\n### Priority\n\nA ordem dos middlewares a serem executados pode ser definida pela prioridade no GetMiddleware.\n\n```dart\nfinal middlewares = [\n  GetMiddleware(priority: 2),\n  GetMiddleware(priority: 5),\n  GetMiddleware(priority: 4),\n  GetMiddleware(priority: -8),\n];\n```\nEsses middlewares serão executados nesta ordem:  **-8 => 2 => 4 => 5**\n\n### Redirect\n\nEsta função será chamada quando a página da rota chamada estiver sendo pesquisada. RouteSettings se torna o resultado do redirecionamento. Ou retorne nulo e não haverá redirecionamento.\n\n```dart\nRouteSettings redirect(String route) {\n  final authService = Get.find<AuthService>();\n  return authService.authed.value ? null : RouteSettings(name: '/login')\n}\n```\n\n### onPageCalled\n\nEsta função será chamada quando uma página for chamada, antes de qualquer coisa ser criada e\nvocê pode usá-la para mudar algo sobre a página ou dar-lhe uma nova página\n\n```dart\nGetPage onPageCalled(GetPage page) {\n  final authService = Get.find<AuthService>();\n  return page.copyWith(title: 'Welcome ${authService.UserName}');\n}\n```\n\n### OnBindingsStart\n\nEsta função será chamada logo antes da inicialização dos Bindings.\nAqui você pode alterar as ligações desta página.\n\n```dart\nList<Bindings> onBindingsStart(List<Bindings> bindings) {\n  final authService = Get.find<AuthService>();\n  if (authService.isAdmin) {\n    bindings.add(AdminBinding());\n  }\n  return bindings;\n}\n```\n\n### OnPageBuildStart\n\nEsta função será chamada logo após a inicialização dos Bindings.\nAqui você pode fazer algo depois de criar as ligações e antes de criar o widget da página.\n\n```dart\nGetPageBuilder onPageBuildStart(GetPageBuilder page) {\n  print('bindings are ready');\n  return page;\n}\n```\n\n### OnPageBuilt\n\nEsta função será chamada logo após a função GetPage.page ser chamada e fornecerá o resultado da função e obtém o widget que será mostrado.\n\n### OnPageDispose\n\nEsta função será chamada logo após descartar todos os objetos relacionados (controladores, visualizações, ...) da página.\n\n## Outras APIs avançadas\n\n```dart\n// fornece os arguments da tela atual\nGet.arguments\n\n// fornece o nome da rota anterior\nGet.previousRoute\n\n// fornece a rota bruta para acessar por exemplo, rawRoute.isFirst()\nGet.rawRoute\n\n// fornece acesso a API de rotas de dentro do GetObserver\nGet.routing\n\n// checa se o snackbar está aberto\nGet.isSnackbarOpen\n\n// checa se o dialog está aberto\nGet.isDialogOpen\n\n// checa se o bottomsheet está aberto\nGet.isBottomSheetOpen\n\n// remove uma rota.\nGet.removeRoute()\n\n// volta repetidamente até o predicate retorne true.\nGet.until()\n\n// vá para a próxima rota e remove todas as rotas\n//anteriores até que o predicate retorne true.\nGet.offUntil()\n\n// vá para a próxima rota nomeada e remove todas as\n//rotas anteriores até que o predicate retorne true.\nGet.offNamedUntil()\n\n// Verifica em que plataforma o app está sendo executado\n// (Esse método é completamente compatível com o FlutterWeb,\n// diferente do método do framework \"Platform.isAndroid\")\nGetPlatform.isAndroid\nGetPlatform.isIOS\nGetPlatform.isMacOS\nGetPlatform.isWindows\nGetPlatform.isLinux\nGetPlatform.isFuchsia\n\n// Verifica o tipo de dispositivo\nGetPlatform.isMobile\nGetPlatform.isDesktop\n// Todas as plataformas são suportadas de forma independente na web!\n// Você pode saber se está executando dentro de um navegador\n// no Windows, iOS, OSX, Android, etc.\nGetPlatform.isWeb\n\n// Equivalente ao método: MediaQuery.of(context).size.width ou height, mas é imutável. \n// Significa que não irá atualizar mesmo que o tamanho da tela mude (como em navegadores ou app desktop)\nGet.height\nGet.width\n\n// fornece o context da tela em qualquer lugar do seu código.\nGet.context\n\n// fornece o context de snackbar/dialog/bottomsheet em qualquer lugar do seu código.\nGet.contextOverlay\n\n// Obs: os métodos a seguir são extensions do context. Já que se\n// tem acesso ao context em qualquer lugar do código da UI, você pode usar lá\n\n// Se você precisa de um width/height adaptável (como em navegadores em que a janela pode ser redimensionada) \n// você precisa usar 'context'\ncontext.width\ncontext.height\n\n// Dá a você agora o poder de definir metade da tela, um terço da dela e assim por diante.\n// Útil para aplicativos responsivos.\n// param dividedBy (double) opcional - default: 1\n// param reducedBy (double) opcional - default: 0\ncontext.heightTransformer()\ncontext.widthTransformer()\n\n/// similar a MediaQuery.of(context).size\ncontext.mediaQuerySize()\n\n/// similar a MediaQuery.of(this).padding\ncontext.mediaQueryPadding()\n\n/// similar a MediaQuery.of(this).viewPadding\ncontext.mediaQueryViewPadding()\n\n/// similar a MediaQuery.of(this).viewInsets;\ncontext.mediaQueryViewInsets()\n\n/// similar a MediaQuery.of(this).orientation;\ncontext.orientation()\n\n/// verifica se o dispositivo está no modo paisagem\ncontext.isLandscape()\n\n/// verifica se o dispositivo está no modo retrato\ncontext.isPortrait()\n\n/// similar a MediaQuery.of(this).devicePixelRatio;\ncontext.devicePixelRatio()\n\n/// similar a MediaQuery.of(this).textScaleFactor;\ncontext.textScaleFactor()\n\n/// obtém a menor dimensão (largura ou altura) da tela\ncontext.mediaQueryShortestSide()\n\n/// retorna True se a largura da tela for maior que 800px\ncontext.showNavbar()\n\n/// retorna True se a menor dimensão (largura ou altura) da tela for menor que 600px\ncontext.isPhone()\n\n/// retorna True se a menor dimensão (largura ou altura) da tela for maior ou igual a 600px\ncontext.isSmallTablet()\n\n/// retorna True se a menor dimensão (largura ou altura) da tela for maior ou igual a 720px\ncontext.isLargeTablet()\n\n/// retorna True se o dispositivo é um Tablet\ncontext.isTablet()\n\n/// Retorna um valor de acordo com o tamanho da tela\n/// Os valores possíveis são:\n/// swatch: se a menor dimensão (largura ou altura) da tela for menor que 300px\n/// mobile: se a menor dimensão (largura ou altura) da tela for menor que 600px\n/// tablet: se a menor dimensão (largura ou altura) da tela for menor que 1200px\n/// desktop: se a largura da tela é maior ou iguial a 1200px  \ncontext.responsiveValue<T>()\n```\n\n### Configurações Globais opcionais e configurações manuais\n\nGetMaterialApp configura tudo para você, mas se quiser configurar Get manualmente, você pode.\n\n```dart\nMaterialApp(\n  navigatorKey: Get.key,\n  navigatorObservers: [GetObserver()],\n);\n```\n\nVocê também será capaz de usar seu próprio Middleware dentro do GetObserver, isso não irá influenciar em nada.\n\n```dart\nMaterialApp(\n  navigatorKey: Get.key,\n  navigatorObservers: [\n    GetObserver(MiddleWare.observer) // Aqui\n  ],\n);\n```\n\nVocê pode criar Configurações Globais para o Get. Apenas adicione `Get.config` ao seu código antes de usar qualquer rota ou faça diretamente no seu GetMaterialApp\n\n```dart\nGetMaterialApp(\n  enableLog: true,\n  defaultTransition: Transition.fade,\n  opaqueRoute: Get.isOpaqueRouteDefault,\n  popGesture: Get.isPopGestureEnable,\n  transitionDuration: Get.defaultDurationTransition,\n  defaultGlobalState: Get.defaultGlobalState,\n);\nGet.config(\n  enableLog = true,\n  defaultPopGesture = true,\n  defaultTransition = Transitions.cupertino\n)\n```\n\nÉ possível redirecionar todas as mensagens de log do GetX™. Útil quando se tem um package de logging e vc quer que ele lide com todos os logs\n\n```dart\nGetMaterialApp(\n  enableLog: true,\n  logWriterCallback: localLogWriter,\n);\n\nvoid localLogWriter(String text, {bool isError = false}) {\n  // passage a mensagem para seu package de logging favorito aqui\n  // Obs: mesmo que as mensagens de log estejam desativadas\n  // com o comando \"enableLog: false\", as mensagens ainda vão passar por aqui\n  // Você precisa checar essa config manualmente aqui se quiser respeitá-la\n}\n```\n\n### Widgets de Estado Local\n\nEsses Widgets permitem que você gerencie um único valor e mantenha o estado efêmero e localmente. Temos versões para Reativo e Simples. Por exemplo, você pode usá-los para alternar obscureText em um `TextField`, talvez criar um painel expansível personalizado ou talvez modificar o índice atual em um `BottomNavigationBar` enquanto altera o conteúdo do corpo em um `Scaffold`.\n\n#### ValueBuilder\nUma simplificação de `StatefulWidget` que funciona com um callback de `setState` que passa o valor atualizado.\n\n\n```dart\nValueBuilder<bool>(\n  initialValue: false,\n  builder: (value, updateFn) => Switch(\n    value: value,\n    onChanged: updateFn, // mesma assinatura! Você poderia usar ( newValue ) => updateFn( newValue )\n  ),\n  // se você precisa chamar algo fora do método builder.\n  onUpdate: (value) => print(\"Valor atualizado: $value\"),\n  onDispose: () => print(\"Widget desmontado\"),   \n),\n```\n\n#### ObxValue\nSimilar a ValueBuilder, mas esta é a versão Reativa, você passa uma instância Rx (lembra do .obs mágico?) e \natualiza automaticamente... não é incrível?\n\n```dart\nObxValue(\n  (data) => Switch(\n    value: data.value,\n    onChanged: data, // Rx tem uma função _callable_! Você poderia usar (flag) => data.value = flag,\n  ),\n  false.obs,\n),\n```\n\n### Explicação em vídeo sobre Outras Features do GetX\n\nAmateur Coder fez um vídeo incrível sobre utils, storage, bindings e outras features! Link: [GetX Other Features](https://youtu.be/ttQtlX_Q0eU)\n\n\n## Dicas Úteis\n\n`.obs`ervables (também conhecidos como _Rx_ Types) possuem uma grande variedade de métodos e operadores internos.\n\n> É muito comum acreditar que uma propriedade com `.obs` **É** o valor real... mas não se engane!\n> Evitamos a declaração de tipo da variável, porque o compilador do Dart é inteligente o suficiente e o código\n> parece mais limpo, mas:\n\n```dart\nvar message = 'Hello world'.obs;\nprint( 'Message \"$message\" é do tipo ${message.runtimeType}');\n```\n\nMesmo que `message` _imprima_ o valor da string, seu tipo é **RxString**!\n\nEntão, você não pode fazer `message.substring( 0, 4 )`.\nVocê tem que acessar o `valor` real dentro do _observable_:\nA \"maneira\" mais usada é utilizando `.value`, mas, você sabia que também pode usar:\n\n```dart\nfinal name = 'GetX'.obs;\n// apenas \"atualiza\" o stream, se o valor for diferente do atual.\nname.value = 'Hey';\n\n// Todas as propriedades Rx são \"chamáveis\" e retorna o novo valor.\n// mas esta abordagem não aceita `null`, a UI não será reconstruída\nname('Hello');\n\n// é como um getter, imprime 'Hello'\nname() ;\n\n/// números:\n\nfinal count = 0.obs;\n\n// Você pode usar todas as operações não mutáveis ​​de um num! \ncount + 1;\n\n// Cuidado! isso só é válido se `count` não for final, mas var\ncount += 1;\n\n// Você também pode comparar com os valores:\ncount > 2;\n\n/// booleans:\n\nfinal flag = false.obs;\n\n// mude o valor entre true/false\nflag.toggle();\n\n\n/// todos os tipos:\n\n// Defina `value` como null.\nflag.nil();\n\n// Todas as operações toString() e toJson() são passada para `value`\nprint( count ); // chama `toString()` de RxInt\n\nfinal abc = [0,1,2].obs;\n// Converte o valor em um Array json, imprime RxList\n// Json é suportado por todos os Rx types!\nprint('json: ${jsonEncode(abc)}, type: ${abc.runtimeType}');\n\n// RxMap, RxList e RxSet são Rx types especiais, que estendem seus tipos nativos.\n// mas você pode trabalhar com uma lista como uma lista normal, embora seja reativa!\nabc.add(12); // Coloca 12 na lista, e ATUALIZA o stream.\nabc[3]; // como uma lista lê o índice 3.\n\n// a igualdade funciona com o Rx e o value do observável, mas o hashCode é sempre obtido do value \nfinal number = 12.obs;\nprint( number == 12 ); // prints > true\n\n/// Rx Models personalizados:\n\n// toJson(), toString() são transferidos para o filho, para que você possa implementar \n// override neles e imprimir o observável diretamente.\n\nclass User {\n    String name, last;\n    int age;\n    User({this.name, this.last, this.age});\n\n    @override\n    String toString() => '$name $last, $age years old';\n}\n\nfinal user = User(name: 'John', last: 'Doe', age: 33).obs;\n\n// `user` é \"reativo\", mas as propriedades dentro NÃO SÃO!\n// Então, se mudarmos alguma variável dentro dele:\nuser.value.name = 'Roi';\n// O widget não vai reconstruir!,\n// `Rx` não tem nenhuma notificação quando você muda algo dentro do usuário.\n// Portanto, para classes personalizadas, precisamos \"notificar\" manualmente a mudança.\nuser.refresh();\n\n// ou podemos usar o método `update()`!\nuser.update((value){\n  value.name='Roi';\n});\n\nprint( user ); // Resultado (toString): Roi Doe, 33 years old\n```\n\n#### GetView\n\nEu amo este Widget, é tão simples, mas tão útil!\n\nÉ um Widget `const Stateless` que tem um getter `controller` registrado para Controller, só isso.\n\n```dart\nclass AwesomeController extends GetxController {\n  final String title = 'My Awesome View';\n}\n\n// SEMPRE lembre de passar o `Type` que você usou para registrar seu controlador!\nclass AwesomeView extends GetView<AwesomeController> {\n  @override\n  Widget build(BuildContext context) {\n    return Container(\n      padding: EdgeInsets.all(20),\n      child: Text(controller.title ), // apenas chame `controller.something`\n    );\n  }\n}\n```\n\n#### GetWidget\n\nA maioria das pessoas não tem ideia sobre este widget, ou confunde totalmente o uso dele. \nO caso de uso é muito raro, mas muito específico: Ele armazena em `cache` um Controller. \nPor causa do _cache_, não pode ser um `const Stateless`.\n\n> Então, quando você precisa armazenar em \"cache\" um Controller?\n\nSe você usar, uma outra característica \"não tão comum\" de **GetX™**: `Get.create()`.\n\n`Get.create(()=>Controller())` irá gerar um novo `Controller` cada vez que você chamar\n`Get.find<Controller>()`,\n\nÉ aí que `GetWidget` brilha... já que você pode usá-lo, por exemplo, \npara manter uma lista de itens Todo. Portanto, se o widget for \"reconstruído\", ele manterá a mesma instância do controlador.\n\n#### GetxService\n\nEsta classe é como um `GetxController`, ele compartilha o mesmo ciclo de vida ( `onInit()`, `onReady()`, `onClose()`). \nMas não tem \"lógica\" dentro dele. Ele apenas notifica o sistema de injeção de dependência do GetX™ de que esta subclasse\n**não pode** ser removida da memória.\n\nPortanto, é muito útil manter seus \"Services\" sempre acessíveis e ativos com `Get.find()`. Como: \n`ApiService`, `StorageService`, `CacheService`.\n\n```dart\nFuture<void> main() async {\n  await initServices(); /// Aguarda a inicialização dos Services.\n  runApp(SomeApp());\n}\n\n/// É uma jogada inteligente para inicializar seus services antes de executar o aplicativo Flutter, \n/// já que você pode controlar o fluxo de execução (talvez você precise carregar alguma configuração de tema, \n/// apiKey, linguagem definida pelo usuário ... então carregue SettingService antes de executar ApiService. \n/// então GetMaterialApp() não precisa reconstruir e obtém os valores diretamente.\nvoid initServices() async {\n  print('iniciando serviços...');\n  /// Aqui é onde você coloca a inicialização de get_storage, hive, shared_pref. \n  /// ou checa a conexão, ou o que quer que seja assíncrono.\n  await Get.putAsync(() => DbService().init());\n  await Get.putAsync(SettingsService()).init();\n  print('Todos os serviços iniciados.');\n}\n\nclass DbService extends GetxService {\n  Future<DbService> init() async {\n    print('$runtimeType delays 2 sec');\n    await 2.delay();\n    print('$runtimeType ready!');\n    return this;\n  }\n}\n\nclass SettingsService extends GetxService {\n  void init() async {\n    print('$runtimeType delays 1 sec');\n    await 1.delay();\n    print('$runtimeType ready!');\n  }\n}\n```\n\nA única maneira de realmente excluir um `GetxService`, é com o `Get.reset()`, que é como uma \n\"hot restart\" do seu aplicativo. Portanto, lembre-se, se você precisar de persistência absoluta de uma instância de classe durante\no ciclo de vida de seu aplicativo, use GetxService.\n\n\n# Breaking Changes da versão 2 para 3\n\n## Tipagem Rx\n\n| Antes   | Depois     |\n| ------- | ---------- |\n| StringX | `RxString` |\n| IntX    | `RxInt`    |\n| MapX    | `RxMap`    |\n| ListX   | `RxList`   |\n| NumX    | `RxNum`    |\n| DoubleX | `RxDouble` |\n\n## RxController e GetBuilder se uniram\n\nRxController e GetBuilder agora viraram um só, você não precisa mais memorizar qual controller quer usar, apenas coloque `GetxController`, vai funcionar para os dois gerenciamento de estados\n\n```dart\n//Gerenciador de estado simples\nclass Controller extends GetXController {\n  String nome = '';\n\n  void atualizarNome(String novoNome) {\n    nome = novoNome;\n    update()\n  }\n}\n```\n\n```dart\nclass Controller extends GetXController {\n  final nome = ''.obs;\n\n  // não precisa de um método direto pra atualizar o nome\n  // só usar o nome.value\n}\n```\n\n## Rotas nomeadas\n\nAntes:\n\n```dart\nGetMaterialApp(\n  namedRoutes: {\n    '/': GetRoute(page: Home()),\n  }\n)\n```\n\nAgora:\n\n```dart\nGetMaterialApp(\n  getPages: [\n    GetPage(name: '/', page: () => Home()),\n  ]\n)\n```\n\n### Porque essa mudança?\n\nFrequentemente, pode ser necessário decidir qual pagina vai ser mostrada ao usuário a partir de um parâmetro, como um token de login. A forma abordada anteriormente não era flexível, já que não permitia isso.\n\nInserir a página numa função reduziu significativamente o consumo de RAM, já que as rotas não são alocadas na memória no momento que o app é iniciado e também permite fazer esse tipo de abordagem:\n\n```dart\n\nGetStorage box = GetStorage();\n\nGetMaterialApp(\n  getPages: [\n    GetPage(name: '/', page:(){  \n      return box.hasData('token') ? Home() : Login();\n    })\n  ]\n)\n```\n\n# Por que GetX™?\n\n1- Muitas vezes após uma atualização do Flutter, muitos dos seus packages irão quebrar. As vezes acontecem erros de compilação, muitas vezes aparecem erros que ainda não existem respostas sobre e o desenvolvedor necessita saber de onde o erro veio, rastreá-lo, para só então tentar abrir uma issue no repositório correspondente e ver seu problema resolvido. Get centraliza os principais recursos para o desenvolvimento (Gerência de estado, de dependências e de rotas), permitindo você adicionar um único package em seu pubspec e começar a trabalhar. Após uma atualização do Flutter, a única coisa que você precisa fazer é atualizar a dependencia do Get e começar a trabalhar. Get também resolve problemas de compatibilidade. Quantas vezes uma versão de um package não é compatível com a versão de outro, porque um utiliza uma dependência em uma versão e o outro em outra versão? Essa também não é uma preocupação usando Get, já que tudo está no mesmo package e é totalmente compatível.\n\n2- Flutter é fácil, Flutter é incrível, mas Flutter ainda tem algum boilerplate que pode ser indesejado para maioria dos desenvolvedores, como o Navigator.of(context).push(context, builder[...]. Get simplifica o desenvolvimento. Em vez de escrever 8 linhas de código para apenas chamar uma rota, você pode simplesmente fazer: Get.to(Home()) e pronto, você irá para a próxima página. Urls dinâmicas da web é algo realmente doloroso de fazer com o Flutter atualmente e isso com o GetX™ é estupidamente simples. Gerenciar estados no Flutter e gerenciar dependências também é algo que gera muita discussão, por haver centenas de padrões na pub. Mas não há nada que seja tão fácil quanto adicionar um \".obs\" no final de sua variável, colocar o seu widget dentro de um Obx e pronto, todas atualizações daquela variável serão automaticamente atualizadas na tela.\n\n3- Facilidade sem se preocupar com desempenho. O desempenho do Flutter já é incrível, mas imagine que você use um gerenciador de estados e um locator para distribuir suas classes blocs/stores/controllers/ etc. Você deverá chamar manualmente a exclusão daquela dependência quando não precisar dela. Mas já pensou em simplesmente usar seu controlador e quando ele não tivesse mais sendo usado por ninguém, ele simplesmente fosse excluído da memória? É isso que GetX™ faz. Com o SmartManagement, tudo que não está sendo usado é excluído da memória e você não deve se preocupar em nada além de programar. Você terá garantia que está consumindo o mínimo de recursos necessários, sem ao menos ter criado uma lógica para isso.\n\n4- Desacoplamento real. Você já deve ter ouvido o conceito \"separar a view da lógica de negócios\". Isso não é uma peculiaridade do BLoC, MVC ou MVVM, qualquer outro padrão existente no mercado tem esse conceito. No entanto, muitas vezes esse conceito pode ser mitigado no Flutter por conta do uso do context.\nSe você precisa de context para localizar um InheritedWidget, você precisa disso na view ou passar o context por parâmetro. Eu particularmente acho essa solução muito feia e para trabalhar em equipes teremos sempre uma dependência da lógica de negócios da View. GetX™ é pouco ortodoxo com a abordagem padrão e apesar de não proibir totalmente o uso de StatefulWidgets, InitState e etc, ele tem sempre uma abordagem similar que pode ser mais limpa. Os controllers tem ciclos de vida e quando você precisa fazer uma solicitação APIREST por exemplo, você não depende de nada da view. Você pode usar onInit para iniciar a chamada http e quando os dados chegarem, as variáveis serão preenchidas. Como GetX™ é totalmente reativo (de verdade e trabalha sob streams), assim que os itens forem preenchidos, automaticamente será atualizado na view todos os widgets que usam aquela variável. Isso permite que as pessoas especialistas em UI trabalhem apenas com widgets e não precisem enviar nada para a lógica de negócio além de eventos do usuário (como clicar em um botão), enquanto as pessoas que trabalham com a lógica de negócio ficarão livres para criá-la e testá-la separadamente.  \n\n# Comunidade\n\n## Canais da comunidade\n\nGetX™ tem uma comunidade altamente ativa e útil. Se você tiver dúvidas, ou quiser alguma ajuda com relação ao uso deste framework, por favor entre em nossos canais da comunidade, sua dúvida será respondida mais rapidamente, e será o lugar mais adequado. Este repositório é exclusivo para abertura de issues e solicitação de recursos, mas fique à vontade para fazer parte da Comunidade GetX™.\n\n| **Slack (Inglês)**                                                                                                          | **Discord (Inglês e Português)**                                                                                            | **Telegram (Português)**                                                                                              |\n| :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------- |\n| [![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) |\n\n## Como contribuir\n\n_Quer contribuir com o projeto? Teremos o orgulho de destacá-lo como um de nossos colaboradores. Aqui estão alguns pontos onde você pode contribuir e tornar o Get (e Flutter) ainda melhor._\n\n- Ajudando a traduzir o readme para outros idiomas.\n- Adicionando documentação ao readme (muitas funções do Get ainda não foram documentadas).\n- Escreva artigos ou faça vídeos ensinando como usar o Get (eles serão inseridos no Readme e futuramente em nosso Wiki).\n- Fazendo PRs para código/testes.\n- Incluindo novas funções.\n\nQualquer contribuição é bem-vinda!\n\n\n## Artigos e vídeos\n\n- [Dynamic Themes in 3 lines using GetX™](https://medium.com/swlh/flutter-dynamic-themes-in-3-lines-c3b375f292e3) - Tutorial by [Rod Brown](https://github.com/RodBr). (inglês)\n- [Complete GetX™ Navigation](https://www.youtube.com/watch?v=RaqPIoJSTtI) - Route management video by Amateur Coder. (inglês)\n- [Complete GetX™ State Management](https://www.youtube.com/watch?v=CNpXbeI_slw) - State management video by Amateur Coder. (inglês)\n- [GetX™ Other Features](https://youtu.be/ttQtlX_Q0eU) - Utils, storage, bindings and other features video by Amateur Coder. (inglês)\n- [Firestore User with GetX™ | Todo App](https://www.youtube.com/watch?v=BiV0DcXgk58) - Video by Amateur Coder. (inglês)\n- [Firebase Auth with GetX™ | Todo App](https://www.youtube.com/watch?v=-H-T_BSgfOE) - Video by Amateur Coder. (inglês)\n- [The Flutter GetX™ Ecosystem ~ State Management](https://medium.com/flutter-community/the-flutter-getx-ecosystem-state-management-881c7235511d) - State management by [Aachman Garg](https://github.com/imaachman). (inglês)\n- [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). (inglês)\n- [GetX™, the all-in-one Flutter package](https://www.youtube.com/watch?v=IYQgtu9TM74) - A brief tutorial covering State Management and Navigation by Thad Carnevalli. (inglês)\n- [Build a To-do List App from scratch using Flutter and GetX™](https://www.youtube.com/watch?v=EcnqFasHf18) - UI + State Management + Storage video by Thad Carnevalli. (inglês)\n- [GetX™ Flutter Firebase Auth Example](https://medium.com/@jeffmcmorris/getx-flutter-firebase-auth-example-b383c1dd1de2) - Article by Jeff McMorris. (inglês)\n- [Flutter State Management with GetX – Complete App](https://www.appwithflutter.com/flutter-state-management-with-getx/) - by App With Flutter. (inglês)\n- [Flutter Routing with Animation using Get Package](https://www.appwithflutter.com/flutter-routing-using-get-package/) - by App With Flutter. (inglês)\n"
  },
  {
    "path": "README.ru.md",
    "content": "![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png)\n\n_Языки: Русский (этот файл), [вьетнамский](README-vi.md), [индонезийский](README.id-ID.md), [урду](README.ur-PK.md), [Английский](README.md), [Китайский](README.zh-cn.md), [Бразильский Португальский](README.pt-br.md), [Испанский](README-es.md), [Польский](README.pl.md), [Kорейский](README.ko-kr.md), [French](README-fr.md)._\n\n[![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)\n[![popularity](https://badges.bar/get/popularity)](https://pub.dev/packages/sentry/score)\n[![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)\n[![pub points](https://badges.bar/get/pub%20points)](https://pub.dev/packages/get/score)\n![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)\n[![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart)\n[![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N)\n[![Get on Slack](https://img.shields.io/badge/slack-join-orange.svg)](https://communityinviter.com/apps/getxworkspace/getx)\n[![Telegram](https://img.shields.io/badge/chat-on%20Telegram-blue.svg)](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g)\n<a href=\"https://github.com/Solido/awesome-flutter\">\n<img alt=\"Awesome Flutter\" src=\"https://img.shields.io/badge/Awesome-Flutter-blue.svg?longCache=true&style=flat-square\" />\n</a>\n<a href=\"https://www.buymeacoffee.com/jonataslaw\" target=\"_blank\"><img src=\"https://i.imgur.com/aV6DDA7.png\" alt=\"Buy Me A Coffee\" style=\"height: 41px !important;width: 174px !important; box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;\" > </a>\n\n![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/getx.png)\n\n- [Про Get](#про-get)\n- [Установка](#установка)\n- [Приложение \"Счётчик\" с GetX](#приложение-счётчик-с-getx)\n- [Три столпа](#три-столпа)\n  - [Управление состоянием](#управление-состоянием)\n    - [Реактивное управление состоянием](#реактивное-управление-состоянием)\n    - [Подробнее об управлении состоянием](#подробнее-об-управлении-состоянием)\n  - [Управление маршрутами](#управление-маршрутами)\n    - [Подробнее об управлении маршрутами](#подробнее-об-управлении-маршрутами)\n  - [Внедрение зависимостей](#внедрение-зависимостей)\n    - [Подробнее о внедрении зависимостей](#подробнее-о-внедрении-зависимостей)\n- [Утилиты](#утилиты)\n  - [Интернационализация](#интернационализация)\n    - [Переводы](#переводы)\n      - [Использование переводов](#использование-переводов)\n    - [Локализация](#локализация)\n      - [Изменение локализации](#изменение-локализации)\n      - [Системная локализация](#системная-локализация)\n  - [Изменение темы](#изменение-темы)\n  - [Другие API](#другие-api)\n    - [Дополнительные глобальные настройки и ручные настройки](#дополнительные-глобальные-настройки-и-ручные-настройки)\n    - [Локальные виджеты состояния](#локальные-виджеты-состояния)\n      - [ValueBuilder](#valuebuilder)\n      - [ObxValue](#obxvalue)\n  - [Полезные советы](#полезные-советы)\n      - [GetView](#getview)\n      - [GetWidget](#getwidget)\n      - [GetxService](#getxservice)\n- [Критические изменения по сравнению с версией 2.0](#критические-изменения-по-сравнению-с-версией-20)\n- [Почему Getx?](#почему-getx)\n- [Сообщества](#сообщества)\n  - [Каналы сообщества](#каналы-сообщества)\n  - [Как внести свой вклад](#как-внести-свой-вклад)\n  - [Статьи и видео](#статьи-и-видео)\n\n# Про Get\n\n- GetX  - это сверхлегкое и мощное решение для Flutter. Оно совмещает в себе высокопроизводительное управление состоянием, интеллектуальное внедрение зависимостей, управление маршрутами быстрым и практичным способом.\n\n- GetX имеет 3 базовых принципа, являющихся приоритетом для всех ресурсов в библиотеке\n\n  - **Производительность:** GetX сфокусирован на производительности и минимальном потреблении ресурсов. Бенчмарки почти всегда не имеют значения в реальном мире, но, если Вам угодно, здесь ([бенчмарки](https://github.com/jonataslaw/benchmarks)) есть индикаторы потребления, где GetX работает лучше, чем другие подходы к управлению состоянием. Разница небольшая, но демонстрирует нашу заботу о ресурсах.\n  - **Продуктивность:** GetX использует простой и приятный синтаксис. Не имеет значения, что вы хотите сделать, всегда есть более легкий способ с GetX. Это сэкономит часы разработки и обеспечит максимальную производительность, которую может обеспечить ваше приложение.\n  - **Организация:** GetX позволяет полностью разделить представление, логику представления, бизнес-логику, внедрение зависимостей и навигацию. Вам не нужен контекст для навигации между маршрутами, поэтому вы не зависите от дерева виджетов. Вам не нужен контекст для доступа к вашим контроллерам / блокам через наследуемый виджет, поэтому вы полностью отделяете логику представления и бизнес-логику от уровня визуализации. Вам не нужно внедрять классы Controllers / Models / Blocs в дерево виджетов через мультипровайдеры, поскольку GetX использует собственную функцию внедрения зависимостей, полностью отделяя DI от его представления.\n    С GetX вы знаете, где найти каждую функцию вашего приложения, имея чистый код по умолчанию. Это, помимо упрощения обслуживания, делает возможным совместное использование модулей, что до того момента во Flutter было немыслимо.\n    BLoC был отправной точкой для организации кода во Flutter, он отделяет бизнес-логику от визуализации. Getx является естественным развитием этого, разделяя не только бизнес-логику, но и логику представления. Дополнительное внедрение зависимостей и маршрутов также разделено, и уровень данных не учитывается. Вы знаете, где все находится, и это проще, чем написать \"Hello World\".\n    GetX - это самый простой, практичный и масштабируемый способ создания высокопроизводительных приложений с помощью Flutter SDK с большой экосистемой вокруг него, которая отлично работает, прост для новичков и точен для экспертов. Он безопасен, стабилен, актуален и предлагает огромный набор встроенных API, которых нет в Flutter SDK по умолчанию.\n\n- GetX не раздут. Он имеет множество функций, которые позволяют вам начать программировать, ни о чем не беспокоясь, но каждая из этих функций находится в отдельных контейнерах и запускается только после использования. Если вы используете только управление состоянием, то будет скомпилировано только управление состоянием. Если вы используете маршрутизацию, то ничего из управления состоянием не будет скомпилировано. Вы можете воспользоваться репозиторием бенчмарка, и вы увидите, что используя только управление состоянием Get, приложение, которое скомпилировано с помощью Get, имеет меньший размер, чем приложения использующие другие пакеты для управления состоянием, потому что всё, что не используется, не будет скомпилировано в Ваш код. Таким образом каждое решение GetX было спроектировано, чтобы быть сверхлёгким. Также в этом есть и заслуга Flutter, который умеет устранять неиспользуемые ресурсы, как ни один другой фреймворк.\n\n- Getx имеет огромную экосистему, способную работать с одним и тем же кодом на Android, iOS, в Интернете, Mac, Linux, Windows и на вашем сервере.\n**С помощью [Get Server](https://github.com/jonataslaw/get_server) ваш код, созданный на веб-интерфейсе, можно повторно использовать на вашем сервере.**\n\n**Кроме того, весь процесс разработки может быть полностью автоматизирован как на сервере, так и во внешнем интерфейсе с помощью [Get CLI](https://github.com/jonataslaw/get_cli)**.\n\n**Кроме того, для дальнейшего повышения вашей продуктивности у нас есть [расширение для VSCode](https://marketplace.visualstudio.com/items?itemName=get-snippets.get-snippets) и [расширение для Android Studio / Intellij](https://plugins.jetbrains.com/plugin/14975-getx-snippets).**\n\n# Установка\n\nДобавьте Get в файл pubspec.yaml:\n\n```yaml\ndependencies:\n  get:\n```\n\nИмпортируйте Get в файлы, в которых планируете его использовать:\n\n```dart\nimport 'package:get/get.dart';\n```\n\n# Приложение \"Счётчик\" с GetX\n\nПроект \"Счётчик\", созданный по умолчанию для нового проекта на Flutter, имеет более 100 строк (с комментариями). Чтобы показать возможности Get, я продемонстрирую, как сделать \"Счётчик\", изменяющий состояние при каждом клике, переключении между страницами и передаче состояния между экранами. Всё это вместе с разделением бизнес логики от представления занимает ВСЕГО ЛИШЬ 26 СТРОК КОДА, ВКЛЮЧАЯ КОММЕНТАРИИ.\n\n- Шаг 1:\n  Добавьте \"Get\" перед вашим MaterialApp, превращая его в GetMaterialApp\n\n```dart\nvoid main() => runApp(GetMaterialApp(home: Home()));\n```\n\n- Примечание: это не изменяет MaterialApp, GetMaterialApp не является модифицированным MaterialApp, это просто предварительно настроенный виджет, у которого в качестве дочернего по умолчанию используется MaterialApp. Вы можете настроить это вручную, но это не обязательно. GetMaterialApp будет создавать маршруты, вводить их, вводить переводы, вводить всё, что вам нужно для навигации. Если вы используете Get только для управления состоянием или зависимостями, нет необходимости использовать GetMaterialApp. GetMaterialApp необходим для навигации, снекбаров, интернационализации, bottomSheets, диалогов и API, связанных с маршрутами и отсутствием контекста.\n- Примечание²: Этот шаг необходим только в том случае, если вы собираетесь использовать управление маршрутами (`Get.to()`, `Get.back()` и так далее). Если вы не собираетесь его использовать, то шаг 1 выполнять необязательно.\n\n- Шаг 2:\n  Создайте свой класс бизнес-логики и поместите в него все переменные, методы и контроллеры.\n  Вы можете сделать любую переменную наблюдаемой, используя простой \".obs\".\n\n```dart\nclass Controller extends GetxController{\n  var count = 0.obs;\n  increment() => count++;\n}\n```\n\n- Шаг 3:\n  Создайте свой View, используйте StatelessWidget и сэкономьте немного оперативной памяти, с Get вам больше не нужно использовать StatefulWidget.\n\n```dart\nclass Home extends StatelessWidget {\n\n  @override\n  Widget build(context) {\n    \n    // Создайте экземпляр вашего класса с помощью Get.put(), чтобы сделать его доступным для всех \"дочерних\" маршрутов.\n    final Controller c = Get.put(Controller());\n\n    return Scaffold(\n      // Используйте Obx(()=> чтобы обновить Text() как только count изменится.\n      appBar: AppBar(title: Obx(() => Text(\"Кликов: ${c.count}\"))),\n\n      // Замените 8 строк Navigator.push простым Get.to(). Вам не нужен context!\n      body: Center(child: ElevatedButton(\n              child: Text(\"Перейти к Other\"), onPressed: () => Get.to(Other()))),\n      floatingActionButton:\n          FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment));\n  }\n}\n\nclass Other extends StatelessWidget {\n  // \"Попросите\" Get найти и предоставить вам ваш Controller, используемый на другой странице.\n  final Controller c = Get.find();\n\n  @override\n  Widget build(context){\n     // Получите доступ к обновленной переменной count\n     return Scaffold(body: Center(child: Text(\"${c.count}\")));\n  }\n}\n```\n\nРезультат:\n\n![](counter-app-gif.gif)\n\nЭто простой проект, но он уже дает понять, насколько мощным является Get. По мере роста вашего проекта эта разница будет становиться все более значительной.\n\nGet был разработан для работы с командами, но он упрощает работу отдельного разработчика.\n\nОптимизируйте ваши сроки, доставляйте всё вовремя без потери производительности. Get не для всех, но, если вы идентифицировали себя с предыщим предложением, Get для вас!\n\n# Три столпа\n\n## Управление состоянием\n\nВ настоящее время для Flutter есть несколько менеджеров состояний. Однако большинство из них связано с использованием ChangeNotifier для обновления виджетов, и это плохой и очень плохой подход к производительности для средних или больших приложений. Вы можете проверить в официальной документации Flutter, что [ChangeNotifier следует использовать с 1 или максимум 2 слушателями](https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html), что делает его практически непригодным для любого приложения среднего или большого размера.\n\nGet не лучше и не хуже, чем любой другой менеджер состояний, но вам следует проанализировать его, а также пункты ниже, чтобы выбрать между использованием Get в чистой форме (Vanilla), либо совместно с другим менеджером состояний.\n\nОпределенно, Get не враг любого другого менеджера состояний, потому что Get - это микрофреймворк, а не просто менеджер состояний, и его можно использовать отдельно или вместе с ними.\n\nGet имеет два разных менеджера состояний: простой менеджер состояний (мы назовем его GetBuilder) и реактивный менеджер состояний (который называется GetX).\n\n### Реактивное управление состоянием\n\nРеактивное программирование может оттолкнуть многих людей, потому что считается сложным. GetX превращает реактивное программирование в нечто довольно простое:\n\n- Вам не нужно создавать StreamControllers.\n- Вам не нужно создавать StreamBuilder для каждой переменной.\n- Вам не нужно создавать класс для каждого состояния.\n- Вам не нужно создавать геттер начального значения.\n\nРеактивное программирование с Get так же просто, как использование setState.\n\nПредставим, что у вас есть переменная name и вы хотите, чтобы каждый раз, когда вы её изменяете, все виджеты, которые её используют, менялись автоматически.\n\nЭто ваша переменная:\n\n```dart\nvar name = 'Джонатас Борхес';\n```\n\nЧтобы сделать его наблюдаемым, вам просто нужно добавить в конец \".obs\":\n\n```dart\nvar name = 'Джонатас Борхес'.obs;\n```\n\nА в пользовательском интерфейсе, если вы хотите отображать это значение и обновлять экран при изменении значений, просто сделайте следующее:\n\n```dart\nObx(() => Text(\"${controller.name}\"));\n```\n\nВот и всё. Это _так_ просто.\n\n### Подробнее об управлении состоянием\n\n**Более подробное объяснение управления состоянием [здесь](./documentation/ru_RU/state_management.md). Там вы увидите больше примеров, а также разницу между простым менеджером состояния и реактивным менеджером состояния.**\n\nВы получите хорошее представление о мощности GetX.\n\n## Управление маршрутами\n\nЕсли вы собираетесь использовать маршруты / снекбары / диалоги / bottomsheets без контекста, GetX отлично подойдёт вам, просто посмотрите:\n\nДобавьте \"Get\" перед MaterialApp, превратив его в GetMaterialApp.\n\n```dart\nGetMaterialApp( // Ранее: MaterialApp(\n  home: MyHome(),\n)\n```\n\nПерейдите на новый экран:\n\n```dart\n\nGet.to(NextScreen());\n```\n\nПерейдите на новый экран с именем. Более подробную информацию об именованных маршрутах смотрите [здесь](./documentation/ru_RU/route_management.md#navigation-with-named-routes)\n\n```dart\n\nGet.toNamed('/details');\n```\n\nЗакрыть снекбар, диалог, bottomsheets, или что-то иное, что вы обычно закрывали с помощью Navigator.pop(context);\n\n```dart\nGet.back();\n```\n\nДля перехода к следующему экрану без возможности вернуться к предыдущему экрану (для использования в SplashScreens, экранах входа и т. д.)\n\n```dart\nGet.off(NextScreen());\n```\n\nДля перехода к следующему экрану и отмены всех предыдущих маршрутов (полезно в корзинах для покупок, опросах и тестах)\n\n```dart\nGet.offAll(NextScreen());\n```\n\nЗаметили, что вам не нужно было использовать контекст, чтобы делать что-либо из этого? Это одно из самых больших преимуществ использования Get. Благодаря этому вы можете без проблем выполнять все эти методы из класса контроллера.\n\n### Подробнее об управлении маршрутами\n\n**Get работает с именованными маршрутами, а также предлагает более низкий уровень контроля над вашими маршрутами! [Здесь](./documentation/ru_RU/route_management.md) есть подробная документация.**\n\n## Внедрение зависимостей\n\nGet имеет простой и мощный менеджер зависимостей, который позволяет вам получить тот же класс, что и ваш BLoC или контроллер, всего одной строкой кода, без Provider context, без InheritedWidget:\n\n```dart\nController controller = Get.put(Controller()); // Вместо Controller controller = Controller();\n```\n\n- Примечание: Если вы используете Get State Manager, обратите больше внимания на API привязок, который упростит подключение вашего представления к контроллеру.\n\nВместо того, чтобы создавать экземпляр вашего класса внутри класса, который вы используете, вы создаете его в экземпляре Get, что сделает его доступным во всем приложении. Таким образом, вы можете использовать свой контроллер (или BLoC) в обычном режиме.\n\n**Совет:** Управление зависимостями Get не связано с другими частями пакета, поэтому, если, например, ваше приложение уже использует менеджер состояний (любой, не имеет значения), вам не нужно все это переписывать, вы можете использовать это внедрение зависимостей без проблем.\n\n```dart\ncontroller.fetchApi();\n```\n\nПредставьте, что вы прошли через множество маршрутов и вам нужны данные, которые остались в вашем контроллере, вам понадобится менеджер состояний в сочетании с Provider или Get_it, верно? Только не с Get. Вам просто нужно попросить Get «найти» ваш контроллер, никаких дополнительных зависимостей вам не потребуется:\n\n```dart\nController controller = Get.find();\n// Да, это выглядит как Магия! Get найдет ваш controller и доставит его вам. У вас может быть миллион созданных контроллеров, и Get всегда найдет нужный.\n```\n\nИ тогда вы сможете восстановить данные вашего контроллера, которые были там получены:\n\n```dart\nText(controller.textFromApi);\n```\n\n### Подробнее о внедрении зависимостей\n\n**Более подробное объяснение управления зависимостями [здесь](./documentation/ru_RU/dependency_management.md)**\n\n# Утилиты\n\n## Интернационализация\n\n### Переводы\n\nПереводы хранятся в виде карты пар \"ключ-значение\". Чтобы добавить собственные переводы, создайте класс и расширьте `Translations`.\n\n```dart\nimport 'package:get/get.dart';\n\nclass Messages extends Translations {\n  @override\n  Map<String, Map<String, String>> get keys => {\n        'en_US': {\n          'hello': 'Hello World',\n        },\n        'de_DE': {\n          'hello': 'Hallo Welt',\n        }\n      };\n}\n```\n\n#### Использование переводов\n\nПросто добавьте `.tr` к указанному ключу, и он будет переведен с использованием текущего значения `Get.locale` и `Get.fallbackLocale`.\n\n```dart\nText('title'.tr);\n```\n\n### Локализация\n\nПередайте параметры в `GetMaterialApp`, чтобы определить языковой стандарт и переводы.\n\n```dart\nreturn GetMaterialApp(\n    translations: Messages(), // ваши переводы\n    locale: Locale('en', 'US'), // перевод будет осуществлен в этой локализации\n    fallbackLocale: Locale('en', 'UK'), // установите резервную локализацию на случай если будет выбрана невалидный локализация.\n);\n```\n\n#### Изменение локализации\n\nВызовите `Get.updateLocale(locale)`, чтобы обновить локализацию. Затем переводы автоматически используют новый языковой стандарт.\n\n```dart\nvar locale = Locale('en', 'US');\nGet.updateLocale(locale);\n```\n\n#### Системная локализация\n\nЧтобы узнать системную локализацию, вам следует использовать `window.locale`.\n\n```dart\nimport 'dart:ui' as ui;\n\nreturn GetMaterialApp(\n    locale: ui.window.locale,\n);\n```\n\n## Изменение темы\n\nПожалуйста, не используйте виджет более высокого уровня, чем `GetMaterialApp`, для его обновления. Это может вызвать повторяющиеся ключи. Многие люди привыкли к старому подходу к созданию виджета «ThemeProvider» только для того, чтобы изменить тему вашего приложения, а это НЕ требуется с GetX ™.\n\nВы можете создать свою собственную тему и просто добавить ее в `Get.changeTheme` без повторяющегося кода:\n\n```dart\nGet.changeTheme(ThemeData.light());\n```\n\nЕсли вы хотите создать что-то вроде кнопки, которая изменяет тему, вы можете объединить для этого два API **GetX ™**:\n\n- API, который проверяет, используется ли темная тема.\n- И API смены темы.\n\nВы можете просто поместить это в `onPressed`:\n\n```dart\nGet.changeTheme(Get.isDarkMode? ThemeData.light(): ThemeData.dark());\n```\n\nКогда `.darkmode` активен, он переключится на _light theme_, и когда _light theme_ станет активной, он изменится на _dark theme_.\n\n## Другие API\n\n```dart\n// получить текущие аргументы текущего экрана\nGet.arguments\n\n// получить аргументы предыдущего маршрута\nGet.previousArguments\n\n// получить имя предыдущего маршрута\nGet.previousRoute\n\n// получить чистый маршрут, например, чтобы узнать: rawRoute.isFirst()\nGet.rawRoute\n\n// получить доступ к Rounting API из GetObserver\nGet.routing\n\n// проверить, открыт ли снекбар\nGet.isSnackbarOpen\n\n// открыт ли диалог\nGet.isDialogOpen\n\n// открыт ли bottomsheets\nGet.isBottomSheetOpen\n\n// удалить один маршрут\nGet.removeRoute()\n\n// возвращаться назад, пока данный предикат не выполнится\nGet.until()\n\n// идти вперед, удалив предыдущие маршруты, пока данный предикат не выполнится\nGet.offUntil()\n\n// перейти к следующему именованному маршруту, удалив предыдущие маршруты, пока данный предикат не выполнится\nGet.offNamedUntil()\n\n// проверить на какой платформе работает приложение\nGetPlatform.isAndroid\nGetPlatform.isIOS\nGetPlatform.isMacOS\nGetPlatform.isWindows\nGetPlatform.isLinux\nGetPlatform.isFuchsia\n\n// проверить тип устройства\nGetPlatform.isMobile\nGetPlatform.isDesktop\n// В вебе все платформы поддерживаются независимо!\n// Можно узнать, работает ли приложение сейчас в браузере\n// и на Windows, и на iOS, и на OSX, и на Android и так далее\nGetPlatform.isWeb\n\n\n// Эквивалент : MediaQuery.of(context).size.height,\n// но неизменяемый.\nGet.height\nGet.width\n\n// Текущий контекст навигации\nGet.context\n\n// Получить контекст показанного снекбара/диалога/bottomsheets в любом месте вызова.\nGet.contextOverlay\n\n// Внимание: методы ниже являются расширениями класса BuildContext.\n// Поскольку доступ к контексту есть в любом месте из вашего UI,\n// вы можете использовать расширения в любом месте UI кода\n\n// Если вам нужна изменяемая высота/ширина (например, настольное или браузерное окно, размер которого можно изменить), вам нужно использовать context\ncontext.width\ncontext.height\n\n// Дает возможность определить половину экрана, треть и так далее.\n// Полезно для отзывчивых приложений.\n// param dividedBy (double) optional - default: 1\n// param reducedBy (double) optional - default: 0\ncontext.heightTransformer()\ncontext.widthTransformer()\n\n/// Схоже с MediaQuery.of(context).size\ncontext.mediaQuerySize()\n\n/// Схоже с MediaQuery.of(context).padding\ncontext.mediaQueryPadding()\n\n/// Схоже с MediaQuery.of(context).viewPadding\ncontext.mediaQueryViewPadding()\n\n/// Схоже с MediaQuery.of(context).viewInsets;\ncontext.mediaQueryViewInsets()\n\n/// Схоже с MediaQuery.of(context).orientation;\ncontext.orientation()\n\n/// Проверить, в горизонтальном ли режиме устройство\ncontext.isLandscape()\n\n/// Проверить, в вертикальном ли режиме устройство\ncontext.isPortrait()\n\n/// Схоже с to MediaQuery.of(context).devicePixelRatio;\ncontext.devicePixelRatio()\n\n/// Схоже с MediaQuery.of(context).textScaleFactor;\ncontext.textScaleFactor()\n\n/// Получить shortestSide экрана\ncontext.mediaQueryShortestSide()\n\n/// Вернет True, если ширина больше 800\ncontext.showNavbar()\n\n/// Вернет True, если меньшая сторона меньше 600p\ncontext.isPhone()\n\n/// Вернет True, если меньшая сторона больше 600p\ncontext.isSmallTablet()\n\n/// Вернет True, если меньшая сторона больше 720p\ncontext.isLargeTablet()\n\n/// Вернет True, если текущее устройство — Планшет\ncontext.isTablet()\n\n/// Возвращает value<T> в зависимости от размера экрана\n/// Можно устанавливать значения для:\n/// watch: Если меньшая сторона меньше 300\n/// mobile: Если меньшая сторона меньше 600\n/// tablet: Если меньшая сторона меньше 1200\n/// desktop: Если ширина больше 1200\ncontext.responsiveValue<T>()\n```\n\n### Дополнительные глобальные настройки и ручные настройки\n\nGetMaterialApp настраивает все за вас, но если вы хотите настроить Get вручную.\n\n```dart\nMaterialApp(\n  navigatorKey: Get.key,\n  navigatorObservers: [GetObserver()],\n);\n```\n\nВы также сможете использовать собственное промежуточное ПО в `GetObserver`, это ни на что не повлияет.\n\n```dart\nMaterialApp(\n  navigatorKey: Get.key,\n  navigatorObservers: [\n    GetObserver(MiddleWare.observer) // Here\n  ],\n);\n```\n\nВы можете создать _Глобальные Настройки_ Для `Get`. Просто добавьте `Get.config` в ваш код прежде чем нажимать на любой из маршрутов.\nИли сделайте это прямо в `GetMaterialApp`\n\n```dart\nGetMaterialApp(\n  enableLog: true,\n  defaultTransition: Transition.fade,\n  opaqueRoute: Get.isOpaqueRouteDefault,\n  popGesture: Get.isPopGestureEnable,\n  transitionDuration: Get.defaultDurationTransition,\n  defaultGlobalState: Get.defaultGlobalState,\n);\n\nGet.config(\n  enableLog = true,\n  defaultPopGesture = true,\n  defaultTransition = Transitions.cupertino\n)\n```\n\nПри желании, вы сможете перенаправить все сообщения из `Get`.\nЕсли вы хотите использовать свой любимый пакет для логирования и собирать логи там:\n\n```dart\nGetMaterialApp(\n  enableLog: true,\n  logWriterCallback: localLogWriter,\n);\n\nvoid localLogWriter(String text, {bool isError = false}) {\n  // передайте сообщение вашей любимой log-библиотеке\n  // но учитывайте, что даже если enableLog: false, сообщения все равно будут передаваться сюда\n  // узнать значение этого флага можно с помощью GetConfig.isLogEnable\n}\n\n```\n\n### Локальные виджеты состояния\n\nЭти виджеты позволяют управлять одним значением, сохраняя состояние эфемерным и локальным.\nУ нас есть варианты для Reactive и Simple.\nНапример, вы можете использовать их для переключения obscureText в `TextField`, возможно, для создания кастомного ExpandablePanel или, возможно, для изменения текущего индекса в `BottomNavigationBar` при изменении содержимого body в `Scaffold`.\n\n#### ValueBuilder\n\nУпрощение `StatefulWidget` который работает с вызовом `.setState` принимающим обновленное значение.\n\n```dart\nValueBuilder<bool>(\n  initialValue: false,\n  builder: (value, updateFn) => Switch(\n    value: value,\n    onChanged: updateFn, // такая же сигнатура! Вы можете использовать ( newValue ) => updateFn( newValue )\n  ),\n  // Если нужно вызвать что-то вне метода builder\n  onUpdate: (value) => print(\"Значение обновлено: $value\"),\n  onDispose: () => print(\"Виджет удален\"),\n),\n```\n\n#### ObxValue\n\nПохож на [`ValueBuilder`](#valuebuilder), но это реактивная версия, вы передаёте Rx экземпляр (помните волшебный .obs?) и\nавтоматически обновляетесь... разве это не великолепно?\n\n```dart\nObxValue((data) => Switch(\n        value: data.value,\n        onChanged: data, // У Rx есть _callable_ функция! Вы можете использовать (flag) => data.value = flag,\n    ),\n    false.obs,\n),\n```\n\n## Полезные советы\n\n`.obs`ervables (наблюдатели) (также известные как Rx-типы) имеют широкий спектр внутренних методов и операторов\n\n> Очень распространено _мнение_, что свойство с `.obs` **ЯВЛЯЕТСЯ** действительным значением... но не ошибайтесь!\n> Мы избегаем объявления типа переменной, потому что компилятор Dart достаточно умен, и\n> код выглядит чище, но:\n\n```dart\nvar message = 'Привет, мир'.obs;\nprint( 'Тип \"$message\" — ${message.runtimeType}');\n```\n\nДаже если `message` _выводит_ значение String, его тип - **RxString**!\n\nИтак, вы не сможете сделать `message.substring( 0, 4 )`.\nВы должны получить доступ к реальному `value` внутри _observable_:\nСамый \"используемый способ\" это `.value`, но, знаете ли вы, что вы также можете использовать ...\n\n```dart\nfinal name = 'GetX'.obs;\n// \"обновляет\" поток только если значение отличается от текущего.\nname.value = 'Хей';\n\n// Все свойства Rx являются \"вызываемыми\" и возвращают новые значения.\n// но это не работает с `null`: UI не будет перестроен.\nname('Привет');\n\n// как геттер, напечатает 'Привет'.\nname() ;\n\n/// числа:\n\nfinal count = 0.obs;\n\n// Вы можете использовать все неизменяемые операции с числами!\ncount + 1;\n\n// Осторожно! Это можно использовать только если `count` не final, а var\ncount += 1;\n\n// Сравнения так же работают:\ncount > 2;\n\n/// логические:\n\nfinal flag = false.obs;\n\n// переключает значение между true/false\nflag.toggle();\n\n\n/// все типы:\n\n// обнуляет значение переменной `value`.\nflag.nil();\n\n// Все toString(), toJson() операции применяются к `value`\nprint( count ); // вызывает `toString()` внутри RxInt\n\nfinal abc = [0,1,2].obs;\n// Преобразует значение в json массив, выводит RxList\n// Json поддерживается всеми Rx типами!\nprint('json: ${jsonEncode(abc)}, тип: ${abc.runtimeType}');\n\n// RxMap, RxList и RxSet являются особенными Rx типами: они расширяют нативные типы.\n// Но вы можете работать со списком как и с обычным списком, хоть и реактивным!\nabc.add(12); // добавлеет 12 в список, and ОБНОВЛЯЕТ поток.\nabc[3]; // как списки, возвращает значение с индексом 3.\n\n\n// Сравнение равенства работает с Rx и с его value, но хэш код всегда берется у value\nfinal number = 12.obs;\nprint( number == 12 ); // печатает true\n\n/// Кастомные Rx Модели:\n\n// toJson(), toString() передаются child, так что вы можете перегрузить эти методы в нем, и вызвать print напрямую.\n\nclass User {\n    String name, last;\n    int age;\n    User({this.name, this.last, this.age});\n\n    @override\n    String toString() => '$name $last, возраст: $age';\n}\n\nfinal user = User(name: 'Джон', last: 'Доу', age: 33).obs;\n\n// `user` – \"реактивный\", но его свойства – НЕТ!\n// Так что если мы обновим что-либо внутри user...\nuser.value.name = 'Рой';\n// Виджет перестроен не будет!\n// `Rx` не знает, изменили ли вы что-то у user.\n// Так что для кастомных классов вам нужно явно \"уведомлять\" об изменении.\nuser.refresh();\n\n// или мы можем использовать метод `update()`!\nuser.update((value){\n  value.name='Рой';\n});\n\nprint( user );\n```\n\n#### GetView\n\nЯ люблю этот виджет, он такой простой, но такой полезный!\n\nЭто `const Stateless` виджет, который имеет геттер `controller` для зарегистрированного `Controller`, вот и всё.\n\n```dart\n class AwesomeController extends GetxController {\n   final String title = 'Моя Удивительная View';\n }\n\n  // ВСЕГДА передавайте `Тип` вашего контроллера!\n class AwesomeView extends GetView<AwesomeController> {\n   @override\n   Widget build(BuildContext context) {\n     return Container(\n       padding: EdgeInsets.all(20),\n       child: Text( controller.title ), // просто вызовите `controller.что-то`\n     );\n   }\n }\n```\n\n#### GetWidget\n\nБольшинство людей понятия не имеют об этом виджете или путаются при его применении.\nВариант его использования редок, но конкретен: он кэширует Controller.\nПоэтому из-за _cache_, он не может быть `const Stateless`.\n\n> Итак, когда вам нужно «кэшировать» контроллер?\n\nВ случаях использования другой \"не распространённой\" фичи **GetX**: `Get.create()`.\n\n`Get.create(()=>Controller())` будет создавать новый `Controller` каждый раз при вызове\n`Get.find<Controller>()`,\n\nЭто тот самый случай, когда `GetWidget` блистает... поскольку вы можете использовать его, например, для хранения списка элементов Todo. Итак, если виджет будет «перестроен», он сохранит тот же экземпляр контроллера.\n\n#### GetxService\n\nЭтот класс похож на `GetxController`, у него такой же жизненный цикл ( `onInit()`, `onReady()`, `onClose()`).\nНо внутри нет никакой «логики». Он просто уведомляет систему **GetX** Dependency Injection о том, что этот подкласс **нельзя** удалить из памяти.\n\nТак что очень полезно держать ваши «Сервисы» всегда доступными и активными с помощью `Get.find()`. Например:\n`ApiService`, `StorageService`, `CacheService`.\n\n```dart\nFuture<void> main() async {\n  await initServices(); /// ПОДОЖДИТЕ ИНИЦИАЛИЗАЦИЮ СЕРВИСОВ.\n  runApp(SomeApp());\n}\n\n/// Умным решением будет проинициализировать сервисы перед вызовом runApp,\n/// поскольку вы можете контроллировать процесс инициализации\n/// (может, вам нужно загрузить конфигурацию Темы, ключи API, язык, определенный пользователем...\n/// Загружайте SettingService прежде чем запускать ApiService.\n/// Таким образом GetMaterialApp() принимает параметры напрямую, и ему не нужно будет перезагружаться\nvoid initServices() async {\n  print('запуск сервисов ...');\n  /// Здесь вы инициализируете get_storage, hive, shared_pref,\n  /// или что-либо другое асинхронное.\n  await Get.putAsync(() => DbService().init());\n  await Get.putAsync(SettingsService()).init();\n  print('Все сервисы запущены...');\n}\n\nclass DbService extends GetxService {\n  Future<DbService> init() async {\n    print('$runtimeType задержка 2 секунды');\n    await 2.delay();\n    print('$runtimeType готов!');\n    return this;\n  }\n}\n\nclass SettingsService extends GetxService {\n  void init() async {\n    print('$runtimeType задержка 1 секунду');\n    await 1.delay();\n    print('$runtimeType готов!');\n  }\n}\n\n```\n\nЕдинственный способ удалить `GetxService` - использовать `Get.reset()`,  который похож на «горячую перезагрузку» вашего приложения. Так что помните, если вам нужен постоянный экземпляр класса в течение всего жизненного цикла вашего приложения, используйте `GetxService`.\n\n# Критические изменения по сравнению с версией 2.0\n\n1- Rx типы:\n\n| До      | После      |\n| ------- | ---------- |\n| StringX | `RxString` |\n| IntX    | `RxInt`    |\n| MapX    | `RxMap`    |\n| ListX   | `RxList`   |\n| NumX    | `RxNum`    |\n| DoubleX | `RxDouble` |\n\nRxController и GetBuilder теперь объединены, вам больше не нужно запоминать, какой контроллер вы хотите использовать, просто используйте GetxController, он будет работать как для простого управления состоянием, так и для реактивного.\n\n2- NamedRoutes\nДо:\n\n```dart\nGetMaterialApp(\n  namedRoutes: {\n    '/': GetRoute(page: Home()),\n  }\n)\n```\n\nСейчас:\n\n```dart\nGetMaterialApp(\n  getPages: [\n    GetPage(name: '/', page: () => Home()),\n  ]\n)\n```\n\nДля чего это изменение?\nЧасто может потребоваться решить, какая страница будет отображаться с помощью параметра или токена входа, предыдущий подход был негибким, так как он не позволял этого.\nВставка страницы в функцию значительно снизила потребление оперативной памяти, поскольку маршруты не будут выделяться в памяти с момента запуска приложения, а также позволил использовать такой подход:\n\n```dart\n\nGetStorage box = GetStorage();\n\nGetMaterialApp(\n  getPages: [\n    GetPage(name: '/', page:(){\n      return box.hasData('token') ? Home() : Login();\n    })\n  ]\n)\n```\n\n# Почему Getx?\n\n1- Много раз после обновления Flutter многие из ваших пакетов ломались. Иногда случаются ошибки компиляции, часто возникают ошибки, на которые до сих пор нет ответов, и разработчику необходимо знать, откуда возникла ошибка, отслеживать ошибку, только затем попытаться открыть проблему в соответствующем репозитории и увидеть, как проблема решена. Get централизует основные ресурсы для разработки (управление состоянием, зависимостями и маршрутами), позволяя вам добавить один пакет в свой pubspec и начать работу. После обновления Flutter единственное, что вам нужно сделать, это обновить зависимость Get и приступить к работе. Get также решает проблемы совместимости. Как часто бывало, что одна версия пакета несовместима с другой, потому что одна использует зависимость в одной версии, а другая - в другой? Это не проблема при использовании Get, поскольку все находится в одном пакете и полностью совместимо.\n\n2- Flutter - это просто, Flutter - это невероятно, но у Flutter все еще некоторый шаблонный код, который может быть нежелательным для большинства разработчиков, например `Navigator.of(context).push (context, builder [...]`. Get упрощает разработку. Вместо того, чтобы писать 8 строк кода для вызова маршрута, вы можете просто сделать это: `Get.to(Home())` и всё готово, вы перейдёте на следующую страницу. Динамические URL-адреса - это действительно болезненная вещь, которую нужно решать во Flutter в настоящее время, а с GetX это элементарно. Управление состояниями во Flutter и управление зависимостями также вызывает много споров, поскольку в pub есть сотни паттернов. Но нет ничего проще, чем добавить «.obs» в конец вашей переменной и поместить ваш виджет внутри Obx, и всё, все обновления этой переменной будут автоматически обновляться на экране.\n\n3- Лёгкость, не беспокоясь о производительности. Производительность Flutter уже потрясающая, но представьте, что вы используете диспетчер состояний и локатор для распределения классов блоков / хранилищ / контроллеров / и других классов. Вам придётся вручную вызывать исключение этой зависимости, когда она вам не нужна. Но вы когда-нибудь думали о том, чтобы просто использовать свой контроллер, и когда он больше никем не использовался, он просто был бы удален из памяти? Это то, что делает GetX. Благодаря SmartManagement всё, что не используется, удаляется из памяти, и вам не нужно беспокоиться ни о чем, кроме программирования. Вы будете уверены, что потребляете минимум необходимых ресурсов, даже не создав для этого логики.\n\n4- Действительное разделение. Вы могли слышать о концепции разделения представления от бизнес логики. Это не исключительная особенность BLoC, MVC, MVVM и тд, любой стандарт реализует эту концепцию. Однако во Flutter возможно ослабление этой концепции из-за необходимости использования контекста.\nЕсли вам нужен контекст для поиска InheritedWidget, он вам нужен в представлении, либо нужно передать контекст как параметр. Мы считаем это решение очень уродливым, и для работы в команде мы всегда будем зависеть от логики представления (View). Getx - необычный подход со стандартным доступом, который хоть и не запрещает использование StatefulWidgets, InitState, и т.д., всегда имеет более чистый аналог. У контроллеров есть жизненные циклы, и когда вам нужно сделать, например, запрос APIREST, вы не зависите ни от чего в представлении. Вы можете использовать onInit для инициирования http-вызова, и когда данные поступят, переменные будут заполнены. Поскольку GetX полностью реактивен (действительно реактивен и работает с потоками), после заполнения элементов все виджеты, использующие эту переменную, будут автоматически обновлены в представлении. Это позволяет людям с опытом работы с пользовательским интерфейсом работать только с виджетами и не отправлять в бизнес-логику ничего, кроме пользовательских событий (например, нажатия кнопки), в то время как люди, работающие с бизнес-логикой, смогут создавать и тестировать бизнес-логику отдельно.\n\nЭта библиотека всегда будет обновляться и реализовывать новые функции. Не стесняйтесь предлагать PR.\n\n# Сообщества\n\n## Каналы сообщества\n\nУ GetX очень активное и готовое к взаимовыручке сообщество. Если у вас есть вопросы или вы хотите получить какую-либо помощь относительно использования этого фреймворка, присоединяйтесь к нашим каналам сообщества, на ваш вопрос ответят быстро. Этот репозиторий предназначен исключительно для открытия проблем и запроса ресурсов, но не стесняйтесь быть частью сообщества GetX.\n\n| **Slack**                                                                                                                   | **Discord**                                                                                                                 | **Telegram**                                                                                                          |\n| :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------- |\n| [![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) |\n\n## Как внести свой вклад\n\n_Хотите внести свой вклад в проект? Вы будем рады отметить вас как одного из наших соавторов. Вот несколько направлений, где вы можете сделать Get (и Flutter) лучше._\n\n- Помощь в переводе readme на другие языки.\n- Добавление документации в readme (многие функции Get еще не задокументированы).\n- Напишите статью или сделайте видео, обучающие использованию Get (они будут вставлены в Readme и в будущем в нашу Wiki).\n- Предложите PRs для кода/тестов.\n- Новые фичи.\n\nПриветствуется любой вклад!\n\n## Статьи и видео\n\n- [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).\n- [Complete GetX™ Navigation](https://www.youtube.com/watch?v=RaqPIoJSTtI) - Route management video by Amateur Coder.\n- [Complete GetX State Management](https://www.youtube.com/watch?v=CNpXbeI_slw) - State management video by Amateur Coder.\n- [GetX™ Other Features](https://youtu.be/ttQtlX_Q0eU) - Utils, storage, bindings and other features video by Amateur Coder.\n- [Firestore User with GetX | Todo App](https://www.youtube.com/watch?v=BiV0DcXgk58) - Video by Amateur Coder.\n- [Firebase Auth with GetX | Todo App](https://www.youtube.com/watch?v=-H-T_BSgfOE) - Video by Amateur Coder.\n- [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).\n- [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.\n- [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.\n- [GetX Flutter Firebase Auth Example](https://medium.com/@jeffmcmorris/getx-flutter-firebase-auth-example-b383c1dd1de2) - Article by Jeff McMorris.\n"
  },
  {
    "path": "README.tr-TR.md",
    "content": "![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png)\n\n[![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)\n[![popularity](https://badges.bar/get/popularity)](https://pub.dev/packages/sentry/score)\n[![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)\n[![pub points](https://badges.bar/get/pub%20points)](https://pub.dev/packages/get/score)\n![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)\n[![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart)\n[![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N)\n[![Get on Slack](https://img.shields.io/badge/slack-join-orange.svg)](https://communityinviter.com/apps/getxworkspace/getx)\n[![Telegram](https://img.shields.io/badge/chat-on%20Telegram-blue.svg)](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g)\n<a href=\"https://github.com/Solido/awesome-flutter\">\n<img alt=\"Awesome Flutter\" src=\"https://img.shields.io/badge/Awesome-Flutter-blue.svg?longCache=true&style=flat-square\" />\n</a>\n<a href=\"https://www.buymeacoffee.com/jonataslaw\" target=\"_blank\"><img src=\"https://i.imgur.com/aV6DDA7.png\" alt=\"Buy Me A Coffee\" style=\"height: 41px !important;width: 174px !important; box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;\" > </a>\n\n![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/getx.png)\n\n\n<div align=\"center\">\n\n**Languages:**\n\n  \n[![English](https://img.shields.io/badge/Language-English-blueviolet?style=for-the-badge)](README.md)\n[![Vietnamese](https://img.shields.io/badge/Language-Vietnamese-blueviolet?style=for-the-badge)](README-vi.md)\n[![Indonesian](https://img.shields.io/badge/Language-Indonesian-blueviolet?style=for-the-badge)](README.id-ID.md)\n[![Urdu](https://img.shields.io/badge/Language-Urdu-blueviolet?style=for-the-badge)](README.ur-PK.md)\n[![Chinese](https://img.shields.io/badge/Language-Chinese-blueviolet?style=for-the-badge)](README.zh-cn.md)\n[![Portuguese](https://img.shields.io/badge/Language-Portuguese-blueviolet?style=for-the-badge)](README.pt-br.md)\n[![Spanish](https://img.shields.io/badge/Language-Spanish-blueviolet?style=for-the-badge)](README-es.md)\n[![Russian](https://img.shields.io/badge/Language-Russian-blueviolet?style=for-the-badge)](README.ru.md)\n[![Polish](https://img.shields.io/badge/Language-Polish-blueviolet?style=for-the-badge)](README.pl.md)\n[![Korean](https://img.shields.io/badge/Language-Korean-blueviolet?style=for-the-badge)](README.ko-kr.md)\n[![French](https://img.shields.io/badge/Language-French-blueviolet?style=for-the-badge)](README-fr.md)\n[![Japanese](https://img.shields.io/badge/Language-Japanese-blueviolet?style=for-the-badge)](README.ja-JP.md)\n[![Turkish](https://img.shields.io/badge/Language-Turkish-blueviolet?style=for-the-badge)](README.tr-TR.md)\n\n</div>\n\n- [Get Hakkında](#get-hakkında)\n- [Kurulum](#kurulum)\n- [GetX ile Sayaç Uygulaması](#getx-ile-sayaç-uygulaması)\n- [Üç Temel Kavram](#üç-temel-kavram)\n  - [State Management (Durum Yönetimi)](#state-management-durum-yönetimi)\n    - [Reactive State Manager (Reaktif Durum Yönetimi)](#reactive-state-manager-reaktif-durum-yönetimi)\n    - [State Management Hakkında Daha Fazla Bilgi](#state-management-hakkında-daha-fazla-bilgi)\n  - [Route Management (Rota Yönetimi)](#route-management-rota-yönetimi)\n    - [Route Management Hakkında Daha Fazla Bilgi](#route-management-hakkında-daha-fazla-bilgi)\n  - [Dependency Management (Bağımlılık Yönetimi)](#dependency-management-bağımlılık-yönetimi)\n    - [Dependency Management Hakkında Daha Fazla Bilgi](#dependency-management-hakkında-daha-fazla-bilgi)\n- [Utils](#utils)\n  - [Internationalization (Uluslararasılaştırma)](#internationalization-uluslararasılaştırma)\n    - [Translations (Çeviriler)](#translations-çeviriler)\n      - [Translations Kullanımı](#translations-kullanımı)\n    - [Locales (Yerel Ayarlar)](#locales-yerel-ayarlar)\n      - [Locale Değiştirme](#locale-değiştirme)\n      - [System locale (Yerel Sistem Ayarları)](#system-locale-yerel-sistem-ayarları)\n  - [Tema Değiştirme](#tema-değiştirme)\n  - [GetConnect](#getconnect)\n    - [Varsayılan Ayarlar](#varsayılan-ayarlar)\n    - [Özel Ayarlarlamalar](#özel-ayarlamalar)\n  - [GetPage Middleware](#getpage-middleware)\n    - [Priority (Öncelik)](#priority-öncelik)\n    - [Redirect (Yönlendirme)](#redirect-yönlendirme)\n    - [onPageCalled](#onpagecalled)\n    - [OnBindingsStart](#onbindingsstart)\n    - [OnPageBuildStart](#onpagebuildstart)\n    - [OnPageBuilt](#onpagebuilt)\n    - [OnPageDispose](#onpagedispose)\n  - [Advanced APIs (Gelişmiş API'ler)](#advanced-apis-gelişmiş-apiler)\n    - [Opsiyonel Genel Ayarlar ve Manuel Ayarlamalar](#opsiyonel-genel-ayarlar-ve-manuel-ayarlamalar)\n    - [Local State Widgets (Yerel Durum Widgetları)](#local-state-widgets-yerel-durum-widgetları)\n      - [ValueBuilder](#valuebuilder)\n      - [ObxValue](#obxvalue)\n  - [Faydalı İpuçları](#faydalı-ipuçları)\n    - [GetView](#getview)\n    - [GetResponsiveView](#getresponsiveview)\n      - [Nasıl Kullanılır?](#nasıl-kullanılır)\n    - [GetWidget](#getwidget)\n    - [GetxService](#getxservice)\n- [2.0 İle Gelen Büyük Değişiklikler](#20-ile-gelen-büyük-değişiklikler)\n- [Neden Getx?](#neden-getx)\n- [Topluluk](#topluluk)\n  - [Topluluk Kanalları](#topluluk-kanalları)\n  - [Nasıl katkıda bulunulur?](#nasıl-katkıda-bulunulur)\n  - [Makaleler ve Videolar](#makaleler-ve-videolar)\n\n# Get Hakkında\n\n- GetX, Flutter için oldukça basit ve güçlü bir çözüm yoludur. Yüksek performanslı state managment (durum yönetimi), yetenekli dependency injection (bağımlılık enjeksiyonu) ve route management'ı (rota yönetimi) hızlı ve pratik şekilde bir araya getirir.\n\n- GetX'in 3 temel ilkesi vardır. Bu ilkeler kütüphanedeki tüm kaynaklar için önemlidir: **ÜRETKENLİK, PERFORMANS VE ORGANİZASYON.**\n\n  - **PERFORMANS:** GetX, performansa ve kaynakların minimum düzeyde tüketimine odaklanmıştır. GetX, Streams ya da ChangeNotifier kullanmaz.\n\n  - **ÜRETKENLİK:** GetX kolay ve keyifli bir syntax (yazım kuralları) kullanır. Ne yapmak istersen iste GetX'de her zaman kolay bir çözüm yolu vardır. Saatlerce süren geliştirmeden tasarruf etmeyi ve uygulanın size sağladığı  performansı maksimum seviyede kullanmayı mümkün kılar.\n\n    Normalde geliştirici, controller'ları hafızadan kaldırmakla ilgilenmelidir. GetX ile bunu yapmaya gerek kalmaz çünkü varsayılan olarak kaynaklar kullanılmadığı zaman hafızadan kendiliğinden kaldırılır. Eğer hafızada tutmak istiyorsanız, dependency içinde \"permanent: true\" olarak tanımlanmanız gerekmektedir. Bu şekilde hem zaman tasarrufu hem de hafızadaki gereksiz dependency'lerin oluşturabileceği riskler azaltmış olur. Dependency yüklemesi varsayılan olarak lazy'dir (tembeldir).\n\n  - **ORGANİZASYON:**  GetX, presentation logic'i (sunum mantığını, business logic'i (iş mantığını), dependency injection'ı, navigasyonu View'dan tamamen ayırmayı sağlar. Route'lar arasında navigasyon için context'e gerek duyulmaz bu sayede widget tree'ye (widget ağacına) bağımlı kalmazsınız. Controllers ya da blocs'daki inheritedWidget'a erişmek için context'e ihtiyaç duyulmaz böylelikle presentation logic ve business logic, view katmanından tamamen ayrılır. Controllers/Models/Blocs sınıflarını widget tree'ye inject (aktarırken) ederken `MultiProvider`'lar kullanılmasına ihtiyaç yoktur. GetX'in kendine ait dependency injection özelliği sayesinde DI'yi de view'dan tamamen ayrır.\n\n    GetX ile varsayılan olarak temiz kod kullanılarak uygulamadaki her bir özelliğin nerede bulunduğuna ulaşabilirsiniz. Bakım kolaylığının yanı sıra Flutter'da düşünüleyemeyen bir şey olan modülleri paylaşmayı tamamen mümkün kılar.\n    BLoC, Flutter'daki kodları organize etmenin başlangıç noktasıdır. Business logic'i, view'dan ayırır. Bunun gelişmiş hali olarak ortaya çıkan GetX sadece business logic'i ayırmakla kalmayıp aynı zamanda dependency injection'ları, route'ları ve presentation logic'i de view'dan ayırır. Data layer (Veri katmanı) bu sayede bütün katmanların dışında bırakılır. Her şeyin nerde olduğunu bilmek \"hello word\" oluşturmaktan çok daha kolay bir yoldur.\n    GetX, Flutter SDK'sı ile çok kolay, pratik ve ölçeklenebilir yüksek performanslı uygulamalar yapmanızı sağlar. Birlikte çalışılabilen büyük bir ekosistem içerir. Yeni başlayanlar için oldukça kolay ve uzmanlar için de doğru olandır. Güvenli, stabil, güncel ve Flutter SDK'da varsayılan olarak olmayan büyük kapsamlı APIs kullanabilmeyi sağlar.\n\n- GetX şişkin değildir. Çoklu davranış içeren özellikleri kullanarak, herhangi bir endişe olmaksızın programlamaya başlamanızı sağlar. Ancak bu özellikler farklı taraflarda olup sadece kullanıldıktan sonra başlatılır. Sadece state management kullanıyorsanız, sadece bu derlenir. Sadece routes kullanırsanız, state management'dan hiçbir şey derlenmez.\n\n- GetX büyük bir ekosistemdir. Geniş bir topluluk, çok sayıda destekçi içerir ve Flutter var olduğu sürece bu korunacaktır. GetX, tek bir kod ile Android, iOS, Web, Mac, Linux, Windows veya kendi server'ınız (sunucunuz) üzerinde çalışmaya elverişlidir.\n  **[Get Server](https://github.com/jonataslaw/get_server) ile frontend üzerinde yaptığınız kodu backend üzerinde tamamen yeniden kullanmanız mümkün**.\n\n**Ek olarak, tüm geliştirme süreci hem server'da hem de frontend'de [Get CLI](https://github.com/jonataslaw/get_cli) ile tamamen otomatikleştirilebilir**.\n\n**Ayrıca üretkenliğinizi arttırmak için \n[VSCode eklentileri](https://marketplace.visualstudio.com/items?itemName=get-snippets.get-snippets) ve the [Android Studio/Intellij eklentileri](https://plugins.jetbrains.com/plugin/14975-getx-snippets) vardır.**\n\n# Kurulum\n\npubspec.yaml dosyasına Get’i ekleyin:\n\n```yaml\ndependencies:\n  get:\n```\n\nGet’i kullanılacak sayfaya import ediyoruz:\n\n```dart\nimport 'package:get/get.dart';\n```\n\n# GetX ile Sayaç Uygulaması\n\n“Sayaç” projesi yeni bir Flutter projesi oluştururken varsayılan olarak gelir. Yorum satırları ile birlikte toplam 100 satır içerir. Get’in gücünü göstermek gerekirse, size bir “sayaç” uygulamasının her bir tıklamada durumunu değiştirip, sayfalar arasında hareket edip ve bunu yaparken state'leri (durumları) aktarıp aynı zamanda organize bir yol izleyerek business logic'i view'dan ayıracağız ve bu YORUM SATIRLARI DAHİL SADECE 26 SATIR İÇERECEK.\n\n- 1.Adım:\n  “Get”’i MaterialApp’den önce  GetMaterialApp'e dönüştürerek ekliyoruz.\n\n```dart\nvoid main() => runApp(GetMaterialApp(home: Home()));\n```\n\n- Not: Bu kullanım Flutter’ın sağladığı MaterialApp’i modifiye etmez. Sadece child'ı (çocuğu) MaterialApp olan ve bir öncesinde konfigüre edilmiş bir widget’tır. Kendiniz de manuel olarak konfigüre edebilirsiniz fakat buna gerek yoktur. GetMaterialApp, route’ları oluşturacak ve içine bunları, translation’ları ve route navigation için ihtiyacınız olabilecek olan her şeyi inject edecektir. Eğer Get’i sadece state management ya da dependency management olarak kullanmak isterseniz, GetMaterialApp kullanmanıza gerek yoktur. Bu yapı routes, snackbars, internationalization, bottomSheets, dialogs, ve route'lara bağlı high-level apis kullanımlarında ek olarak da context'in yokluğundaki durumlarda kullanılmalıdır.\n- Not²: Bu adım sadece route management kullanıldığında gereklidir (`Get.to()`, `Get.back()` ve bunlar gibi). Kullanmayacaksanız 1. adımı yapmanıza gerek yoktur.\n\n- 2.Adım:\n  İş mantıklarını içeren sınıfı oluşturup içine tüm değişkenleri metodları ve controller'ları ekleyin.İstediğiniz herhangi bir değişkeni \".obs\" ile gözlemlenebilir yapabilirsiniz.\n\n```dart\nclass Controller extends GetxController{\n  var count = 0.obs;\n  increment() => count++;\n}\n```\n\n- 3.Adım:\n  View'ı oluşturun ve içine StatelessWidget (bu RAM'den tasarruf sağlar) yerleştirin. Get sayesinde StatefulWidget kullanmanıza gerek yoktur.\n\n```dart\nclass Home extends StatelessWidget {\n\n  @override\n  Widget build(context) {\n\n    // Sınıfınızın nesnesini getirmek için Get.put() kullanılır. Bu içindeki tüm \"child\" route'ları görüntülenebilir yapar.\n    final Controller c = Get.put(Controller());\n\n    return Scaffold(\n      // Sayaç her değiştiğinde Text() içindeki değerin güncellenmesi için Obx(()=> kullanılır\n      appBar: AppBar(title: Obx(() => Text(\"Clicks: ${c.count}\"))),\n\n      // Navigator.push içeren 8 satırı basit bir şekilde Get.to() ile değiştirin. Bunda context'e ihtiyacınız kalmamaktadır.\n      body: Center(child: ElevatedButton(\n              child: Text(\"Go to Other\"), onPressed: () => Get.to(Other()))),\n      floatingActionButton:\n          FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment));\n  }\n}\n\nclass Other extends StatelessWidget {\n  // Önceki sayfada zaten kulllandığımız  Controller'ı, Get'de \"find\" diyerek getirmesinini istiyoruz.\n  final Controller c = Get.find();\n\n  @override\n  Widget build(context){\n     // Güncellenen sayaç değişkenine erişiyoruz.\n     return Scaffold(body: Center(child: Text(\"${c.count}\")));\n  }\n}\n```\n\nSonuç:\n\n![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/counter-app-gif.gif)\n\nBu basit bir proje ama Get'in ne kadar güçlü olduğunu zaten açıkça ortaya koyuyor. Projeniz büyüdükçe bu gücü daha iyi anlacaksınız.\n\nGet, ekiplerle çalışmak üzere tasarlanmıştır. Ayrıca bireysel geliştiricinin de işini oldukça kolaylaştırır.\n\nPerformanstan ödün vermeden her şeyi zamanında teslim etmenize yardımcı olur. Get tam olarak sana layık!\n\n# Üç Temel Kavram\n\n## State management (Durum Yönetimi)\n\nGet iki farklı state manager içerir: simple state manager (GetBuilder da denilir) ve reactive state manager (GetX/Obx)\n\n### Reactive State Manager (Reaktif Durum Yönetimi)\n\nReaktif programlama, birçok kişi tarafından karmaşık olduğu söylendiği için kafa karışıklığına yol açabilir. Ancak GetX, reaktif programlamayı oldukça basit bir hale dönüştürür:\n\n- StreamController'ları oluşturmanıza ihtiyacınız yoktur.\n- Her bir değişken için StreamBuilder oluşturmanıza gerekmez.\n-  Her state için sınıf oluşturmanıza gerek yoktur.\n- Başlangıç değerleri için get metodu oluşturmaya ihtiyaç olmaz.\n- Code generators kullanmanız gerekmez.\n\nGet, reaktif programlamayı setState kullanmak kadar kolay yapmaktadır.\n\nBir isim değişkeniniz olduğunu ve onu her değiştirdiğinizde, onu kullanan tüm widget'ların otomatik olarak güncellendiğini düşünün.\n\nBu sizin sayaç değişkeniniz:\n\n```dart\nvar name = 'Jonatas Borges';\n```\n\nGözlemlenebilir yapmak için \".obs\" ekliyorsunuz ve bu şekli alıyor:\n\n```dart\nvar name = 'Jonatas Borges'.obs;\n```\n\nUI'da (kullanıcı arayüzünde) bu değeri göstermek ve değerler değiştiğinde ekranı güncellemek istediğinizde, hemen şunu yapın:\n\n```dart\nObx(() => Text(\"${controller.name}\"));\n```\n\nHepsi bu. İşte _bu kadar_ basit.\n\n### State Management Hakkında Daha Fazla Bilgi\n\n**State Management'ın daha ayrıntılı bir açıklamasına [buradan](./documentation/en_US/state_management.md) erişebilirsiniz. Orada daha fazla örnek ile simple state manager ve reactive state manager arasındaki farkı görebilirsiniz**\n\nGetX'in gücü hakkında daha iyi bir fikir edineceksiniz.\n\n## Route Management (Rota Yönetimi)\n\nEğer routes/snackbars/dialogs/bottomsheets yapılarını context'e ihtiyaç duymadan kullanmak istedğinizde, GetX bunun için biçilmiş kaftan.\n\nMaterialApp'i GetMaterialApp ile değiştiriyoruz.\n\n```dart\nGetMaterialApp( // Önceki hal: MaterialApp(\n  home: MyHome(),\n)\n```\n\nYeni ekrana geçmek için:\n\n```dart\n\nGet.to(NextScreen());\n```\n\nName (isim) ile yeni sayfaya geçiş yapılabilir. Named routes (İsimli rotalar) hakkında daha çok bilgiye [buradan](./documentation/tr_TR/route_management.md#navigation-with-named-routes) ulaşabilirsiniz.\n\n```dart\n\nGet.toNamed('/details');\n```\n\nSnackbars, dialogs, bottomsheets ve normalde Navigator.pop(context) ile kapatacağınız herhangi bir şeyi kapatmak için;\n\n```dart\nGet.back();\n```\n\nÖnceki ekrana geri dönme seçeneğinin olmadan bir sonraki ekrana gitmek için (örnek olarak SplashScreens, login screens, vs.)\n\n```dart\nGet.off(NextScreen());\n```\n\nSonraki ekrana gitmek ve önceki tüm route'ları kapatmak için shopping carts, polls, ve test'lerde kullanılır)\n\n```dart\nGet.offAll(NextScreen());\n```\n\nBunlardan herhangi birini yapmak için context kullanmanız gerekmediğini fark ettiniz mi? Get route management'ı kullanmanın en büyük avantajlarından biri de budur. Böylelikle controller sınıfınızda olan tüm metodları endişe olmadan çalıştırabilirsiniz.\n\n### Route Management Hakkında Daha Fazla Bilgi\n\n**Get, named routes ile çalışırken route'lar arası geçişleri kolayca kontrol etmenizi sağlar. Daha ayrıntılı doküman için [buraya](./documentation/tr_TR/route_management.md) tıklayabilirsiniz.**\n\n## Dependency Management (Bağımlılık Yönetimi)\n\nGet basit ve güçlü bir dependency manager içerir. Sadece tek satır kod ile Bloc ya da Controller'ınızın aynı sınıf nesnesini getirmenizi sağlar. Ayrıca Provider context, ya da inheritedWidget kullanmanıza gerek kalmaz:\n\n```dart\nController controller = Get.put(Controller()); // Controller controller = Controller(); yazmak yerine\n```\n\n- Not: Get'in State Manager'ını kullanıyorsanız, API bağlamaya daha çok dikkat edin ki onlar view'ı controller'a kolayca bağlamanızı sağlayacaktır.\n\nKullanacağınız sınıfın içinde başka bir sınıfın nesnesini oluşturmak yerine, Get instance sayesinde uygulamanızın her yerinde aynı sınıf nesnesini kullanabilir hale getirebilirsiniz.\nBöylelikle controller (ya da Bloc sınıfını) normal bir şekilde kullanabilirsiniz.\n\n**İpucu:** Get dependency management, kütüphanenin diğer parçalarından ayrıdır. Örnek olarak eğer uygulamanızda hali hazırda state manager kullanıyorsanız (hangisi olduğu fark etmez), en baştan yazmaya gerek yoktur. Bu dependency injection'ı problem olmadan kullanabilirsiniz.\n\n```dart\ncontroller.fetchApi();\n```\n\nFarzedin ki çok fazla sayıda route'larınız ve controller'larınızda erişmeniz gereken data'lar olsun, state manager'ı Provider ya da Get_it gibi kütüphaneler ile bağlamanız gerekmekedir. Get kullanarak bunları bağlamaya ihtiyacınız kalmaz. Get'e sadece \"find\" diyerek controller'ınızı bulmasını istemeniz yeterlidir. Fazladan dependency'lere ihtiyacınız yoktur:\n\n```dart\nController controller = Get.find();\n// Evet, inanılmaz değil mi? Get, controller'ınızı bulup getirecek. Get, milyonlarca controller tanımlanmış da olsa size her zaman doğrusunu getirecektir.\n```\n\nSonrasında üstte alınan controller'daki verilerinizi kullanabileceksiniz:\n\n```dart\nText(controller.textFromApi);\n```\n\n### Dependency Management Hakkında Daha Fazla Bilgi\n\n**Dependency management'a daha derinden bakmak için [buraya](./documentation/tr_TR/dependency_management.md) tıklayabilirsiniz**\n\n# Utils\n\n## Internationalization (Uluslararasılaştırma)\n\n### Translations (Çeviriler)\n\nTranslations, map halinde basit key-value değerleri tutar.\nÖzel translation'larınızı eklemek için bir sınıf oluşturup `Translations`sınıfını extend edebilirsiniz.\n\n```dart\nimport 'package:get/get.dart';\n\nclass Messages extends Translations {\n  @override\n  Map<String, Map<String, String>> get keys => {\n        'en_US': {\n          'hello': 'Hello World',\n        },\n        'de_DE': {\n          'hello': 'Hallo Welt',\n        }\n      };\n}\n```\n\n#### Translations kullanımı\n\nÖnecen belirlenmiş key'e sadece `.tr` eklenince `Get.locale` ve `Get.fallbackLocale` şimdiki değerleri kullanarak otomatik çeviriyi yapacaktır.\n\n\n```dart\nText('title'.tr);\n```\n\n#### Tekil ve çoğul çevirisi yapımı\n\n```dart\nvar products = [];\nText('singularKey'.trPlural('pluralKey', products.length, Args));\n```\n\n#### Parametreler ile çeviri yapımı\n\n```dart\nimport 'package:get/get.dart';\n\n\nMap<String, Map<String, String>> get keys => {\n    'en_US': {\n        'logged_in': 'logged in as @name with email @email',\n    },\n    'es_ES': {\n       'logged_in': 'iniciado sesión como @name con e-mail @email',\n    }\n};\n\nText('logged_in'.trParams({\n  'name': 'Jhon',\n  'email': 'jhon@example.com'\n  }));\n```\n\n### Locales (Yerel Ayarlar)\n\nLocale ve translation'lar`GetMaterialApp`'in parametreleri içinde atanabilir.\n\n```dart\nreturn GetMaterialApp(\n    translations: Messages(), //Çevirileriniz\n    locale: Locale('en', 'US'), //Çeviriler bu locale dilinde gösterilecek\n    fallbackLocale: Locale('en', 'UK'), // Eğer yanlış bir locale olması durumunda gösterilecek fallback locale\n);\n```\n\n#### Locale değiştirme\n\n`Get.updateLocale(locale)` çağrılarak locale güncellenebilir. Çeviriler otomatik olarak yeni locale dilinde olacaktır.\n\n```dart\nvar locale = Locale('en', 'US');\nGet.updateLocale(locale);\n```\n\n#### System locale (Yerel Sistem Ayarları)\n\nSistem locale'i okumak için `Get.deviceLocale` kullanılır.\n\n```dart\nreturn GetMaterialApp(\n    locale: Get.deviceLocale,\n);\n```\n\n## Tema Değiştirme\n\nGüncellemek için`GetMaterialApp`'in üstüne bir widget koymayın. Bu, kopya key'ler oluşmasını tetikler. Birçok kişi tema değiştirmek için tarih öncesi bir yöntem olan \"ThemeProvider\" widget'ı oluşturmayı tercih eder. **GetX™** ile buna HİÇ gerek duyulmaz.\n\n`Get.changeTheme`ile kendi oluşturduğunuz temanızı hızlı bir şekilde ekleyebilirsiniz:\n\n```dart\nGet.changeTheme(ThemeData.light());\n```\n\n`onTap`'de Temayı değiştiren bir buton oluşturmak istiyorsanız, bunun için iki **GetX™** API'sini birleştirebilirsiniz:\n\n- API, karanlık `Theme`'in kullanıp kullanılmadığını kontrol eder.\n- `Theme` Change API'yi `onPressed`içine koyabilirsiniz:\n\n```dart\nGet.changeTheme(Get.isDarkMode? ThemeData.light(): ThemeData.dark());\n```\n\n`.darkmode` aktif hale geldiğinde, tıklandığında _light theme_ 'e döner, _light theme_ aktif olduğunda,  _dark theme_'e geçer.\n\n## GetConnect\n\nGetConnect backend ile frontend'in http ya da websockets ile kolayca iletişime geçmesini sağlar.\n\n### Varsayılan Ayarlar\n\nSadece GetConnect'den extend ederek gelen GET/POST/PUT/DELETE/SOCKET metodlarını kullanarak Rest API ya da websockets ile kolayca iletişim kurabilirsiniz.\n\n```dart\nclass UserProvider extends GetConnect {\n  // Get request\n  Future<Response> getUser(int id) => get('http://youapi/users/$id');\n  // Post request\n  Future<Response> postUser(Map data) => post('http://youapi/users', body: data);\n  // File  ile Post request\n  Future<Response<CasesModel>> postCases(List<int> image) {\n    final form = FormData({\n      'file': MultipartFile(image, filename: 'avatar.png'),\n      'otherFile': MultipartFile(image, filename: 'cover.png'),\n    });\n    return post('http://youapi/users/upload', form);\n  }\n\n  GetSocket userMessages() {\n    return socket('https://yourapi/users/socket');\n  }\n}\n```\n\n### Özel Ayarlamalar\n\nGetConnect oldukça düzenlenebilir. Kendi base Url'nizi tanımlayabilir, cevapları ve Request'leri düzenleyebilirsiniz. Authenticator oluşturup kendiliğinden authenticate olmasını sağlayabilirsiniz. Size verilen standart decoder ile tüm request'leri ek bir ayar olmadan modellerinize aktarabilirsiniz.\n\n```dart\nclass HomeProvider extends GetConnect {\n  @override\n  void onInit() {\n    // Tüm request'ler jsonEncode'a gider: CasesModel.fromJson()\n    httpClient.defaultDecoder = CasesModel.fromJson;\n    httpClient.baseUrl = 'https://api.covid19api.com';\n    // baseUrl = 'https://api.covid19api.com'; //baseUrl'yi bu şekilde tanımlar\n    // Http ve websockets kullanılmış ise [httpClient] instance'ına ihtiyaç yoktur.\n\n\n    // Gelen tüm request'ler \"apikey\"'in header özelliğine gier.\n    httpClient.addRequestModifier((request) {\n      request.headers['apikey'] = '12345678';\n      return request;\n    });\n\n    // Eğer sunucu \"Brazilya\"'dan bir veri gönderse bile\n    // response'dan veriyi kaldırdığın için kullanıcılar göremez.\n    // response önceden getirişmiş olsa bile \n    httpClient.addResponseModifier<CasesModel>((request, response) {\n      CasesModel model = response.body;\n      if (model.countries.contains('Brazil')) {\n        model.countries.remove('Brazilll');\n      }\n    });\n\n    httpClient.addAuthenticator((request) async {\n      final response = await get(\"http://yourapi/token\");\n      final token = response.body['token'];\n      // header veriliyor\n      request.headers['Authorization'] = \"$token\";\n      return request;\n    });\n\n    // HttpStatus, HttpStatus.unauthorized ise \n    // Autenticator 3 defa çağırılır.\n    httpClient.maxAuthRetries = 3;\n  }\n  }\n\n  @override\n  Future<Response<CasesModel>> getCases(String path) => get(path);\n}\n```\n\n## GetPage Middleware\n\nGetPage'in GetMiddleWare listesi oluşturan ve bunları özel bir sırada çalıştıran bir özelliği vardır.\n\n**Not**: GetPage, Middlewares içeriyor ise bu sayfanın tüm çocukları da aynı middlewares'i otomatik olarak içerir.\n\n### Priority (Öncelik)\n\nMiddlewares'in sıralı çalışması için GetMiddleware'lerin priority'leri (öncelikleri) düzenlenmelidir.\n\n```dart\nfinal middlewares = [\n  GetMiddleware(priority: 2),\n  GetMiddleware(priority: 5),\n  GetMiddleware(priority: 4),\n  GetMiddleware(priority: -8),\n];\n```\n\nMiddleware'ler bu sırada çalışacaktır:   **-8 => 2 => 4 => 5**\n\n### Redirect (Yönlendirme)\n\n Çağrılan route'un sayfası arandığında, fonsyon çağırılmış olacaktır. Redirect için RouteSettings kullanılır. Name değeri null verilebilir ve bu olduğu zaman herhangi bir redirect olmayacaktır.\n\n```dart\nRouteSettings redirect(String route) {\n  final authService = Get.find<AuthService>();\n  return authService.authed.value ? null : RouteSettings(name: '/login')\n}\n```\n\n### onPageCalled\n\nBu fonsyon, herhangi bir şey oluşmadan önce sayfa çağırılmak istenildiğinde kullanılır. Sayfada bir şey değiştirmek için ya da yeni bir sayfa vermek için kullanabilirsiniz.\n\n```dart\nGetPage onPageCalled(GetPage page) {\n  final authService = Get.find<AuthService>();\n  return page.copyWith(title: 'Welcome ${authService.UserName}');\n}\n```\n\n### OnBindingsStart\n\nBu fonsyon Bindings başlatılmadan hemen önce çalışır.\nBu sayfa için Bindings'i şu şekilde değiştirebilirsiniz.\n\n```dart\nList<Bindings> onBindingsStart(List<Bindings> bindings) {\n  final authService = Get.find<AuthService>();\n  if (authService.isAdmin) {\n    bindings.add(AdminBinding());\n  }\n  return bindings;\n}\n```\n\n### OnPageBuildStart\n\nBu fonsyon Bindings başlatıldıktan hemen sonra çalışır.\nBindings oluşturulduktan hemen sonra ve widget sayfası oluşturulmadan önce kullanabilirsiniz.\n\n```dart\nGetPageBuilder onPageBuildStart(GetPageBuilder page) {\n  print('bindings are ready');\n  return page;\n}\n```\n\n### OnPageBuilt\n\nBu fonskyon GetPage.page fonskyonu çağrıldıktan hemen sonra çalışır ve fonksyonun sonucunu verir. Sonrasında gösterilecek widget'ı alır.\n\n### OnPageDispose\n\nBu fonsyon sayfadaki ilgili tüm objelerin (Controllers, views, ...) dispose olmasından hemen sonra çalışır.\n\n## Advanced APIs (Gelişmiş API'ler)\n\n```dart\n// currentScreen'deki arg'ı verir\nGet.arguments\n\n// Önceki route'un name'ini verir.\nGet.previousRoute\n\n// Erişmek için raw route'u verir. Örnek olarak: rawRoute.isFirst()\nGet.rawRoute\n\n// GetObserver'dan Routing API'ye erişim verir.\nGet.routing\n\n// Snackbar açık mı kontrolü yaplır.\nGet.isSnackbarOpen\n\n// Dialog açık mı kontrolü yaplır.\nGet.isDialogOpen\n\n// Bottomsheet açık mı kontrolü yaplır.\nGet.isBottomSheetOpen\n\n// Tek route kaldırılır.\nGet.removeRoute()\n\n// predicate, true döndürene kadar terarlanarak geri gelir.\nGet.until()\n\n// Yeni route a gider ve eski tüm route'ları, predicate, true döndürene kadar kaldırır.\nGet.offUntil()\n\n// named route'a gider ve eski tüm route'ları, predicate, true döndürene kadar kaldırır.\nGet.offNamedUntil()\n\n//Hangi platformda çalıştığı kontrol edilir.\nGetPlatform.isAndroid\nGetPlatform.isIOS\nGetPlatform.isMacOS\nGetPlatform.isWindows\nGetPlatform.isLinux\nGetPlatform.isFuchsia\n\n//Cihaz türü kontrol edilir.\nGetPlatform.isMobile\nGetPlatform.isDesktop\n//Web'de tüm platformlar bağımsız olarak desteklenir!\n//Bir tarayıcının içinde çalışıp çalışmadığınızı anlayabilirsiniz\n//Windows, iOS, OSX, Android, vs. gibi\nGetPlatform.isWeb\n\n\n// Aşağıdakine eşittir : MediaQuery.of(context).size.height,\n// fakat immutable'dır (sabittir).\nGet.height\nGet.width\n\n// Navigator'e şimdiki context'i verir.\nGet.context\n\n// Önde olan snackbar/dialog/bottomsheet'a nerede olursanız olun context'i verir. \nGet.contextOverlay\n\n// Not: aşağıdaki metodlar context üzerine olan extension'lardır.\n// UI'ın herhangi bir yerinde context'e erişebilirsiniz ve istediğiniz yerde kullanabilirsiniz.\n\n// Eğer değişken bir height/width verileri varsa (örnek olarak Masaüstü ya da tarayıcı gibi ölçeği değişebilen pencereler) context'i kullanmaya ihtiyacınız vardır.\ncontext.width\ncontext.height\n\n// Size ekranın yarısını, üçte birini vb. tanımlamayı sağlar.\n// Responsive uygulamalar için kullanışlıdır.\n// param dividedBy (double) optional - default: 1\n// param reducedBy (double) optional - default: 0\ncontext.heightTransformer()\ncontext.widthTransformer()\n\n/// MediaQuery.of(context).size'a benzer\ncontext.mediaQuerySize()\n\n/// MediaQuery.of(context).padding'e benzer\ncontext.mediaQueryPadding()\n\n/// MediaQuery.of(context).viewPadding'e benzer\ncontext.mediaQueryViewPadding()\n\n/// MediaQuery.of(context).viewInsets;'e benzer\ncontext.mediaQueryViewInsets()\n\n/// MediaQuery.of(context).orientation;'a benzer\ncontext.orientation()\n\n/// Cihazın yatay modda olup olmadığını kontrol eder.\ncontext.isLandscape()\n\n/// Cihazın dikey modda olup olmadığını kontrol eder.\ncontext.isPortrait()\n\n/// MediaQuery.of(context).devicePixelRatio;'ya benzer\ncontext.devicePixelRatio()\n\n/// MediaQuery.of(context).textScaleFactor;'e benzer\ncontext.textScaleFactor()\n\n/// Ekranın en kısa kenarını getirir\ncontext.mediaQueryShortestSide()\n\n/// width 800'den büyük ise true döndürür.\ncontext.showNavbar()\n\n/// Kısa kenar 600p'den küçük ise true döndürür.\ncontext.isPhone()\n\n/// Kısa kenar 600p'den büyük ise true döndürür.\ncontext.isSmallTablet()\n\n/// Kısa kenar 720p'den büyük ise true döndürür.\ncontext.isLargeTablet()\n\n/// Cihaz tablet ise true döndürür.\ncontext.isTablet()\n\n/// Ekran boyutuna göre <T> değerini döndürür\n/// için değer verebilir:\n/// watch: Kısa kenar 300'den küçük ise\n/// mobile: Kısa kenar 600'den küçük ise\n/// tablet: Kısa kenar 1200'den küçük ise\n/// desktop: width 1200'den büyük ise\n\ncontext.responsiveValue<T>()\n```\n\n### Opsiyonel Genel Ayarlar ve Manuel Ayarlamalar\n\nGetMaterialApp çoğu şeyi sizin için otomatik olarak ayarlar, ayrıca kendiniz de isterseniz Get'i manuel olarak ayarlayabilirsiniz.\n\n```dart\nMaterialApp(\n  navigatorKey: Get.key,\n  navigatorObservers: [GetObserver()],\n);\n```\n\n`GetObserver` içinde kendi Middleware'ınızı kullanabilirsiniz ve bu hiçbir şeyi etkilemez.\n\n```dart\nMaterialApp(\n  navigatorKey: Get.key,\n  navigatorObservers: [\n    GetObserver(MiddleWare.observer) // Burası\n  ],\n);\n```\n\n`Get` için _Global Settings_ oluşturabilirsiniz. Herhangi bir route'a push yapmadan önce kodunuza `Get.config` eklemeniz yeterli. \nYa da doğrudan  `GetMaterialApp` içinde tanımlayabilirsiniz.\n\n```dart\nGetMaterialApp(\n  enableLog: true,\n  defaultTransition: Transition.fade,\n  opaqueRoute: Get.isOpaqueRouteDefault,\n  popGesture: Get.isPopGestureEnable,\n  transitionDuration: Get.defaultDurationTransition,\n  defaultGlobalState: Get.defaultGlobalState,\n);\n\nGet.config(\n  enableLog = true,\n  defaultPopGesture = true,\n  defaultTransition = Transitions.cupertino\n)\n```\n\nİsteğe bağlı olarak tüm logging mesajlarını `Get` üzerinden yönlendirebilirsiniz. \nKendi istediğiniz logging paketinizi kullanmak \nve oradaki log'ları yakalamak istiyorsanız:\n\n```dart\nGetMaterialApp(\n  enableLog: true,\n  logWriterCallback: localLogWriter,\n);\n\nvoid localLogWriter(String text, {bool isError = false}) {\n  // istediğiniz logging paketine mesajı aktarır\n  // eğer, enableLog: false ise log mesajları bu callback içine gönderilir\n  // GetConfig.isLogEnable aracılığıyla isterseniz kontrol edebilirsiniz\n}\n\n```\n\n### Local State Widgets (Yerel Durum Widgetları)\n\nBu widget'lar tek bir değeri kontrol etmenize ve durumu geçici ya da yerel olarak tutmanızı sağlar.\nReactive ve simple olan yapılar içerir.\nÖrneğin bunları `TextField` içindeki obscureText parametresine bağlayabilirsiniz. İsterseniz kendinizinkini (Expandable Panel vs.) de oluşturabilirsiniz ya da `Scaffold`'daki body'nin içeriği değişirken `BottomNavigationBar` içindeki current index'i değiştirebilirsiniz.\n\n#### ValueBuilder\n\nVeri güncellemenin bir yolu olan  `StatefulWidget`'daki  `.setState` yapısının basitleştirilmiş halidir.\n\n```dart\nValueBuilder<bool>(\n  initialValue: false,\n  builder: (value, updateFn) => Switch(\n    value: value,\n    onChanged: updateFn, // tamamen aynısı! ( newValue ) => updateFn( newValue ) yapısını da kullanabilirsiniz\n  ),\n  // eğer builder metodu dışından bir çağırma işlemi yapılacak ise\n  onUpdate: (value) => print(\"Value updated: $value\"),\n  onDispose: () => print(\"Widget unmounted\"),\n),\n```\n\n#### ObxValue\n\n[`ValueBuilder`](#valuebuilder)'a oldukça benzer olmasının yanında bu Reactive halidir. Rx nesnesine aktarabilir ( .obs yapısını hatıladınız mı?) ve otomatik olarak güncellenmensini sağlayabilirsiniz, resmen muhteşem değil mi ?  \n\n```dart\nObxValue((data) => Switch(\n        value: data.value,\n        onChanged: data, // Rx, çağrılabilen fonsyon içerir. (flag) => data.value = flag şeklinde kullanılablir.\n    ),\n    false.obs,\n),\n```\n\n## Faydalı Ipuçları\n\n`.obs` yapıları olan gözlemlenebilirler ( _Rx_ tipleri olarak da bilinirler) oldukça çeşitli internal metodlara ve operatörlere sahiptirler.\n\n>  `.obs` yapısının gerçek değer olduğunu düşünenler oldukça yaygındır fakat bu yanlış bir düşüncedir.\n> Değişkenleri, Type declaration yapmaktan kaçınmalıyız. Çünkü Dart'ın derleyicisi zaten bunu anlayacak kadar zekidir.\n> Kodunuzu daha temiz gösterir fakat:\n\n```dart\nvar message = 'Hello world'.obs;\nprint( 'Message \"$message\" has Type ${message.runtimeType}');\n```\n\n`message`, gerçek String Type değerini yazdırsa bile aslında bu bir **RxString** Type değeridir!\n\nYani `message.substring( 0, 4 )` şeklinde kullanmazsınız.\n _observable_ içindeki gerçek `value`'ya (değere) erişmelisiniz.\nEn çok \"kullanılan yol\"  `.value` yapısı ile erişmektir fakat şu şekilde kullanabileceğiniz bir yol daha var...\n\n\n```dart\nfinal name = 'GetX'.obs;\n// eğer değer şimdikinden farklı ise, sadece stream'i \"günceller\"\nname.value = 'Hey';\n\n// Tüm Rx özellikleri \"çağrılabilir\" ve geriye yeni bir değer döndürür.\n// Fakat bu yaklaşım `null` değerleri kabul etmez, sonucunda UI rebuild (tekrardan oluşturulmaz) edilmez.\nname('Hello');\n\n// getter yapmak gibi, 'Hello'yazdırır.\n\nname() ;\n\n/// numbers:\n\nfinal count = 0.obs;\n\n// Tüm non mutable (değişken olmayan) işlemleri num primitives üzerinden yapabilirsiniz.\ncount + 1;\n\n// Dikkat edin! Bu sadece `count` değerinin 'final' olmayıp 'var' olduğu değerlerde mümkündür.\ncount += 1;\n\n// Ayrıca değerleri kıyaslayabilirsiniz:\ncount > 2;\n\n/// booleans:\n\nfinal flag = false.obs;\n\n// değer true/false arasında değişir.\nflag.toggle();\n\n\n/// tüm tipler için:\n\n// \"value\"'ları null'a çevirir.\nflag.nil();\n\n// Tüm toString(), toJson() işlemleri `value`'ya aktarılır.\nprint( count ); // RxInt içinden `toString()` çağrılır.\n\nfinal abc = [0,1,2].obs;\n// Değeri bir json Array (dizi) yapısına çevirir ve RxList şeklinde yazdırır.\n// Json tüm Rx tipleri tarafından desteklenir.\nprint('json: ${jsonEncode(abc)}, type: ${abc.runtimeType}');\n\n// RxMap, RxList ve RxSet kendi native tiplerinden extend edilen özel Rx tipleridir.\n// Fakat List ile çalışmak normal listelerle çalışmak gibidir. Reaktiv olmasına rağmen.\nabc.add(12); // '12' listeye eklenir ve stream GÜNCELLENİR.\nabc[3]; // List'deki gibi 3. index okunur.\n\n\n// Rx ve value ile çalışmak aynıdır fakat hashCode her zaman value'dan alınır.\nfinal number = 12.obs;\nprint( number == 12 ); // çıktı: true\n\n/// Özel Rx Modelleri:\n\n\n// toJson(), toString() child'a gönderilir. Böylelikle override'ları onlara implement edebilirsiniz ve doğrudan gözlemlenebiliri print() edebilirsiniz.\n\nclass User {\n    String name, last;\n    int age;\n    User({this.name, this.last, this.age});\n\n    @override\n    String toString() => '$name $last, $age years old';\n}\n\nfinal user = User(name: 'John', last: 'Doe', age: 33).obs;\n\n// `user`,\"reactive\" yapıdadır. Fakat içinde özellikleri DEĞİLDİR.\n// Yani eğer içindeki bazı değerleri değiştirirsek\nuser.value.name = 'Roi';\n//widget, rebuild olmayacaktır!,\n//`Rx`, user içindeki bir şeyi değiştirdiğinizde, bundan haberi olmayacaktır.\n// Özel sınıflar oluşturmak için, manuel olarak değişiklikleri \"notify\" etmeliyiz.\nuser.refresh();\n\n// Ya da `update()` metodunu kullanabiliriz\nuser.update((value){\n  value.name='Roi';\n});\n\nprint( user );\n```\n## StateMixin\n\n`UI` state ile başa çıkmanın başka bir yolu da `StateMixin<T>`  kullanmaktır.\nBunu implement yapmak için, controller'ınıza  `with` kullanarak yanına `StateMixin<T>` eklemekle olur.\nBu sizin T modelini kullanmanızı sağlar.\n\n\n``` dart\nclass Controller extends GetController with StateMixin<User>{}\n```\n\n`change()` metodu istediğiniz yerde State'i değiştirmemizi sağlar.\nVeri(data) ve durum(status) aktarmak için kullanılan yol:\n\n```dart\nchange(data, status: RxStatus.success());\n```\n\nRxStatus şu durumları kullanmanızı sağlar:\n\n``` dart\nRxStatus.loading();\nRxStatus.success();\nRxStatus.empty();\nRxStatus.error('message');\n```\n\nUI'ın içinde temsil edilmesi için şu şekilde kullanılır:\n\n```dart\nclass OtherClass extends GetView<Controller> {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n\n      body: controller.obx(\n        (state)=>Text(state.name),\n        \n        // Kendi yüklenme göstergenizi (loading indicator) buraya eklebilirsiniz\n        // hali hazırda gelen yapı şudur: Center(child:CircularProgressIndicator())\n        onLoading: CustomLoadingIndicator(),\n        onEmpty: Text('No data found'),\n\n        // Keni hata widget'ınızı buraya yazabilirsiniz\n        // hali hazırda gelen yapı şudur: Center(child:Text(error))\n        onError: (error)=>Text(error),\n      ),\n    );\n}\n```\n\n#### GetView\n\nBu widget'ı çok seviyorum, oldukça basit ve çok kullanışlı!\n\n`const Stateless` Widget, `Controller`'ı tanımlamak için `controller` özelliği içerir. \n\n```dart\n class AwesomeController extends GetController {\n   final String title = 'My Awesome View';\n }\n\n  // controller'ınızı register etmek için bunu kullandığınız `Type`'a geçirmeyi asla unutmayın.\n class AwesomeView extends GetView<AwesomeController> {\n   @override\n   Widget build(BuildContext context) {\n     return Container(\n       padding: EdgeInsets.all(20),\n       child: Text(controller.title), // sadece `controller.something` deyin\n     );\n   }\n }\n```\n\n#### GetResponsiveView\n\nResponsive view oluşturmak için bu widget'tan extend edilir.\nBu widget ekran size ve type hakkında bilgiler içeren  \n`screen` özelliğini taşır.\n\n##### Nasıl kullanılır?\n\nbuild yapmanız için 2 yönteminiz vardır.\n\n- build yapmak için `builder` metodu ile widget döndürmek\n- `desktop`, `tablet`,`phone`, `watch`  metodları ile \n  bu özel metodlar ekran türü bu metodlarla eşitlendiiği zaman build metodunu tetikler.\n  Mesela ekran [ScreenType.Tablet] ise `tablet` metodu çalışrıtılacaktır.\n  **Not:** Eğer bu metodu kullanırsanız, lütfen  `alwaysUseBuilder` özelliğini `false` olarak işaretleyin.\n\n`settings` özelliği sayesinde ekranın türüne göre genişlik limiti koyabilirsiniz.\n\n![örnek](https://github.com/SchabanBo/get_page_example/blob/master/docs/Example.gif?raw=true)\nBu ekranın kodları\n[burada](https://github.com/SchabanBo/get_page_example/blob/master/lib/pages/responsive_example/responsive_view.dart)\n\n#### GetWidget\n\nÇoğu kişinin widget'lar hakkında hiçbir fikri yok ya da kullanırken inanılmaz kafası karışıyor.\nBu kullanım oldukça nadir fakat özel: Controller `caches`'leme işlemi _cache_ yüzünden asla bir  `const Stateless` oluşamaz.\n\n> Peki ne zaman Controller'ı \"cache\"'yemeye ihtiyacınız olacak?\n\n\"Çok da yaygın olmayan\" bir **GetX** özelliğini kullanıyorsanız: `Get.create()`.\n\n`Get.create(()=>Controller())` yapısı siz her `Get.find<Controller>()` dediğinizde size yeni bir `Controller` oluşturacak.\n\n`GetWidget`'ın ışığı burada parlıyor. Örnek olarak bir listede \n\nTodo ögelerini tutmak istiyorsanız kullanılır. Eğer widget'ın \"rebuilt\" olursa, yapı yine aynı controller nesnesini tutmaya devam edecektir.\n\n#### GetxService\n\nBu sınıf `GetxController`' bezer. Uygulamanın lifecycle'larını (hayat döngüsü metodlarını) içerir ( `onInit()`, `onReady()`, `onClose()`).\nFakat içinde hiçbir mantıksal yapı bulunmaz. Sadece **GetX**'in Dependency Injection sistemini bilgilendirir. \n\nBunun alt sınıfları, memory (bellekten) hiçbir şekilde **kaldırılamaz**. \n\n\nBu yöntem \"Servislerinizi\" tutmak için oldukça kullanışlıdır. Servisleriniz bu şekilde her zaman ulaşılabilir ve aktif olur.  `Get.find()` metodu buna yeter. Örnek olarak:`ApiService`, `StorageService`, `CacheService`.\n\n\n```dart\nFuture<void> main() async {\n  await initServices(); /// SERVİSLERİN BAŞLATILMASI BEKLENİR\n  runApp(SomeApp());\n}\n\n/// Servislerinizi Flutter uygulaması çalışmadan önce başlatılması oldukça mantıklı bir harekettir.\n/// Uygulama akışını kontrol edebilirsiniz. (belki de birkaç tane Tema düzenlemesi ya da\n/// apiKey, kulllanıcıdan gelen  dil tanımlaması gibi düzenlemeler yapmanız lazımdır...Bu durumna SettingService'i ApiService'den önce çalışması gerekmektedir.\n/// GetMaterialApp() 'in rebuild yapmasına gerek yoktur. Çünkü değerleri doğrudan alır.\nvoid initServices() async {\n  print('starting services ...');\n  /// Burası sizin get_storage, hive, shared_pref gibi yükelemeleri yaptığınız yer.\n  /// ya da daha fazla özellik bağlamak ve ya async yapıları kullanmak için\n  await Get.putAsync(() => DbService().init());\n  await Get.putAsync(SettingsService()).init();\n  print('All services started...');\n}\n\nclass DbService extends GetxService {\n  Future<DbService> init() async {\n    print('$runtimeType delays 2 sec');\n    await 2.delay();\n    print('$runtimeType ready!');\n    return this;\n  }\n}\n\nclass SettingsService extends GetxService {\n  void init() async {\n    print('$runtimeType delays 1 sec');\n    await 1.delay();\n    print('$runtimeType ready!');\n  }\n}\n\n```\n\n`GetxService`'lerini silmenin tek bir yolu vardır o da `Get.reset()`. \nBu yöntem uygulamanıza \"Hot Reboot\" yapmak gibidir. Eğer uygulamanızın hayat süresi boyunca mutlaka kalıcılığı olmasını istediğiniz bir sınıfın nesnesini oluşturmak istediğiniz zaman  `GetxService`'i kullanın.\n\n\n### Testler\n\nController'larınızı lifecycle'ları (hayat döngüleri) dahil olmak üzere diğer sınıflar gibi test edebilirsiniz:\n\n```dart\nclass Controller extends GetxController {\n  @override\n  void onInit() {\n    super.onInit();\n    //Değeri name2 ile değiştirme\n\n    name.value = 'name2';\n  }\n\n  @override\n  void onClose() {\n    name.value = '';\n    super.onClose();\n  }\n\n  final name = 'name1'.obs;\n\n  void changeName() => name.value = 'name3';\n}\n\nvoid main() {\n  test('''\nTest the state of the reactive variable \"name\" across all of its lifecycles''',\n      () {\n    /// Controller'ınızı lifecycle dışında test edebilirsiniz.\n    /// Fakat bunu GetX dependency injection kullanmadığınız taktirde \n    /// kullanmanız önerilmiyor.\n    final controller = Controller();\n    expect(controller.name.value, 'name1');\n\n    /// Eğer kullanıyorsanı istediğiniz her şeyi test edebilirsiniz.\n    /// Her lifecycle sonrası uygulamanızın durumu dahil olmak üzere.\n    Get.put(controller); // onInit çağrıldıktan sonra\n    expect(controller.name.value, 'name2');\n\n    /// Bu fonksoynu test edin\n    controller.changeName();\n    expect(controller.name.value, 'name3');\n\n    /// onClose çağrıldıktan sonra\n    Get.delete<Controller>();\n\n    expect(controller.name.value, '');\n  });\n}\n```\n\n#### Ipuçları\n\n##### Mockito or mocktail\nEğer GetxController/GetxService'inizi mock yapmaya ihtiyacınız varsa GetxController'dan extend etmeniz ve Mock ile mixin'lemelisiniz.\n\n```dart\nclass NotificationServiceMock extends GetxService with Mock implements NotificationService {}\n```\n\n##### Using Get.reset()\nEğer widget'ları ya da widget grupllarını test etmek istiyorsanız, testinizin sonunda Get.reset'i kullanın ya da önceki testinizden kalma tüm ayarları sıfırlayın.\n\n##### Get.testMode \nEğer controller'larınızın içinden navigation kullanmak istiyorsanız. Main'den önce  `Get.testMode = true` şeklinde kullanın.\n\n\n# 2.0 Ile Gelen Büyük Değişiklikler\n\n1- Rx Types :\n\n| Önce    |    Sonra   |\n| ------- | ---------- |\n| StringX | `RxString` |\n| IntX    | `RxInt`    |\n| MapX    | `RxMap`    |\n| ListX   | `RxList`   |\n| NumX    | `RxNum`    |\n| DoubleX | `RxDouble` |\n\nRxController ve GetBuilder şimdi birleştiler. Artık hangi controller'ı kullanmak istediğinizi hatırlamak zorunda değilsiniz. SAdece GetxController diyerek halledin. Bu simple state management ve reactive ile düzgün çalışacaktır.\n\n2- NamedRoutes\n\nÖnce:\n\n```dart\nGetMaterialApp(\n  namedRoutes: {\n    '/': GetRoute(page: Home()),\n  }\n)\n```\n\nŞimdiki:\n\n```dart\nGetMaterialApp(\n  getPages: [\n    GetPage(name: '/', page: () => Home()),\n  ]\n)\n```\nNeden bu değişiklik?\n\nGenellikle, hangi sayfanın bir parametreden görüntüleneceğine veya bir giriş belirteciden görüntüleneceğine karar vermek gerekebilir, önceki yaklaşım buna izin vermediği için esnek değildi.\nSayfayı bir fonksiyona sokmak, RAM tüketimini önemli ölçüde azaltır, çünkü rotalar uygulama başlatılmasından bu yana belleğe tahsis edilmeyecek ve aynı zamanda bu tür bir yaklaşım yapmasına izin verilmeyecek:\n\n```dart\n\nGetStorage box = GetStorage();\n\nGetMaterialApp(\n  getPages: [\n    GetPage(name: '/', page:(){\n      return box.hasData('token') ? Home() : Login();\n    })\n  ]\n)\n```\n\n# Neden Getx?\n\n1- Birçok kez Flutter güncellendikten sonra, birçok paket çalışmaz hale gelecek. Genelde derleme hataları gerçekleşir. Bu hataların hala cevabı olmayabilir. Geliştiricinin bu hatanın nerden geldiğini bilmesi gereklidir. Sonrasında bu hatayı izleyip bunun hakkında repository'de issue açması ve sorunun çözülmesini beklemelidir. Get, geliştirme için gereken ana kaynaklarını  (State, dependency ve route management) merkezde toplar, pubspec'e tek bir paket eklemeye izin verir ve çalışmaya başlar. Flutter güncellendikten sonra tek yapmanız gereken Get dependency'yi güncellemek ve çalışmaya başlamaktır. Get uyumluluk problemlerini de çözer. Paketler arasında genelde güncellemeler sonrası uyumsuzluklar olabilir. Get'in kendi içinde her şey birbiri ile uyumlu olduğundan bunun için endişelenmenize gerek yoktur.\n\n2- Flutter oldukça kolay kullanımı olan inanılmaz olmasının yanı sıra birçok geliştirici tarafından istenmeyen `Navigator.of(context).push (context, builder [...]` gibi ezber yapılar içerir. Get geliştirmeyi basitleştirir. Route çağırmak için 8 kod yazmak yerine sadece `Get.to(Home())` diyerek bir sonraki sayfaya geçebilirsin. Dynamic web urls ile çalışmak mevcut Flutter ile çalışırken zorlayıcı olabilir. Get ile durum tam tersi hal alır ve işleri çok kolay bir hale getirir. Flutter'da State'leri yönetmek için dependency'leri pub içerindeki yüzlerce kütüphane arasından seçmek birçok tartışmayı da beraberinde getiren bir konudur. Get sayesinde ekranda değişkeni otomatik olarak güncellemesini sağlamak için değişkeninizin sonuna \".obs\" eklemek ve widget'ınızı Obx ile sarmalamak yeterlidir.\n\n3- Performansı kafaya takmayın. Flutter'ın performansı zaten çok iyi. Bir de state manager kullanırken ve blocs/stores/controllers gibi sınıflarınızı locator ile yönetirken de aynı performansı aldığınızı düşünün. İhtiyacınız olmadığında  dependency'lerinizi dışarıdan çağırmak zorunda kalacaksınız. Hiç düşündünüz mü, basitçe kullandığınız controller'ınızın artık kimse tarafından kullanılmadığında kolayca bellekten silindiğini? İşte  GetX bunu yapar. SmartManagement sayesinde kullanılmayan her şey endişelenmenize gerek kalmadan otomatik olarak hafızadan silinir. Bunun için bir logic yaratmaya gerek bile kalmadan, kaynakları minimum ölçüde tükettiğinize emin olabilirsiniz. \n\n4- Gerçek ayrıştırma: \"View ile the business logic (iş mantığını) birbirlerinden ayırmak\" kavramını duymuş olabilirsiniz. Bu sadece BLoC, MVC, MVVM'ye özgü bir özellik değildir, piyasadaki diğer standart tasarım desenlerinde de mevcuttur. Ancak bu kavram Flutter'da context kullanımına bağlı olarak kolaylaştırılabilir.\nBir InheritedWidget bulabilmek için context'e ihtiyaç duyduğunuzda, bunu view'da yapmalı ya da parametre ile aktarmalıyız. Ben bu yöntemi oldukça çirkin buluyorum. Ayrıca bir ekip ile çalışırken  View'daki iş mantığına hep bağımlı olacağız. GetX standart yaklaşımı benimsemez ve StatefulWidgets, InitState, vb. yapılarını tamamen ortadan kaldırmaz. Daha temiz bir yaklaşım sunar. Controller'ların yaşam döngüleri vardır. Mesela APIREST talebi yaptığında view'a bağlı olmak zorunda değilsin. Http çağrısı başlatmak için \"onInit\" kullanabilirsiniz. Veriler geldiğinde yerleştirilecektir. GEtX tamamen reaktif  (cidden,stream'lerin altında çalışır) olduğu için tüm item'lar doldurulduğunda o değişkeni kullanan tüm widget'lar view'da otomatik olarak güncellenecektir. Bu UI uzmanlığına sahip kişilerin sadece widget'larla çalışmasını sağlar ve kullanıcı etkinlikleri dışında iş mantığına hiçbir şey göndermek zorunda değildir (bir düğmeye tıklamak gibi). İş mantığı ile çalışan insanlar, bunu ayrı olarak oluşturmak ve test etmek konusunda serbest olacaktır.\n\nBu kütüphane her zaman güncellenebilir ve yeni özellikler eklenebilir olacaktır. PR ve contribute yapmakta tamamen özgürsünüz.\n\n# Topluluk\n\n## Topluluk Kanalları\n\nGetX oldukça aktif ve yardımsever bir topluluğa sahiptir. Bu framework kullanımıyla ilgili sorularınız varsa veya herhangi bir yardım istiyorsanız, lütfen topluluk kanallarımıza katılın, sorunuz daha hızlı yanıtlanacak ki bunun için en uygun yer burasıdır. Repository'de issues açabilir ve kaynak talep edebilirsiniz.  GetX topluluğunun bir parçası olmaktan çekinmeyin.\n\n| **Slack**                                                                                                                   | **Discord**                                                                                                                 | **Telegram**                                                                                                          |\n| :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------- |\n| [![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) |\n\n## Nasıl katkıda bulunulur?\n\n_Projeye katkıda bulunmak ister misiniz? Sizi destekçilerimizden biri olarak öne çıkarmaktan gurur duyacağız. İşte katkıda bulunabileceğiniz ve Get'i (ve Flutter'ı) daha da iyi hale getirebileceğiniz bazı noktalar._\n\n- Readme dosyasının diğer dillere çevrilmesine yardımcı olmak.\n- Readme'ye dokümanlar eklemek (birçok Get fonsyonu henüz belgelenmedi).\n- Get'in kullanımını öğretmek için makaleler yazabilir ya da videolar çekebilirsiniz (Bunlar Readme ve gelecekte Wiki'ye eklenecek).\n- Kod ve test PR'ları önermek.\n- Yeni fonksiyonlar eklemek.\n\nHer türlü yardım için teşekkürler.\n\n\n## Makaleler ve videolar\n\n- [Flutter Getx EcoSystem package for arabic people](https://www.youtube.com/playlist?list=PLV1fXIAyjeuZ6M8m56zajMUwu4uE3-SL0) - Tutorial by [Pesa Coder](https://github.com/UsamaElgendy).\n- [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).\n- [Complete GetX™ Navigation](https://www.youtube.com/watch?v=RaqPIoJSTtI) - Route management video by Amateur Coder.\n- [Complete GetX State Management](https://www.youtube.com/watch?v=CNpXbeI_slw) - State management video by Amateur Coder.\n- [GetX™ Other Features](https://youtu.be/ttQtlX_Q0eU) - Utils, storage, bindings and other features video by Amateur Coder.\n- [Firestore User with GetX | Todo App](https://www.youtube.com/watch?v=BiV0DcXgk58) - Video by Amateur Coder.\n- [Firebase Auth with GetX | Todo App](https://www.youtube.com/watch?v=-H-T_BSgfOE) - Video by Amateur Coder.\n- [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).\n- [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).\n- [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.\n- [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.\n- [GetX Flutter Firebase Auth Example](https://medium.com/@jeffmcmorris/getx-flutter-firebase-auth-example-b383c1dd1de2) - Article by Jeff McMorris.\n- [Flutter State Management with GetX – Complete App](https://www.appwithflutter.com/flutter-state-management-with-getx/) - by App With Flutter.\n- [Flutter Routing with Animation using Get Package](https://www.appwithflutter.com/flutter-routing-using-get-package/) - by App With Flutter.\n- [A minimal example on dartpad](https://dartpad.dev/2b3d0d6f9d4e312c5fdbefc414c1727e?) - by [Roi Peker](https://github.com/roipeker)\n"
  },
  {
    "path": "README.ur-PK.md",
    "content": "﻿![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png)\n\n**🌎 اردو ( Selected ✔) [| انگریزی |](README.md) [| ویتنامی |](README-vi.md) [| انڈونیشی |](README.id-ID.md) [چینی |](README.zh-cn.md) [برازیلی پرتگالی |](README.pt-br.md) [ہسپانوی |](README-es.md) [روسی |](README.ru.md) [پولش |](README.pl.md) [کورین |](README.ko-kr.md), [French](README-fr.md)**\n\n[![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)\n[![popularity](https://badges.bar/get/popularity)](https://pub.dev/packages/sentry/score)\n[![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)\n[![pub points](https://badges.bar/get/pub%20points)](https://pub.dev/packages/get/score)\n![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)\n[![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart)\n[![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N)\n[![Get on Slack](https://img.shields.io/badge/slack-join-orange.svg)](https://communityinviter.com/apps/getxworkspace/getx)\n[![Telegram](https://img.shields.io/badge/chat-on%20Telegram-blue.svg)](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g)\n<a href=\"https://github.com/Solido/awesome-flutter\">\n<img alt=\"Awesome Flutter\" src=\"https://img.shields.io/badge/Awesome-Flutter-blue.svg?longCache=true&style=flat-square\" />\n</a>\n<a href=\"https://www.buymeacoffee.com/jonataslaw\" target=\"_blank\"><img src=\"https://i.imgur.com/aV6DDA7.png\" alt=\"Buy Me A Coffee\" style=\"height: 41px !important;width: 174px !important; box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;\" > </a>\n\n![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/getx.png)\n\n- [تعارف](#تعارف)\n- [انسٹال](#انسٹال)\n- [کاؤنٹرایپ](#کاؤنٹرایپ)\n- [تین ستون](#تین-ستون)\n  - [اسٹیٹ مینجمنٹ](#اسٹیٹ-مینجمنٹ)\n    - [ری ایکٹو اسٹیٹ منیجر](#ری-ایکٹو-اسٹیٹ-منیجر)\n    - [اسٹیٹ مینجمنٹ کے بارے میں مزید تفصیلات](#اسٹیٹ-مینجمنٹ-کے-بارے-میں-مزید-تفصیلات)\n  - [روٹ مینجمنٹ](#روٹ-مینجمنٹ)\n    - [روٹ مینجمنٹ کے بارے میں مزید تفصیلات](#روٹ-مینجمنٹ-کے-بارے-میں-مزید-تفصیلات)\n  - [انحصار کا انتظام](#انحصار-کا-انتظام)\n    - [انحصار کے انتظام کے بارے میں مزید تفصیلات](#انحصار-کے-انتظام-کے-بارے-میں-مزید-تفصیلات)\n- [استعمال](#استعمال)\n  - [عالمگیریت](#عالمگیریت)\n    - [ترجمہ](#ترجمہ)\n      - [ترجمہ کا استعمال](#ترجمہ-کا-استعمال)\n    - [مقامی](#مقامی)\n      - [مقام کی تبدیلی](#مقام-کی-تبدیلی)\n      - [سسٹم لوکیشن](#سسٹم-لوکیشن)\n  - [تھیم کی تبدیلی](#تھیم-کی-تبدیلی)\n  - [رابطے کا قیام](#رابطے-کا-قیام)\n    - [ڈیفالٹ کنکشن کا قیام](#ڈیفالٹ-کنکشن-کا-قیام)\n    - [خود سے رابطے کا قیام](#خود-سے-رابطے-کا-قیام)\n  - [گیٹ پیج مڈل ویئر](#گیٹ-پیج-مڈل-ویئر)\n    - [ترجیح](#ترجیح)\n    - [ری ڈائریکٹ](#ری-ڈائریکٹ)\n    - [جب پیج کی درخواست کی جائے](#جب-پیج-کی-درخواست-کی-جائے)\n    - [آنبائنڈنگ اسٹارٹ](#آنبائنڈنگ-اسٹارٹ)\n    - [آنپیج بلڈ اسٹارٹ](#آنپیج-بلڈ-اسٹارٹ)\n    - [جب پیج لوڈ ہو](#جب-پیج-لوڈ-ہو)\n    - [جب صفحہ تصرف ہوجائے](#جب-صفحہ-تصرف-ہوجائے)\n  - [دوسرے اعلی درجے کی APIs](#دوسرے-اعلی-درجے-کی-apis)\n    - [اختیاری عالمی ترتیبات اور دستی تشکیلات](#اختیاری-عالمی-ترتیبات-اور-دستی-تشکیلات)\n    - [مقامی اسٹیٹ ویجٹ](#مقامی-اسٹیٹ-ویجٹ)\n      - [ویلیو بلڈر](#ویلیو-بلڈر)\n      - [اوبکس ویلیو](#اوبکس-ویلیو)\n  - [کارآمد نکات](#کارآمد-نکات)\n      - [گیٹ ویو](#گیٹ-ویو)\n      - [گیٹ ویجٹ](#گیٹ-ویجٹ)\n      - [گیٹکس سروس](#گیٹکس-سروس)\n- [پچھلے ورژن سے اہم تبدیلیاں](#پچھلے-ورژن-سے-اہم-تبدیلیاں)\n- [گیٹکس کیوں؟](#گیٹکس-کیوں)\n- [سماجی خدمات](#سماجی-خدمات)\n  - [کمیونٹی چینلز](#کمیونٹی-چینلز)\n  - [کس طرح شراکت کریں](#کس-طرح-شراکت-کریں)\n  - [مضامین اور ویڈیوز](#مضامین-اور-ویڈیوز)\n\n# تعارف\n\nگیٹ ایکس  اسٹیٹ مینجمنٹ کے لئے ایک ہلکا پھلکا اور طاقتور حل ہے۔ یہ تیز اور عملی انداز میں اعلی کارکردگی والی اسٹسٹ مینجمنٹ ، ذہین انحصار انجکشن ، اور روٹ مینجمنٹ کو یکجا کرتا ہے۔ گیٹ ایکس کے 3 بنیادی اصول ہیں ، اس کا مطلب یہ ہے کہ لائبریری میں موجود تمام وسائل کی ترجیح یہی ہے: **پروڈکٹیوٹی,  کارکردگی اور تنظیم**\n\n **پروڈکٹیوٹی :** گیٹ ایکس کارکردگی اور وسائل کی کم سے کم کھپت پر مرکوز ہے۔ گیٹ ایکس اسٹریمز یا چینج نوٹیفائر استعمال نہیں کرتا ہے۔\n  \n **کارکردگی :** گیٹ ایکس ایک آسان اور خوشگوار ترکیب استعمال کرتا ہے۔ اس سے کوئی فرق نہیں پڑتا ہے کہ آپ کیا کرنا چاہتے ہیں ، گیٹ-ایکس کے ساتھ ہمیشہ ایک آسان راستہ رہتا ہے۔ اس سے کوڈنگ کے کئی گھنٹوں کی بچت ہوگی اور یہ آپ کی ایپلیکیشن فراہم کرنے والی زیادہ سے زیادہ کارکردگی کو نکال دے گی۔ عام طور پر ، ڈویلپر میموری سے کنٹرولرز کو ہٹانے سے متعلق رہنا چاہئے۔ گیٹ-ایکس کے ساتھ یہ ضروری نہیں ہے ، کیونکہ وسائل میموری سے حذف ہوجاتے ہیں جب وہ بطور ڈیفالٹ استعمال نہیں ہوتے ہیں۔ اگر آپ اسے یاد میں رکھنا چاہتے ہیں تو ، آپ کو اپنی انحصار میں واضح طور پر \"مستقل: سچ\" کا اعلان کرنا ہوگا۔ اس طرح ، وقت کی بچت کے علاوہ ، آپ کو میموری پر غیر ضروری انحصار کرنے کا خطرہ بھی کم ہوتا ہے۔ انحصار لوڈنگ ڈیفالٹ کے لحاظ سے بھی سست ہے۔\n\n **تنظیم :** گیٹ-ایکس کی مدد سے منظر ، نمائش کی منطق ، کاروباری منطق ، انحصار انجیکشن ، اور نیویگیشن کی مجموعی ڈوپولنگ کی اجازت دیتا ہے۔ راستوں کے مابین تشریف لے جانے کے لئے سیاق و سباق کی ضرورت نہیں ہے ، لہذا ، آپ اس کے لئے ویجیٹ ٹری (ویژنائزیشن) پر منحصر نہیں ہیں۔ وراثت میں ملنے والے ویجیٹ کے ذریعے اپنے کنٹرولرز / بلاکس تک رسائی حاصل کرنے کے لئے سیاق و سباق کی ضرورت نہیں ہے ، لہذا آپ اپنی پریزنٹیشن منطق اور کاروباری منطق کو اپنی نظریاتی پرت سے مکمل طور پر ڈوپل کرتے ہیں۔ آپ کو متعدد فراہم کنندگان کے ذریعہ اپنے ویجیٹ ٹری میں اپنے کنٹرولرز / ماڈلز / بلاکس کی کلاسیں انجیکشن کرنے کی ضرورت نہیں ہے ، کیونکہ یہ گیٹ ایکس اپنی انحصار انجیکشن کی خصوصیت استعمال کرتا ہے ، جس سے ڈی آئی کو اس کے نظارے کو مکمل طور پر خارج کردیتی ہے۔ گیٹ-ایکس کے ذریعے آپ جانتے ہو کہ اپنی درخواست کی ہر خصوصیت کو کہاں تلاش کرنا ہے ، بطور ڈیفالٹ صاف ستھرا۔ بحالی کی سہولت فراہم کرنے کے علاوہ ، یہ ماڈیولوں کی شیئرنگ کو بھی یقینی بناتا ہے ، ایسی کوئی چیز جو اس وقت تک پھڑپھڑ پھینک کر ناقابل فہم تھی ، اور کچھ مکمل طور پر ممکن تھا۔\nبی ایل او سی پھڑپھڑا میں کوڈ کو منظم کرنے کا نقطہ آغاز تھا ، یہ کاروباری منطق کو تصور سے الگ کرتا ہے۔ گیٹ ایکس اس کا فطری ارتقا ہے ، جس سے نہ صرف کاروباری منطق کو الگ کیا جائے بلکہ پیش کش کی منطق بھی۔ انحصار اور راستوں کا بونس انجیکشن بھی ڈوپل ہوچکا ہے ، اور ڈیٹا لیئر ان سب سے باہر ہے۔ آپ جانتے ہیں کہ سب کچھ کہاں ہے ، اور یہ سب کچھ ہیلو دنیا کی تعمیر سے زیادہ آسان طریقے سے ہے۔ گیٹ-ایکس ، فلٹر ایس ڈی کے کے ساتھ اعلی کارکردگی کی ایپلی کیشنز کی تعمیر کا آسان ترین ، عملی اور اسکیل ایبل طریقہ ہے ، جس کے ارد گرد ایک بہت بڑا ماحولیاتی نظام ہے جو کامل کے ساتھ مل کر کام کرتا ہے ، ابتدائی افراد کے لئے آسان اور ماہرین کے لئے درست ہے۔ یہ محفوظ ، مستحکم ، تازہ ترین ہے ، اور APIs کی ایک بہت بڑی رینج پیش کرتا ہے جو پہلے سے طے شدہ فلوٹر SDK پر موجود نہیں ہے۔\n\nگیٹ ایکس پھولا ہوا نہیں ہے۔ اس میں بہت ساری خصوصیات ہیں جو آپ کو کسی بھی چیز کی فکر کیے بغیر پروگرامنگ شروع کرنے کی اجازت دیتی ہیں ، لیکن ان خصوصیات میں سے ہر ایک الگ الگ کنٹینر میں ہے ، اور صرف استعمال کے بعد شروع کی گئی ہے۔ اگر آپ صرف اسٹیٹ مینجمنٹ کا استعمال کرتے ہیں تو صرف اسٹیٹ مینجمنٹ مرتب کی جائے گی۔ اگر آپ صرف راستے ہی استعمال کرتے ہیں تو ، اسٹیٹ مینجمنٹ کی طرف سے کوئی بھی چیز مرتب نہیں کی جائے گی۔\n\nگیٹ ایکس میں ایک بہت بڑا ماحولیاتی نظام ، ایک بڑی برادری ، بڑی تعداد میں تعاون کار موجود ہے ، اور جب تک پھڑپھڑ موجود ہے اس کو برقرار رکھا جائے گا۔ گیٹ ایکس بھی اسی کوڈ کے ساتھ اینڈروئیڈ ، آئی او ایس ، ویب ، میک ، لینکس ، ونڈوز اور اپنے سرور پر چلنے کے قابل ہے۔\n**یہ ممکن ہے کہ اپنے پس منظر میں فرنٹ اینڈ پر تیار کردہ اپنے کوڈ کو پوری طرح سے استعمال کریں [گیٹ ایکس سرور](https://github.com/jonataslaw/get_server)**.\n\n**اس کے علاوہ ، سرور پر اور سامنے والے اختتام پر ، پوری ترقی کا عمل مکمل طور پر خودکار ہوسکتا ہے [CLI حاصل کریں](https://github.com/jonataslaw/get_cli)**.\n\n**اس کے علاوہ ، آپ کی پیداوری کو مزید بڑھانے کے لئے ، ہمارے پاس ہے\n[VSCode](https://marketplace.visualstudio.com/items?itemName=get-snippets.get-snippets) اور [Android Studio/Intellij](https://plugins.jetbrains.com/plugin/14975-getx-snippets)**\n\n# انسٹال\nکوڈ میں گیٹ ایکس کی تنصیب\n```yaml\n# pubspec.yaml\ndependencies:\n  get:\n```\nان فائلوں میں امپورٹ کریں جو استعمال ہوں گی\n```dart\nimport 'package:get/get.dart';\n```\n\n# کاؤنٹرایپ\n\nگیٹ-ایکس کی طاقت کو ظاہر کرنے کے ل I ، میں یہ ظاہر کروں گا کہ کس طرح ہر کلک کے ساتھ \"کاؤنٹر\" بنانا ہے ، کس طرح صفحات کے مابین تبادلہ کرنا اور اسکرینوں کے درمیان اسٹسٹ کو مشترکہ انداز میں بانٹنا ، کاروباری منطق کو صرف نظر سے الگ کرنا ، 26 لائنز کوڈ شامل تبصرے۔\n\n- پہلا قدم :\n  اپنے میٹریل ایپ سے پہلے \"گیٹ\" شامل کریں ، اسے گیٹ میٹریئل ایپ میں تبدیل کریں\n\n```dart\nvoid main() => runApp(GetMaterialApp(home: Home()));\n```\n\nنوٹ: اس سے مٹیریل ایپ میں ترمیم نہیں ہوتی ، گیٹ میٹیرال ایپ کوئی ترمیم شدہ میٹریل ایپ نہیں ہے ، یہ ایک کنفیگریڈ ویجیٹ ہے ، جس میں بطور سی سی فلڈ میٹریل ایپ ہے۔ آپ اسے دستی طور پر تشکیل دے سکتے ہیں ، لیکن یہ یقینی طور پر ضروری نہیں ہے۔ گیٹ میٹریئل ایپ راستوں کو تخلیق کرے گی ، انہیں انجیکشن دے گی ، ترجمہ انجیکشن کرے گی ، روٹ نیویگیشن کے لئے آپ کی ضرورت کی ہر چیز کو انجیکشن دے گی۔ اگر آپ صرف ریاستی انتظام یا انحصار کے انتظام کے لئے گیٹیکس کا استعمال کرتے ہیں تو ، گیٹ میٹریئل ایپ کو استعمال کرنے کی ضرورت نہیں ہے۔ گیٹ میٹیرال ایپ راستوں ، سنیکبارز ، عالمگیریت ، نچلی شیٹس ، مکالموں ، اور روٹس سے متعلق اعلی سطحی اپس اور سیاق و سباق کی عدم موجودگی کے لئے ضروری ہے۔\nیہ اقدام صرف اس صورت میں ضروری ہے اگر آپ روٹ مینجمنٹ کا استعمال کریں گے (`Get.to()`, `Get.back()`). اگر آپ اسے استعمال نہیں کریں گے تو پھر ضروری نہیں ہے کہ قدم 1 کریں\n\n- دوسرا مرحلہ :\n  اپنی کاروباری منطق کلاس بنائیں اور اس کے اندر تمام متغیرات ، طریقے اور کنٹرولر رکھیں۔\n   کا استعمال کرتے ہوئے کسی بھی متغیر کو قابل مشاہدہ کرسکتے ہیں \".obs\".\n\n```dart\nclass Controller extends GetxController{\n  var count = 0.obs;\n  increment() => count++;\n}\n```\n\n- تیسرا قدم :\n  اپنا نظارہ بنائیں ، اسٹیٹ لیس ویجیٹ استعمال کریں اور کچھ رام کو بچائیں ، گیٹ-ایکس کی مدد سے آپ کو اب اسٹیٹ فل ویجٹ استعمال کرنے کی ضرورت نہیں ہوگی۔\n\n```dart\nclass Home extends StatelessWidget {\n\n  @override\n  Widget build(context) {\n    // آپ کی کلاس کا آغاز\n    // Instantiate your class using Get.put() to make it available for all \"child\" routes there.\n    final Controller c = Get.put(Controller());\n\n    return Scaffold(\n      // Use Obx(()=> to update Text() whenever count is changed.\n      appBar: AppBar(title: Obx(() => Text(\"Clicks: ${c.count}\"))),\n\n      // Replace the 8 lines Navigator.push by a simple Get.to(). You don't need context\n      body: Center(child: ElevatedButton(\n              child: Text(\"Go to Other\"), onPressed: () => Get.to(Other()))),\n      floatingActionButton:\n          FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment));\n  }\n}\n\nclass Other extends StatelessWidget {\n  // You can ask Get to find a Controller that is being used by another page and redirect you to it.\n  final Controller c = Get.find();\n\n  @override\n  Widget build(context){\n     // Access the updated count variable\n     return Scaffold(body: Center(child: Text(\"${c.count}\")));\n  }\n}\n```\n\nنتیجہ\n![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/counter-app-gif.gif)\nیہ ایک سادہ پروجیکٹ ہے لیکن اس سے پہلے ہی یہ واضح ہوجاتا ہے کہ گیٹ کتنا طاقتور ہے۔ جیسے جیسے آپ کا پروجیکٹ بڑھتا جائے گا ، یہ فرق مزید نمایاں ہوتا جائے گا۔\nگیٹ کو ٹیموں کے ساتھ کام کرنے کے لئے ڈیزائن کیا گیا تھا ، لیکن اس سے ایک فرد ڈویلپر کا کام آسان ہوجاتا ہے۔\nاپنی آخری تاریخ کو بہتر بنائیں ، کارکردگی کو کھونے کے بغیر وقت پر سب کچھ فراہم کریں۔ اگر آپ نے اس جملے کی نشاندہی کی ہے تو ، گیٹ-ایکس آپ کے لئے ہے!\n# تین ستون\n## اسٹیٹ مینجمنٹ\nگیٹ کے دو مختلف مینیجر ہوتے ہیں: سادہ ریاستی مینیجر (ہم اسے گیٹ بلڈر کہیں گے) اور رد عمل کا مظاہرہ کرنے والے مینیجر (گیٹ-ایکس / اوب-ایکس)\n### ری ایکٹو اسٹیٹ منیجر\nری ایکٹیو پروگرامنگ بہت سے لوگوں کو اجنبی بنا سکتا ہے کیونکہ ایسا کہا جاتا ہے کہ یہ پیچیدہ ہے۔ گیٹ ایکس نے رد عمل مندانہ پروگرامنگ کو کسی آسان چیز میں تبدیل کردیا:\n- آپ کو اسٹریمکنٹرولر بنانے کی ضرورت نہیں ہوگی\n- آپ کو ہر متغیر کے لئے ایک اسٹریم بلڈر بنانے کی ضرورت نہیں ہوگی\n- آپ کو ہر ریاست کے لئے کلاس بنانے کی ضرورت نہیں ہوگی\n- آپ کو ابتدائی قدر کے لئے گیٹ ایکس بنانے کی ضرورت نہیں ہوگی\n- آپ کو کوڈ جنریٹر استعمال کرنے کی ضرورت نہیں ہوگی\n\n\nگیٹ-ایکس کے ساتھ قابل عمل پروگرامنگ اتنا ہی آسان ہے جتنا سیٹ اسٹیٹ کے استعمال سے۔\n\nآئیے تصور کریں کہ آپ کے پاس متغیر ہے اور چاہتے ہیں کہ جب بھی آپ اسے تبدیل کریں ، اس کا استعمال کرنے والے تمام وجیٹس خود بخود تبدیل ہوجائیں۔\n\nیہ آپ کی گنتی متغیر ہے:\n\n```dart\nvar name = 'Jonatas Borges';\n```\n\n\".obs\" اسے مشاہدہ کرنے کے لئے؛ آپ کو اس کے آخر میں  شامل کرنے کی ضرورت ہے\n\n```dart\nvar name = 'Jonatas Borges'.obs;\n```\n\nاور صارف کے انٹرفیس میں ، جب آپ اس نمبر کو دکھانا چاہتے ہیں اور جب بھی اس کی اہمیت بدل جاتی ہے تو اسکرین کو اپ ڈیٹ کرنا چاہتے ہیں ، صرف یہ کریں:\n\n```dart\nObx(() => Text(\"${controller.name}\"));\n```\n\nبس۔ یہ آسان ہے.\n\n### اسٹیٹ مینجمنٹ کے بارے میں مزید تفصیلات\n\n**اسٹیٹ مینجمنٹ کی مزید گہرائی سے وضاحت ملاحظہ کریں [یہاں](./documentation/en_US/state_management.md).  وہاں آپ مزید مثالیں دیکھیں گے اور آسان ریاستی مینیجر اور رد عمل ریاست کے مینیجر کے مابین بھی فرق**\n\nآپ کو گیٹ ایکس پاور کا ایک اچھا خیال ملے گا۔\n\n## روٹ مینجمنٹ\nاگر آپ سیاق و سباق کے بغیر راستے / سنیکبارز / مکالمے / بوتل شیٹ استعمال کرنے جارہے ہیں تو گیٹ ایکس آپ کے لئے بھی بہترین ہے ، بس اسے دیکھیں:\nاپنے میٹریل ایپ سے پہلے \"گیٹ\" شامل کریں ، اسے گیٹ میٹریئل ایپ میں تبدیل کریں\n```dart\nGetMaterialApp( // Before: MaterialApp(\n  home: MyHome(),\n)\n```\n\nنئی اسکرین پر جائیں:\n\n```dart\n\nGet.to(NextScreen());\n```\n\nنام کے ساتھ نئی اسکرین پر جائیں۔ نامزد راستوں کے بارے میں مزید تفصیلات دیکھیں [یہاں](./documentation/en_US/route_management.md#navigation-with-named-routes)\n\n```dart\n\nGet.toNamed('/details');\n```\n\nسنیک بار ، ڈائیلاگ ، نیچے شیٹ کو بند کریں \nNavigator.pop(context);\n\n```dart\nGet.back();\n```\n\nاگلی اسکرین پر جانے کے لئے اور پچھلی اسکرین پر واپس جانے کا کوئی آپشن نہیں (اسپلش اسکرین ، لاگ ان اسکرینوں وغیرہ میں استعمال کیلئے)\n\n```dart\nGet.off(NextScreen());\n```\n\nاگلی سکرین پر جانے اور پچھلے سبھی راستوں کو منسوخ کرنے کے لئے (شاپنگ کارٹس ، پولز اور ٹیسٹوں میں کارآمد)\n\n```dart\nGet.offAll(NextScreen());\n```\n\nغور کیا کہ آپ کو ان میں سے کوئی بھی کام کرنے کے لئے سیاق و سباق کا استعمال نہیں کرنا پڑا؟ گیٹ روٹ مینجمنٹ کو استعمال کرنے کا سب سے بڑا فائدہ یہ ہے۔ اس کی مدد سے ، آپ اپنے کنٹرولر کلاس کے اندر ، تشویش کے بغیر ، ان تمام طریقوں کو انجام دے سکتے ہیں۔\n\n### روٹ مینجمنٹ کے بارے میں مزید تفصیلات\n\n**گیٹ ایکس نامی روٹ کے ساتھ کام کرتا ہے اور اپنے راستوں پر نچلی سطح کا کنٹرول بھی پیش کرتا ہے! ایک گہرائی میں دستاویزات موجود ہیں [یہاں](./documentation/en_US/route_management.md)**\n\n## انحصار کا انتظام\n\nگیٹ ایکس کے پاس ایک سادہ اور طاقتور انحصار منیجر ہے جو آپ کو اپنے بلاک یا کنٹرولر کی طرح ایک ہی کلاس کو دوبارہ حاصل کرنے کی سہولت دیتا ہے جس میں کوڈ کی صرف 1 لائنز ، کوئی فراہم کنندہ سیاق و سباق ، کوئی وراثت والا ویجٹ نہیں ہے۔\n\n```dart\nController controller = Get.put(Controller()); // Rather Controller controller = Controller();\n```\nنوٹ: اگر آپ گیٹ اسٹیٹ منیجر استعمال کررہے ہیں تو ، اے پی آئی کی پابندیوں پر زیادہ توجہ دیں ، جس سے آپ کے قول کو اپنے کنٹرولر سے مربوط کرنے میں آسانی ہوگی۔\n\nآپ جس کلاس کو استعمال کررہے ہیں اس میں اپنی کلاس کو تیز کرنے کے بجائے ، آپ اسے حاصل کریں مثال کے طور پر اندر داخل کررہے ہیں ، جس سے یہ آپ کے ایپ میں دستیاب ہوگا۔\nلہذا آپ اپنے کنٹرولر (یا کلاس بلاک) کو عام طور پر استعمال کرسکتے ہیں\n\n**اشارہ:**گیٹ ایکس انحصار کا انتظام پیکیج کے دوسرے حصوں سے گر گیا ہے ، لہذا اگر مثال کے طور پر آپ کی ایپ پہلے ہی اسٹیٹ مینیجر کو استعمال کررہی ہے (کوئی بھی ، اس سے کوئی فرق نہیں پڑتا ہے) ، آپ کو یہ سب کچھ دوبارہ لکھنے کی ضرورت نہیں ہے ، آپ اس انحصار کو استعمال کرسکتے ہیں۔\n```dart\ncontroller.fetchApi();\n```\n\nذرا تصور کریں کہ آپ نے متعدد راستوں سے گھوما ہوا ہے ، اور آپ کو ایک ایسے ڈیٹا کی ضرورت ہے جو آپ کے کنٹرولر میں پیچھے رہ گیا ہو ، آپ کو فراہم کنندہ یا گیٹ_یٹ کے ساتھ مل کر ایک ریاستی مینیجر کی ضرورت ہوگی ، صحیح؟ گیٹ ایکس کے ساتھ نہیں۔ آپ کو اپنے کنٹرولر کے ل \"\" ڈھونڈنے \"کے لئے گیٹ ایکس سے پوچھنے کی ضرورت ہے ، آپ کو کسی بھی اضافی انحصار کی ضرورت نہیں ہے۔\n\n```dart\nController controller = Get.find();\n```\n\nاور پھر آپ اپنا کنٹرولر ڈیٹا دوبارہ حاصل کرنے میں کامیاب ہوجائیں گے جو وہاں واپس حاصل کیا گیا تھا\n\n```dart\nText(controller.textFromApi);\n```\n\n### انحصار کے انتظام کے بارے میں مزید تفصیلات\n\n**انحصار کے انتظام کی مزید گہرائی سے وضاحت ملاحظہ کریں [یہاں](./documentation/en_US/dependency_management.md)**\n\n# استعمال\n\n## عالمگیریت\n\n### ترجمہ\n\nترجمہ کو ایک آسان کلیدی قدر والے لغت کے نقشے کے طور پر رکھا جاتا ہے۔\nحسب ضرورت ترجمہ شامل کرنے کے لئے ، ایک کلاس تشکیل دیں اور توسیع کریں \n`Translations`\n```dart\nimport 'package:get/get.dart';\n\nclass Messages extends Translations {\n  @override\n  Map<String, Map<String, String>> get keys => {\n        'en_US': {\n          'hello': 'Hello World',\n        },\n        'de_DE': {\n          'hello': 'Hallo Welt',\n        }\n      };\n}\n```\n\n#### ترجمہ کا استعمال\n\nبس ضمیمہ کریں `.tr` مخصوص کی میں اور اس کی موجودہ قیمت کا استعمال کرتے ہوئے ترجمہ کیا جائے گا`Get.locale` اور `Get.fallbackLocale`.\n\n```dart\nText('title'.tr);\n```\n\n### مقامی\n\nمقام اور ترجمے کی وضاحت کے لئے پیرامیٹرز کو `گیٹ میٹیرال ایپ` پاس کریں۔\n\n```dart\nreturn GetMaterialApp(\n    translations: Messages(), // your translations\n    locale: Locale('en', 'US'), // translations will be displayed in that locale\n    fallbackLocale: Locale('en', 'UK'), // specify the fallback locale in case an invalid locale is selected.\n);\n```\n\n#### مقام کی تبدیلی\n\nلوکل کو اپ ڈیٹ کرنے کے لئے کال کریں گیٹ۔ اپ ڈیٹ لوکل (لوکل)۔ پھر ترجمے خود بخود نیا مقام استعمال کرتے ہیں۔\n\n```dart\nvar locale = Locale('en', 'US');\nGet.updateLocale(locale);\n```\n\n#### سسٹم لوکیشن\n\nڈیوائس لوکل حاصل کرنے کے لئے اس لائن کو استعمال کریں\n\n```dart\nreturn GetMaterialApp(\n    locale: Get.deviceLocale,\n);\n```\n\n## تھیم کی تبدیلی\n\nبرائے کرم `گیٹ میٹرال ایپ` سے زیادہ کسی بھی اعلی سطح کے ویجیٹ کو اپ ڈیٹ کرنے کیلئے استعمال نہ کریں۔ اس سے ڈپلیکیٹ کیز کو متحرک کیا جاسکتا ہے۔ بہت سارے لوگ صرف اپنی ایپ کے تھیم کو تبدیل کرنے کے لئے \"تھیم پیڈائزر\" ویجیٹ بنانے کے پراگیتہاسک نقطہ نظر کے عادی ہیں ، اور یہ ** گیٹ ایکس ™ ** کے ساتھ یقینی طور پر ضروری نہیں ہے۔\n\nآپ اپنا کسٹم تھیم تشکیل دے سکتے ہیں اور اس کے لئے کسی بھی بوائلر پلیٹ کے بغیر اسے `گیٹ.چینج تھیم` میں شامل کرسکتے ہیں:\n\n```dart\nGet.changeTheme(ThemeData.light());\n```\n\n\nاگر آپ بٹن کی طرح کوئی چیز بنانا چاہتے ہیں جو تھیم کو `آن ٹیپ میں تبدیل کردے ، تو آپ اس کے لئے دو ** گیٹ ایکس ™ ** اے پی پی کو جوڑ سکتے ہیں:\n\n- اے پی آئی جو چیک کرتا ہے کہ آیا گہرا `تھیم` استعمال کیا جارہا ہے۔\n- اور `تھیم` کی تبدیلی ، آپ اسے صرف `آن پیسڈ` میں ڈال سکتے ہیں۔\n\n```dart\nGet.changeTheme(Get.isDarkMode? ThemeData.light(): ThemeData.dark());\n```\n\nجب ڈارک موڈ چالو ہوجاتا ہے ، تو وہ _ لائٹ تھیم_ میں تبدیل ہوجائے گا ، اور جب _ لائٹ تھیم_ فعال ہوجائے گا ، تو یہ _ ڈارک تھیم_ میں بدل جائے گا۔\n\n## رابطے کا قیام\nگیٹ کنیکٹ آپ کی پیٹھ سے اپنے سامنے تک HTTP یا ویب ساکٹس کے ذریعہ مواصلت کرنے کا ایک آسان طریقہ ہے\n\n### ڈیفالٹ کنکشن کا قیام\nآپ آرام سے گیٹ کنیکٹ کو بڑھا سکتے ہیں اور GET / POST / PUT / DELETE / SOCKET طریقوں کو اپنے ریسٹ API یا ویب ساکٹس کے ساتھ بات چیت کرسکتے ہیں۔\n\n```dart\nclass UserProvider extends GetConnect {\n  // Get request\n  Future<Response> getUser(int id) => get('http://youapi/users/$id');\n  // Post request\n  Future<Response> postUser(Map data) => post('http://youapi/users', body: data);\n  // Post request with File\n  Future<Response<CasesModel>> postCases(List<int> image) {\n    final form = FormData({\n      'file': MultipartFile(image, filename: 'avatar.png'),\n      'otherFile': MultipartFile(image, filename: 'cover.png'),\n    });\n    return post('http://youapi/users/upload', form);\n  }\n\n  GetSocket userMessages() {\n    return socket('https://yourapi/users/socket');\n  }\n}\n```\n### خود سے رابطے کا قیام\n\nگیٹ کنیکٹ انتہائی حسب ضرورت ہے آپ درخواست کو تبدیل کرنے والے ، جواب دہندگان کے بطور ، جواب دہندگان کی حیثیت سے ، ایک مستند کی وضاحت ، اور حتی کہ کوششوں کی تعداد بھی کرسکتے ہیں جس میں وہ خود کو مستند کرنے کی کوشش کرے گی ، اس کے علاوہ یہ ایک معیاری ڈیکوڈر کی وضاحت کے امکان کو بھی فراہم کرے گی جو تبدیل ہوجائے گی۔ آپ کی ساری درخواستیں آپ میں اضافی تشکیل کے بغیر ماڈل کرتی ہیں۔\n\n```dart\nclass HomeProvider extends GetConnect {\n  @override\n  void onInit() {\n    // All request will pass to jsonEncode so CasesModel.fromJson()\n    httpClient.defaultDecoder = CasesModel.fromJson;\n    httpClient.baseUrl = 'https://api.covid19api.com';\n    // baseUrl = 'https://api.covid19api.com'; // It define baseUrl to\n    // Http and websockets if used with no [httpClient] instance\n\n    // It's will attach 'apikey' property on header from all requests\n    httpClient.addRequestModifier((request) {\n      request.headers['apikey'] = '12345678';\n      return request;\n    });\n\n    // Even if the server sends data from the country \"Brazil\",\n    // it will never be displayed to users, because you remove\n    // that data from the response, even before the response is delivered\n    httpClient.addResponseModifier<CasesModel>((request, response) {\n      CasesModel model = response.body;\n      if (model.countries.contains('Brazil')) {\n        model.countries.remove('Brazilll');\n      }\n    });\n\n    httpClient.addAuthenticator((request) async {\n      final response = await get(\"http://yourapi/token\");\n      final token = response.body['token'];\n      // Set the header\n      request.headers['Authorization'] = \"$token\";\n      return request;\n    });\n\n    //Autenticator will be called 3 times if HttpStatus is \n    //HttpStatus.unauthorized\n    httpClient.maxAuthRetries = 3;\n  }\n\n  @override\n  Future<Response<CasesModel>> getCases(String path) => get(path);\n}\n```\n\n## گیٹ پیج مڈل ویئر\n\nگیٹ پیج کے پاس اب نئی پراپرٹی ہے جو گیٹ میڈل ویئر کی فہرست لیتی ہے اور انہیں مخصوص ترتیب میں چلاتی ہے۔\n\nنوٹ: جب گیٹ پیج کے مڈل ویئرز ہوں گے تو ، اس صفحے کے سبھی بچوں میں ایک جیسے مڈل ویئرز خودبخود ہوں گے۔\n\n### ترجیح\n\nمڈل ویئر کو چلانے کا آرڈر گیٹ میڈل ویئر میں ترجیحی طور پر ترتیب دیا جاسکتا ہے۔\n\n```dart\nfinal middlewares = [\n  GetMiddleware(priority: 2),\n  GetMiddleware(priority: 5),\n  GetMiddleware(priority: 4),\n  GetMiddleware(priority: -8),\n];\n```\nوہ مڈل ویئر اسی ترتیب سے چلائے جائیں گے **-8 => 2 => 4 => 5**\n\n### ری ڈائریکٹ\n\nاس فنکشن کو اس وقت کہا جائے گا جب کال والے راستے کے صفحے کی تلاش کی جا رہی ہو۔ اس کو ری ڈائریکٹ کرنے کے نتیجے میں روٹ سیٹنگز لیتے ہیں۔ یا اسے کالعدم کردیں اور کوئی ردوبدل نہیں ہوگا۔\n\n```dart\nRouteSettings redirect(String route) {\n  final authService = Get.find<AuthService>();\n  return authService.authed.value ? null : RouteSettings(name: '/login')\n}\n```\n\n### جب پیج کی درخواست کی جائے\n\nجب اس صفحے کو کچھ بھی تخلیق کرنے سے پہلے بلایا جائے گا تو اس فنکشن کو کہا جائے گا\nآپ اسے صفحہ کے بارے میں کچھ تبدیل کرنے یا نیا صفحہ دینے کیلئے استعمال کرسکتے ہیں\n\n```dart\nGetPage onPageCalled(GetPage page) {\n  final authService = Get.find<AuthService>();\n  return page.copyWith(title: 'Welcome ${authService.UserName}');\n}\n```\n\n### آنبائنڈنگ اسٹارٹ\n\nاس فنکشن کو بائنڈنگ شروع کرنے سے پہلے ہی کہا جائے گا۔\nیہاں آپ اس صفحے کے لئے پابندیوں کو تبدیل کرسکتے ہیں۔\n\n```dart\nList<Bindings> onBindingsStart(List<Bindings> bindings) {\n  final authService = Get.find<AuthService>();\n  if (authService.isAdmin) {\n    bindings.add(AdminBinding());\n  }\n  return bindings;\n}\n```\n\n### آنپیج بلڈ اسٹارٹ\n\nاس فنکشن کو بائنڈنگ شروع کرنے کے بعد ہی کہا جائے گا۔\nیہاں آپ اس کے بعد اور پیج ویجیٹ بنانے سے پہلے پابندیوں کو تخلیق کرنے کے بعد کچھ کرسکتے ہیں۔\n\n```dart\nGetPageBuilder onPageBuildStart(GetPageBuilder page) {\n  print('bindings are ready');\n  return page;\n}\n```\n\n### جب پیج لوڈ ہو\n\nاس فنکشن کو گیٹ پیج ڈاٹ پیج فنکشن کے بلانے کے ٹھیک ہی بعد میں کہا جائے گا اور آپ کو اس فنکشن کا نتیجہ پیش کرے گا۔ اور دکھایا جائے گا کہ ویجیٹ لے لو.\n\n### جب صفحہ تصرف ہوجائے\n\nاس فنکشن کو صفحے کے تمام متعلقہ اشیاء (کنٹرولرز ، آراء ، ...) کو ضائع کرنے کے بعد ہی کہا جائے گا۔\n\n## دوسرے اعلی درجے کی APIs\n\n```dart\n// give the current args from currentScreen\nGet.arguments\n\n// give name of previous route\nGet.previousRoute\n\n// give the raw route to access for example, rawRoute.isFirst()\nGet.rawRoute\n\n// give access to Routing API from GetObserver\nGet.routing\n\n// check if snackbar is open\nGet.isSnackbarOpen\n\n// check if dialog is open\nGet.isDialogOpen\n\n// check if bottomsheet is open\nGet.isBottomSheetOpen\n\n// remove one route.\nGet.removeRoute()\n\n// back repeatedly until the predicate returns true.\nGet.until()\n\n// go to next route and remove all the previous routes until the predicate returns true.\nGet.offUntil()\n\n// go to next named route and remove all the previous routes until the predicate returns true.\nGet.offNamedUntil()\n\n//Check in what platform the app is running\nGetPlatform.isAndroid\nGetPlatform.isIOS\nGetPlatform.isMacOS\nGetPlatform.isWindows\nGetPlatform.isLinux\nGetPlatform.isFuchsia\n\n//Check the device type\nGetPlatform.isMobile\nGetPlatform.isDesktop\n//All platforms are supported independently in web!\n//You can tell if you are running inside a browser\n//on Windows, iOS, OSX, Android, etc.\nGetPlatform.isWeb\n\n\n// Equivalent to : MediaQuery.of(context).size.height,\n// but immutable.\nGet.height\nGet.width\n\n// Gives the current context of the Navigator.\nGet.context\n\n// Gives the context of the snackbar/dialog/bottomsheet in the foreground, anywhere in your code.\nGet.contextOverlay\n\n// Note: the following methods are extensions on context. Since you\n// have access to context in any place of your UI, you can use it anywhere in the UI code\n\n// If you need a changeable height/width (like Desktop or browser windows that can be scaled) you will need to use context.\ncontext.width\ncontext.height\n\n// Gives you the power to define half the screen, a third of it and so on.\n// Useful for responsive applications.\n// param dividedBy (double) optional - default: 1\n// param reducedBy (double) optional - default: 0\ncontext.heightTransformer()\ncontext.widthTransformer()\n\n/// Similar to MediaQuery.of(context).size\ncontext.mediaQuerySize()\n\n/// Similar to MediaQuery.of(context).padding\ncontext.mediaQueryPadding()\n\n/// Similar to MediaQuery.of(context).viewPadding\ncontext.mediaQueryViewPadding()\n\n/// Similar to MediaQuery.of(context).viewInsets;\ncontext.mediaQueryViewInsets()\n\n/// Similar to MediaQuery.of(context).orientation;\ncontext.orientation()\n\n/// Check if device is on landscape mode\ncontext.isLandscape()\n\n/// Check if device is on portrait mode\ncontext.isPortrait()\n\n/// Similar to MediaQuery.of(context).devicePixelRatio;\ncontext.devicePixelRatio()\n\n/// Similar to MediaQuery.of(context).textScaleFactor;\ncontext.textScaleFactor()\n\n/// Get the shortestSide from screen\ncontext.mediaQueryShortestSide()\n\n/// True if width be larger than 800\ncontext.showNavbar()\n\n/// True if the shortestSide is smaller than 600p\ncontext.isPhone()\n\n/// True if the shortestSide is largest than 600p\ncontext.isSmallTablet()\n\n/// True if the shortestSide is largest than 720p\ncontext.isLargeTablet()\n\n/// True if the current device is Tablet\ncontext.isTablet()\n\n/// اسکرین کے سائز کے مطابق <T> ایک قیمت لوٹاتا ہے\n/// اس کی قیمت دے سکتے ہیں:\n/// واچ: اگر مختصر ترین جگہ 300 سے چھوٹی ہے\n/// موبائل: اگر مختصر ترین سائٹ 600 سے چھوٹی ہے\n/// ٹیبلٹ: اگر مختصر ترین سائٹ 1200 سے چھوٹی ہے\n/// ڈیسک ٹاپ: اگر چوڑائی 1200 سے زیادہ ہے\ncontext.responsiveValue<T>()\n```\n\n### اختیاری عالمی ترتیبات اور دستی تشکیلات\n\nگیٹ میٹریئل ایپ آپ کے لئے ہر چیز کو کنفیگر کرتی ہے ، لیکن اگر آپ تشکیل کرنا چاہتے ہیں تو دستی طور پر حاصل کریں۔\n\n```dart\nMaterialApp(\n  navigatorKey: Get.key,\n  navigatorObservers: [GetObserver()],\n);\n```\n\nآپ `گیٹ اوزرور` کے اندر اپنا مڈل ویئر بھی استعمال کرسکیں گے ، اس سے کسی بھی چیز پر اثر نہیں پڑے گا۔\n\n```dart\nMaterialApp(\n  navigatorKey: Get.key,\n  navigatorObservers: [\n    GetObserver(MiddleWare.observer) // Here\n  ],\n);\n```\n\nآپ `گیٹ` کیلئے _ عالمی ترتیبات_ تشکیل دے سکتے ہیں۔ کسی بھی راستے کو آگے بڑھانے سے پہلے صرف اپنے کوڈ میں `گیٹ کنفیگ` شامل کریں۔\nیا اسے اپنے `گیٹ میٹیرال ایپ` میں براہ راست کریں\n\n```dart\nGetMaterialApp(\n  enableLog: true,\n  defaultTransition: Transition.fade,\n  opaqueRoute: Get.isOpaqueRouteDefault,\n  popGesture: Get.isPopGestureEnable,\n  transitionDuration: Get.defaultDurationTransition,\n  defaultGlobalState: Get.defaultGlobalState,\n);\n\nGet.config(\n  enableLog = true,\n  defaultPopGesture = true,\n  defaultTransition = Transitions.cupertino\n)\n```\n\nآپ لاگ ان پیغامات کو اختیاری طور پر `گیٹ` سے دوبارہ بھیج سکتے ہیں۔\nاگر آپ خود اپنا ، پسندیدہ لاگنگ پیکیج استعمال کرنا چاہتے ہیں تو ،\nاور وہاں موجود نوشتہ جات پر قبضہ کرنا چاہتے ہیں:\n\n```dart\nGetMaterialApp(\n  enableLog: true,\n  logWriterCallback: localLogWriter,\n);\n\nvoid localLogWriter(String text, {bool isError = false}) {\n  // pass the message to your favourite logging package here\n  // please note that even if enableLog: false log messages will be pushed in this callback\n  // you get check the flag if you want through GetConfig.isLogEnable\n}\n\n```\n\n### مقامی اسٹیٹ ویجٹ\n\nیہ وجیٹس آپ کو ایک ہی قیمت کا انتظام کرنے ، اور مقامی طور پر ریاست کو دائمی اور مقامی رکھنے کی اجازت دیتے ہیں۔\nہمارے پاس ری ایکٹیو اور سادہ ذائقے ہیں۔\nمثال کے طور پر ، آپ ان کو ٹیکسٹ فیلڈ میں چھپے ہوئے متن کو ٹوگل کرنے کے لئے استعمال کرسکتے ہیں ، شاید کوئی رواج بنائیں\nتوسیع پذیر پینل ، یا ہوسکتا ہے کہ موجودہ فہرست میں ترمیم کرکے نیچے کی نیویگیشن بار میں مواد کو تبدیل کرتے ہوئے\n`Scaffold` میں جسم کا\n\n#### ویلیو بلڈر\n\n`StatefulWidget` کی ایک سادگی جو` .setState` کال بیک کے ساتھ کام کرتی ہے جو تازہ ترین قیمت لیتی ہے۔\n\n```dart\nValueBuilder<bool>(\n  initialValue: false,\n  builder: (value, updateFn) => Switch(\n    value: value,\n    onChanged: updateFn, // same signature! you could use ( newValue ) => updateFn( newValue )\n  ),\n  // if you need to call something outside the builder method.\n  onUpdate: (value) => print(\"Value updated: $value\"),\n  onDispose: () => print(\"Widget unmounted\"),\n),\n```\n\n#### اوبکس ویلیو\n\nاس طرح آپ کو قیمت ملتی ہے\n\n```dart\nObxValue((data) => Switch(\n        value: data.value,\n        onChanged: data, // Rx has a _callable_ function! You could use (flag) => data.value = flag,\n    ),\n    false.obs,\n),\n```\n\n## کارآمد نکات\n\n`.obs`ervables ( _Rx_ Types) \n```dart\nvar message = 'Hello world'.obs;\nprint( 'Message \"$message\" has Type ${message.runtimeType}');\n```\n\n `message`  --> **RxString**\n\n[x] `message.substring( 0, 4 )`.\n[o] `.value`\n\n```dart\nfinal name = 'GetX'.obs;\n// only \"updates\" the stream, if the value is different from the current one.\nname.value = 'Hey';\n\n// All Rx properties are \"callable\" and returns the new value.\n// but this approach does not accepts `null`, the UI will not rebuild.\nname('Hello');\n\n// is like a getter, prints 'Hello'.\nname() ;\n\n/// numbers:\n\nfinal count = 0.obs;\n\n// You can use all non mutable operations from num primitives!\ncount + 1;\n\n// Watch out! this is only valid if `count` is not final, but var\ncount += 1;\n\n// You can also compare against values:\ncount > 2;\n\n/// booleans:\n\nfinal flag = false.obs;\n\n// switches the value between true/false\nflag.toggle();\n\n\n/// all types:\n\n// Sets the `value` to null.\nflag.nil();\n\n// All toString(), toJson() operations are passed down to the `value`\nprint( count ); // calls `toString()` inside  for RxInt\n\nfinal abc = [0,1,2].obs;\n// Converts the value to a json Array, prints RxList\n// Json is supported by all Rx types!\nprint('json: ${jsonEncode(abc)}, type: ${abc.runtimeType}');\n\n// RxMap, RxList and RxSet are special Rx types, that extends their native types.\n// but you can work with a List as a regular list, although is reactive!\nabc.add(12); // pushes 12 to the list, and UPDATES the stream.\nabc[3]; // like Lists, reads the index 3.\n\n\n// equality works with the Rx and the value, but hashCode is always taken from the value\nfinal number = 12.obs;\nprint( number == 12 ); // prints > true\n\n/// Custom Rx Models:\n\n// toJson(), toString() are deferred to the child, so you can implement override on them, and print() the observable directly.\n\nclass User {\n    String name, last;\n    int age;\n    User({this.name, this.last, this.age});\n\n    @override\n    String toString() => '$name $last, $age years old';\n}\n\nfinal user = User(name: 'John', last: 'Doe', age: 33).obs;\n\n// `user` is \"reactive\", but the properties inside ARE NOT!\n// So, if we change some variable inside of it...\nuser.value.name = 'Roi';\n// The widget will not rebuild!,\n// `Rx` don't have any clue when you change something inside user.\n// So, for custom classes, we need to manually \"notify\" the change.\nuser.refresh();\n\n// or we can use the `update()` method!\nuser.update((value){\n  value.name='Roi';\n});\n\nprint( user );\n```\n\n#### گیٹ ویو\n\n\nمجھے یہ ویجیٹ پسند ہے ، بہت آسان ، پھر بھی ، اتنا مفید ہے!\n\nایک کانسٹیٹ اسٹیٹ لیس ویجیٹ ہے جس میں رجسٹرڈ `کنٹرولر` کے لئے حاصل کرنے والا `کنٹرولر` ہے ، بس۔\n\n```dart\n class AwesomeController extends GetxController {\n   final String title = 'My Awesome View';\n }\n\n  // ALWAYS remember to pass the `Type` you used to register your controller!\n class AwesomeView extends GetView<AwesomeController> {\n   @override\n   Widget build(BuildContext context) {\n     return Container(\n       padding: EdgeInsets.all(20),\n       child: Text(controller.title), // just call `controller.something`\n     );\n   }\n }\n```\n\n#### گیٹ ویجٹ\n\nزیادہ تر لوگوں کو اس ویجیٹ کے بارے میں کوئی اندازہ نہیں ہے ، یا اس کے استعمال کو پوری طرح سے الجھن میں ہے\nاستعمال کا معاملہ بہت کم ہے ، لیکن بہت ہی خاص ہے: یہ ایک کنٹرولر کی مدد کرتا ہے\nکیچ_کی وجہ سے ، `مجاز اسٹیٹ لیس  نہیں ہوسکتا ہے\n\n> تو ، جب آپ کو ایک کنٹرولر \"کیش\" کرنے کی ضرورت ہے؟\n\nاگر آپ استعمال کرتے ہیں تو ، ** گیٹ ایکس ** کی ایک اور \"اتنی عام نہیں\" خصوصیت: `گیٹ.کریٹ`۔\n\n`Get.create(()=>Controller())` ایک نیا پیدا کرے گا `Controller` ہر بار جب آپ کال کریں گے\n`Get.find<Controller>()`,\n\nاسی جگہ پر `گیٹ ویجٹ` چمکتا ہے ... جیسے کہ آپ اسے استعمال کرسکتے ہیں ، مثال کے طور پر ،\nٹوڈو اشیاء کی ایک فہرست رکھنے کے ل. لہذا ، اگر آپکے پاس وجٹس کو \"دوبارہ تعمیر\" ہو جاتا ہے تو ، یہ وہی کنٹرولر مثال برقرار رکھے گا۔\n\n#### گیٹکس سروس\n\nThis class is like a `GetxController`, it shares the same lifecycle ( `onInit()`, `onReady()`, `onClose()`).\nBut has no \"logic\" inside of it. It just notifies **GetX** Dependency Injection system, that this subclass\n**can not** be removed from memory.\n\nSo is super useful to keep your \"Services\" always reachable and active with `Get.find()`. Like:\n`ApiService`, `StorageService`, `CacheService`.\n\n```dart\nFuture<void> main() async {\n  await initServices(); /// AWAIT SERVICES INITIALIZATION.\n  runApp(SomeApp());\n}\n\n/// Is a smart move to make your Services intiialize before you run the Flutter app.\n/// as you can control the execution flow (maybe you need to load some Theme configuration,\n/// apiKey, language defined by the User... so load SettingService before running ApiService.\n/// so GetMaterialApp() doesnt have to rebuild, and takes the values directly.\nvoid initServices() async {\n  print('starting services ...');\n  /// Here is where you put get_storage, hive, shared_pref initialization.\n  /// or moor connection, or whatever that's async.\n  await Get.putAsync(() => DbService().init());\n  await Get.putAsync(SettingsService()).init();\n  print('All services started...');\n}\n\nclass DbService extends GetxService {\n  Future<DbService> init() async {\n    print('$runtimeType delays 2 sec');\n    await 2.delay();\n    print('$runtimeType ready!');\n    return this;\n  }\n}\n\nclass SettingsService extends GetxService {\n  void init() async {\n    print('$runtimeType delays 1 sec');\n    await 1.delay();\n    print('$runtimeType ready!');\n  }\n}\n\n```\n\n`گیٹکسسروس` کو اصل میں حذف کرنے کا واحد راستہ ،`گیٹ.ریسیٹ`  ہے جو ایک جیسے ہے\nآپ کی ایپ کا \"گرم ریبوٹ\"۔ لہذا ، یاد رکھیں ، اگر آپ کو دوران کلاس مثال کے طور پر مطلق استقامت کی ضرورت ہو\nاپنی ایپ کی زندگی بھر ، `گیٹکسسروس` استعمال کریں۔\n\n# پچھلے ورژن سے اہم تبدیلیاں\n\n1.  آر ایکس اقسام:\n\n| Before  | After      |\n| ------- | ---------- |\n| StringX | `RxString` |\n| IntX    | `RxInt`    |\n| MapX    | `RxMap`    |\n| ListX   | `RxList`   |\n| NumX    | `RxNum`    |\n| DoubleX | `RxDouble` |\n\nآر ایکس کنٹرولر اور گیٹ بلڈر اب آپس میں مل گئے ہیں ، اب آپ کو یہ حفظ کرنے کی ضرورت نہیں ہے کہ آپ کون سے کنٹرولر استعمال کرنا چاہتے ہیں ، صرف گیٹکسکنٹرولر کا استعمال کریں ، یہ سادہ سسٹم مینجمنٹ اور رد عمل کے  بھی کام کرے گا۔\n\n2.  نامزد روٹس\nپہلے:\n\n```dart\nGetMaterialApp(\n  namedRoutes: {\n    '/': GetRoute(page: Home()),\n  }\n)\n```\n\nاب:\n\n```dart\nGetMaterialApp(\n  getPages: [\n    GetPage(name: '/', page: () => Home()),\n  ]\n)\n```\n\nیہ تبدیلی کیوں؟\nاکثر ، یہ فیصلہ کرنا ضروری ہوسکتا ہے کہ پیرامیٹر ، یا لاگ ان ٹوکن سے کون سا صفحہ ڈسپلے ہوگا ، پچھلا نقطہ نظر پیچیدہ تھا ، کیونکہ اس نے اس کی اجازت نہیں دی۔\nصفحہ کو کسی فنکشن میں داخل کرنے سے رام کی کھپت میں نمایاں کمی واقع ہوئی ہے ، کیونکہ ایپ شروع ہونے کے بعد سے روٹوں کو میموری میں مختص نہیں کیا جائے گا ، اور اس طرح اس طرح کے نقطہ نظر کو کرنے کی بھی اجازت دی گئی ہے۔\n\n```dart\n\nGetStorage box = GetStorage();\n\nGetMaterialApp(\n  getPages: [\n    GetPage(name: '/', page:(){\n      return box.hasData('token') ? Home() : Login();\n    })\n  ]\n)\n```\n\n# گیٹکس کیوں؟\n\n1.  فلٹر کی تازہ کاری کے بعد ، آپ کے بہت سے پیکیجز ٹوٹ جائیں گے۔ بعض اوقات تالیف کی غلطیاں ہوتی ہیں ، غلطیاں اکثر ظاہر ہوتی ہیں کہ اب بھی اس کے بارے میں کوئی جواب نہیں ملتا ہے ، اور ڈویلپر کو یہ جاننے کی ضرورت ہوتی ہے کہ غلطی کہاں سے ہوئی ہے ، غلطی کو ٹریک کریں ، تب ہی متعلقہ ذخیرہ میں کوئی مسئلہ کھولنے کی کوشش کریں ، اور دیکھیں کہ اس کا مسئلہ حل ہوتا ہے۔ ترقی کے مرکزی وسائل کو مرکز بنائیں (ریاست ، انحصار اور روٹ مینجمنٹ) ، آپ کو اپنے پبسپیک میں ایک پیکیج شامل کرنے اور کام شروع کرنے کی اجازت دے۔ پھڑپھڑانے کی تازہ کاری کے بعد ، آپ کو صرف انحصار کرنے کی ضرورت ہے گیٹ انحصار کو اپ ڈیٹ کریں ، اور کام کریں۔ مطابقت کے مسائل کو بھی حل کریں حاصل کریں۔ ایک پیکج کا ورژن کتنی بار دوسرے کے ورژن کے ساتھ مطابقت نہیں رکھتا ہے ، کیونکہ ایک ورژن میں انحصار استعمال کرتا ہے ، اور دوسرا دوسرے ورژن میں۔ گیٹ کو استعمال کرنے میں بھی یہ کوئی تشویش نہیں ہے ، کیونکہ سب کچھ ایک ہی پیکج میں ہے اور مکمل طور پر ہم آہنگ ہے۔\n\n2. فلٹر آسان ہے .فلٹر ناقابل یقین ہے ، لیکن .فلٹر کے پاس اب بھی کچھ بوائلرپلیٹ موجود ہے جو زیادہ تر ڈویلپرز کے لئے ناپسندیدہ ہوسکتا ہے ، جیسے `Navigator.of(context).push (context, builder [...]`. پروگرامنگ کو آسان بنائیں۔ صرف راستے پر کال کرنے کے لئے 8 لائنوں کے کوڈ لکھنے کے بجائے ، آپ صرف یہ کرسکتے ہیں: `Get.to(Home())` اور آپ کر چکے ہیں ، آپ اگلے صفحے پر جائیں گے۔ متحرک ویب یو آر ایل ایک بہت تکلیف دہ چیز ہے جس کے ساتھ کرنا ہے ۔فلٹر فی الحال ، اور یہ کہ گیٹیکس کے ساتھ احمقانہ حد تک آسان ہے۔ .. فلٹر میں ریاستوں کا انتظام کرنا ، اور انحصار کا انتظام کرنا بھی ایک ایسی چیز ہے جو بہت ساری بحثیں پیدا کرتی ہے ، کیوں کہ پب میں سیکڑوں نمونوں کی موجودگی موجود ہے۔ لیکن آپ کے متغیر کے اختتام پر `.obs` شامل کرنے جتنا آسان کوئی چیز نہیں ہے ، اور اپنے ویجیٹ کو کسی اوکس کے اندر رکھ دیں ، اور بات یہ ہے کہ اس متغیر کی تمام تر تازہ کاری خود بخود اسکرین پر اپ ڈیٹ ہوجائے گی۔\n\n3. کارکردگی کی فکر کئے بغیر آسانی۔ .فلٹر کی کارکردگی پہلے ہی حیرت انگیز ہے ، لیکن تصور کریں کہ آپ اپنے بلاکس / اسٹورز / کنٹرولرز / وغیرہ کلاسوں کو تقسیم کرنے کے لئے اسٹیٹ مینیجر اور لوکیٹر کا استعمال کرتے ہیں۔ جب آپ کو ضرورت نہ ہو تو آپ کو دستی طور پر اس انحصار کے اخراج کو کال کرنا پڑے گا۔ لیکن کیا آپ نے کبھی اپنے کنٹرولر کو محض استعمال کرنے کے بارے میں سوچا ہے ، اور جب اب یہ کسی کے ذریعہ استعمال نہیں ہو رہا تھا تو ، اسے آسانی سے میموری سے حذف کردیا جائے گا؟ گیٹ ایکس یہی کرتا ہے۔ اسمارٹ مینجمنٹ کے ساتھ ، ہر وہ چیز جو استعمال نہیں ہورہی ہے اسے میموری سے حذف کردیا جاتا ہے ، اور آپ کو پروگرامنگ کے علاوہ کسی بھی چیز کی فکر کرنے کی ضرورت نہیں ہے۔ آپ کو یقین دلایا جائے گا کہ آپ کم از کم ضروری وسائل بروئے کار لا رہے ہیں ، حتی کہ اس کے لئے بھی کوئی منطق پیدا نہیں کیا۔\n\n4. اصل ڈیکوپلنگ۔ آپ نے یہ نظریہ \"کاروبار کی منطق سے نظریہ کو الگ کریں\" سنا ہوگا۔ یہ ریاستی انتظام کے دیگر حلوں کی کوئی خاصیت نہیں ہے اور مارکیٹ میں کسی دوسرے معیار کا یہ تصور ہے۔ تاہم ، سیاق و سباق کے استعمال کی وجہ سے پھڑپھڑ میں اکثر اس تصور کو کم کیا جاسکتا ہے۔\nاگر آپ کو وراثت والے ویجیٹ کو تلاش کرنے کے لئے سیاق و سباق کی ضرورت ہوتی ہے تو ، آپ کو اس کی نظر میں ضرورت ہوگی ، یا پیرامیٹر کے ذریعہ سیاق و سباق کو منتقل کریں۔ مجھے خاص طور پر یہ حل بہت ہی بدصورت معلوم ہوتا ہے ، اور ٹیموں میں کام کرنے کے لئے ہمیں ہمیشہ ویو کی کاروباری منطق پر انحصار کرنا پڑے گا۔ گیٹکس معیاری نقطہ نظر کے ساتھ غیر روایتی ہے ، اور اگرچہ اس میں اسٹیٹ فل وِیجٹس ، انیسٹیٹ وغیرہ کے استعمال پر مکمل پابندی نہیں ہے تو ، اس کا ہمیشہ ایسا ہی نقطہ نظر ہوتا ہے جو صاف ستھرا ہوسکتا ہے۔ کنٹرولرز کے پاس زندگی کا دور رہتا ہے ، اور جب آپ کو مثال کے طور پر درخواست دینے کی ضرورت ہوتی ہے تو ، آپ کو نظر میں کسی چیز پر انحصار نہیں کرنا ہوتا ہے۔ آپ ایچ ٹی ٹی پی کال شروع کرنے کے لئے اونٹ کا استعمال کرسکتے ہیں ، اور جب ڈیٹا آجائے گا تو متغیرات آباد ہوجائیں گے۔ چونکہ گیٹ ایکس مکمل طور پر رد عمل مند ہے (واقعتا، ، اور نہروں کے تحت کام کرتا ہے) ، ایک بار جب سامان بھر جاتا ہے تو ، اس متغیر کو استعمال کرنے والے تمام ویجٹ خود بخود منظر میں اپ ڈیٹ ہوجائیں گے۔ اس سے UI کی مہارت رکھنے والے افراد کو صرف وگیٹس کے ساتھ کام کرنے کا موقع ملتا ہے ، اور صارف کے واقعات (جیسے بٹن پر کلک کرنے کے علاوہ) کے علاوہ کاروباری منطق پر کچھ بھی نہیں بھیجنا پڑتا ہے ، جبکہ کاروباری منطق کے ساتھ کام کرنے والے افراد الگ الگ کاروبار کی منطق کی تخلیق اور جانچ کر سکتے ہیں۔\n\nاس لائبریری کو ہمیشہ اپ ڈیٹ کیا جائے گا اور نئی خصوصیات کو نافذ کیا جائے گا۔ بلا جھجک پی آر پیش کریں اور ان میں اپنا حصہ ڈالیں۔\n\n# سماجی خدمات\n\n## کمیونٹی چینلز\n\nگیٹ ایکس میں انتہائی فعال اور مددگار کمیونٹی ہے۔ اگر آپ کے ذہن میں سوالات ہیں ، یا اس فریم ورک کے استعمال کے سلسلے میں کوئی مدد چاہتے ہیں تو ، براہ کرم ہمارے کمیونٹی چینلز میں شامل ہوں ، آپ کے سوال کا زیادہ جلد جواب دیا جائے گا ، اور یہ سب سے موزوں جگہ ہوگی۔ یہ ذخیر. مسائل کو کھولنے ، اور وسائل کی درخواست کرنے کے لئے خصوصی ہے ، لیکن گیٹ ایکس کمیونٹی کا حصہ بننے میں آزاد محسوس کرتے ہیں۔\n\n| **Slack**                                                                                                                   | **Discord**                                                                                                                 | **Telegram**                                                                                                          |\n| :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------- |\n| [![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) |\n\n## کس طرح شراکت کریں\n\n\nمنصوبے میں شراکت کرنا چاہتے ہیں؟ ہمیں اپنے ایک ساتھی کی حیثیت سے آپ کو اجاگر کرنے پر فخر ہوگا۔ یہاں کچھ نکات ہیں جہاں آپ اپنا حصہ ڈال سکتے ہیں اور گیٹ (اور پھڑپھڑنا) کو اور بہتر بنا سکتے ہیں۔\n\n- ریڈمی کو دوسری زبانوں میں ترجمہ کرنے میں مدد کرنا۔\n- دستاویزات کو ریڈ می میں شامل کرنا (گیٹ کے بہت سارے کام ابھی دستاویزی نہیں ہوئے ہیں)۔\n- مضامین لکھیں یا ویڈیوز بنائیں جس کی تعلیم دیتے ہیں کہ گیٹ (ان کو ریڈیم میں اور مستقبل میں ہمارے ویکی میں داخل کیا جائے گا) کو کس طرح استعمال کیا جائے۔\n- کوڈ / ٹیسٹ کے لئے پی آر پیش کرنا۔\n- نئے افعال سمیت.\n\nکسی بھی شراکت کا خیرمقدم ہے!\n\n## مضامین اور ویڈیوز\n\n- [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).\n- [Complete GetX™ Navigation](https://www.youtube.com/watch?v=RaqPIoJSTtI) - Route management video by Amateur Coder.\n- [Complete GetX State Management](https://www.youtube.com/watch?v=CNpXbeI_slw) - State management video by Amateur Coder.\n- [GetX™ Other Features](https://youtu.be/ttQtlX_Q0eU) - Utils, storage, bindings and other features video by Amateur Coder.\n- [Firestore User with GetX | Todo App](https://www.youtube.com/watch?v=BiV0DcXgk58) - Video by Amateur Coder.\n- [Firebase Auth with GetX | Todo App](https://www.youtube.com/watch?v=-H-T_BSgfOE) - Video by Amateur Coder.\n- [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).\n- [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).\n- [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.\n- [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.\n- [GetX Flutter Firebase Auth Example](https://medium.com/@jeffmcmorris/getx-flutter-firebase-auth-example-b383c1dd1de2) - Article by Jeff McMorris.\n- [Flutter State Management with GetX – Complete App](https://www.appwithflutter.com/flutter-state-management-with-getx/) - by App With Flutter.\n- [Flutter Routing with Animation using Get Package](https://www.appwithflutter.com/flutter-routing-using-get-package/) - by App With Flutter.\n\n\n"
  },
  {
    "path": "README.zh-cn.md",
    "content": "![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png)\n\n_语言: 中文, [英文](README.md), [越南文](README-vi.md), [印度尼西亚](README.id-ID.md), [乌尔都语](README.ur-PK.md), [巴西葡萄牙语](README.pt-br.md), [俄语](README.ru.md), [西班牙语](README-es.md), [波兰语](README.pl.md), [韩国语](README.ko-kr.md), [法语](README-fr.md), [French](README-fr.md)._\n\n[![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)\n[![popularity](https://badges.bar/get/popularity)](https://pub.dev/packages/sentry/score)\n[![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)\n[![pub points](https://badges.bar/get/pub%20points)](https://pub.dev/packages/get/score)\n![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)\n[![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart)\n[![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N)\n[![Get on Slack](https://img.shields.io/badge/slack-join-orange.svg)](https://communityinviter.com/apps/getxworkspace/getx)\n[![Telegram](https://img.shields.io/badge/chat-on%20Telegram-blue.svg)](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g)\n<a href=\"https://github.com/Solido/awesome-flutter\">\n<img alt=\"Awesome Flutter\" src=\"https://img.shields.io/badge/Awesome-Flutter-blue.svg?longCache=true&style=flat-square\" />\n</a>\n<a href=\"https://www.buymeacoffee.com/jonataslaw\" target=\"_blank\"><img src=\"https://i.imgur.com/aV6DDA7.png\" alt=\"Buy Me A Coffee\" style=\"height: 41px !important;width: 174px !important; box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;\" > </a>\n\n![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/getx.png)\n\n- [关于Get](#关于get)\n- [安装](#安装)\n- [GetX的计数器示例](#getx的计数器示例)\n- [三大功能](#三大功能)\n  - [状态管理](#状态管理)\n    - [响应式状态管理器](#响应式状态管理器)\n    - [关于状态管理的更多细节](#关于状态管理的更多细节)\n  - [路由管理](#路由管理)\n    - [关于路由管理的更多细节](#关于路由管理的更多细节)\n  - [依赖管理](#依赖管理)\n    - [关于依赖管理的更多细节](#关于依赖管理的更多细节)\n- [实用工具](#实用工具)\n  - [国际化](#国际化)\n    - [翻译](#翻译)\n      - [使用翻译](#使用翻译)\n    - [语言](#语言)\n      - [改变语言](#改变语言)\n      - [系统语言](#系统语言)\n  - [改变主题](#改变主题)\n  - [GetConnect](#getconnect)\n    - [默认配置](#默认配置)\n    - [自定义配置](#自定义配置)\n  - [GetPage 中间件](#getpage-中间件)\n    - [优先级](#优先级)\n    - [Redirect](#redirect)\n    - [onPageCalled](#onpagecalled)\n    - [OnBindingsStart](#onbindingsstart)\n    - [OnPageBuildStart](#onpagebuildstart)\n    - [OnPageBuilt](#onpagebuilt)\n    - [OnPageDispose](#onpagedispose)\n  - [其他高级API](#其他高级api)\n    - [可选的全局设置和手动配置](#可选的全局设置和手动配置)\n    - [局部状态组件](#局部状态组件)\n      - [ValueBuilder](#valuebuilder)\n      - [ObxValue](#obxvalue)\n  - [有用的提示](#有用的提示)\n      - [GetView](#getview)\n      - [GetWidget](#getwidget)\n      - [GetxService](#getxservice)\n- [从2.0开始的兼容性变化](#从20开始的兼容性变化)\n- [为什么选择Getx？](#为什么选择getx)\n- [社区](#社区)\n  - [社区渠道](#社区渠道)\n  - [如何做贡献](#如何做贡献)\n  - [文章和视频](#文章和视频)\n\n# 关于Get\n\n- GetX 是 Flutter 上的一个轻量且强大的解决方案：高性能的状态管理、智能的依赖注入和便捷的路由管理。\n\n- GetX 有3个基本原则：\n\n  - **性能：** GetX 专注于性能和最小资源消耗。GetX 打包后的apk占用大小和运行时的内存占用与其他状态管理插件不相上下。如果你感兴趣，这里有一个[性能测试](https://github.com/jonataslaw/benchmarks)。\n  - **效率：** GetX 的语法非常简捷，并保持了极高的性能，能极大缩短你的开发时长。\n  - **结构：** GetX 可以将界面、逻辑、依赖和路由完全解耦，用起来更清爽，逻辑更清晰，代码更容易维护。\n  \n- GetX 并不臃肿，却很轻量。如果你只使用状态管理，只有状态管理模块会被编译，其他没用到的东西都不会被编译到你的代码中。它拥有众多的功能，但这些功能都在独立的容器中，只有在使用后才会启动。\n\n- Getx有一个庞大的生态系统，能够在Android、iOS、Web、Mac、Linux、Windows和你的服务器上用同样的代码运行。\n**通过[Get Server](https://github.com/jonataslaw/get_server)** 可以在你的后端完全重用你在前端写的代码。\n\n**此外，通过[Get CLI](https://github.com/jonataslaw/get_cli)**，无论是在服务器上还是在前端，整个开发过程都可以完全自动化。\n\n**此外，为了进一步提高您的生产效率，我们还为您准备了一些插件**\n\n- **getx_template**：一键生成每个页面必需的文件夹、文件、模板代码等等\n  - [Android Studio/Intellij插件](https://plugins.jetbrains.com/plugin/15919-getx)\n- **GetX Snippets**：输入少量字母，自动提示选择后，可生成常用的模板代码\n  - [Android Studio/Intellij扩展](https://plugins.jetbrains.com/plugin/14975-getx-snippets)\n  - [VSCode扩展](https://marketplace.visualstudio.com/items?itemName=get-snippets.get-snippets)\n\n# 安装\n\n将 Get 添加到你的 pubspec.yaml 文件中。\n\n```yaml\ndependencies:\n  get:\n```\n\n在需要用到的文件中导入，它将被使用。\n\n```dart\nimport 'package:get/get.dart';\n```\n\n# GetX的计数器示例\n\nFlutter默认创建的 \"计数器 \"项目有100多行（含注释），为了展示Get的强大功能，我将使用 GetX 重写一个\"计数器 Plus版\"，实现：\n- 每次点击都能改变状态\n- 在不同页面之间切换\n- 在不同页面之间共享状态\n- 将业务逻辑与界面分离\n\n而完成这一切只需 **26 行代码（含注释）** \n\n- 步骤1.\n在你的MaterialApp前添加 \"Get\"，将其变成GetMaterialApp。\n\n```dart\nvoid main() => runApp(GetMaterialApp(home: Home()));\n```\n\n- 注意：这并不能修改Flutter的MaterialApp，GetMaterialApp并不是修改后的MaterialApp，它只是一个预先配置的Widget，它的子组件是默认的MaterialApp。你可以手动配置，但绝对没有必要。GetMaterialApp会创建路由，注入它们，注入翻译，注入你需要的一切路由导航。如果你只用Get来进行状态管理或依赖管理，就没有必要使用GetMaterialApp。GetMaterialApp对于路由、snackbar、国际化、bottomSheet、对话框以及与路由相关的高级apis和没有上下文（context）的情况下是必要的。\n- 注2: 只有当你要使用路由管理(`Get.to()`, `Get.back()`等)时才需要这一步。如果你不打算使用它，那么就不需要做第1步。\n\n- 第二步：\n  创建你的业务逻辑类，并将所有的变量，方法和控制器放在里面。\n  你可以使用一个简单的\".obs \"使任何变量成为可观察的。\n\n```dart\nclass Controller extends GetxController{\n  var count = 0.obs;\n  increment() => count++;\n}\n```\n\n- 第三步:\n  创建你的界面，使用StatelessWidget节省一些内存，使用Get你可能不再需要使用StatefulWidget。\n\n```dart\nclass Home extends StatelessWidget {\n\n  @override\n  Widget build(context) {\n\n    // 使用Get.put()实例化你的类，使其对当下的所有子路由可用。\n    final Controller c = Get.put(Controller());\n\n    return Scaffold(\n      // 使用Obx(()=>每当改变计数时，就更新Text()。\n      appBar: AppBar(title: Obx(() => Text(\"Clicks: ${c.count}\"))),\n\n      // 用一个简单的Get.to()即可代替Navigator.push那8行，无需上下文！\n      body: Center(child: ElevatedButton(\n              child: Text(\"Go to Other\"), onPressed: () => Get.to(Other()))),\n      floatingActionButton:\n          FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment));\n  }\n}\n\nclass Other extends StatelessWidget {\n  // 你可以让Get找到一个正在被其他页面使用的Controller，并将它返回给你。\n  final Controller c = Get.find();\n\n  @override\n  Widget build(context){\n     // 访问更新后的计数变量\n     return Scaffold(body: Center(child: Text(\"${c.count}\")));\n  }\n}\n```\n\n结果：\n\n![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/counter-app-gif.gif)\n\n这是一个简单的项目，但它已经让人明白Get的强大。随着项目的发展，这种差异将变得更加显著。\n\nGet的设计是为了与团队合作，但它也可以让个人开发者的工作变得更简单。\n\n加快开发速率，在不损失性能的情况下按时交付一切。Get并不适合每一个人，但如果你认同这句话，Get就是为你准备的!\n\n# 三大功能\n\n## 状态管理\n\n目前，Flutter有几种状态管理器。但是，它们中的大多数都涉及到使用ChangeNotifier来更新widget，这对于中大型应用的性能来说是一个很糟糕的方法。你可以在Flutter的官方文档中查看到，[ChangeNotifier应该使用1个或最多2个监听器](https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html)，这使得它们实际上无法用于任何中等或大型应用。\n\nGet 并不是比任何其他状态管理器更好或更差，而是说你应该分析这些要点以及下面的要点来选择只用Get，还是与其他状态管理器结合使用。\n\nGet不是其他状态管理器的敌人，因为Get是一个微框架，而不仅仅是一个状态管理器，既可以单独使用，也可以与其他状态管理器结合使用。\n\nGet有两个不同的状态管理器：简单的状态管理器（GetBuilder）和响应式状态管理器（GetX）。\n\n### 响应式状态管理器\n\n响应式编程可能会让很多人感到陌生，因为觉得它很复杂，但是GetX将响应式编程变得非常简单。\n\n- 你不需要创建StreamControllers.\n- 你不需要为每个变量创建一个StreamBuilder。\n- 你不需要为每个状态创建一个类。\n- 你不需要为一个初始值创建一个get。\n\n使用 Get 的响应式编程就像使用 setState 一样简单。\n\n让我们想象一下，你有一个名称变量，并且希望每次你改变它时，所有使用它的小组件都会自动刷新。\n\n这就是你的计数变量。\n\n```dart\nvar name = 'Jonatas Borges';\n```\n\n要想让它变得可观察，你只需要在它的末尾加上\".obs\"。\n\n```dart\nvar name = 'Jonatas Borges'.obs;\n```\n\n而在UI中，当你想显示该值并在值变化时更新页面，只需这样做。\n\n```dart\nObx(() => Text(\"${controller.name}\"));\n```\n\n这就是全部，就这么简单。\n\n### 关于状态管理的更多细节\n\n**关于状态管理更深入的解释请查看[这里](./documentation/zh_CN/state_management.md)。在那里你将看到更多的例子，以及简单的状态管理器和响应式状态管理器之间的区别**。\n\n你会对GetX的能力有一个很好的了解。\n\n## 路由管理\n\n如果你想免上下文（context）使用路由/snackbars/dialogs/bottomsheets，GetX对你来说也是极好的，来吧展示：\n\n在你的MaterialApp前加上 \"Get\"，把它变成GetMaterialApp。\n\n```dart\nGetMaterialApp( // Before: MaterialApp(\n  home: MyHome(),\n)\n```\n\n导航到新页面\n\n```dart\n\nGet.to(NextScreen());\n```\n\n用别名导航到新页面。查看更多关于命名路由的详细信息[这里](./documentation/zh_CN/route_management.md#navigation-with-named-routes)\n\n```dart\n\nGet.toNamed('/details');\n```\n\n要关闭snackbars, dialogs, bottomsheets或任何你通常会用Navigator.pop(context)关闭的东西。\n\n```dart\nGet.back();\n```\n\n进入下一个页面，但没有返回上一个页面的选项（用于闪屏页，登录页面等）。\n\n```dart\nGet.off(NextScreen());\n```\n\n进入下一个页面并取消之前的所有路由（在购物车、投票和测试中很有用）。\n\n```dart\nGet.offAll(NextScreen());\n```\n\n注意到你不需要使用context来做这些事情吗？这就是使用Get路由管理的最大优势之一。有了它，你可以在你的控制器类中执行所有这些方法，而不用担心context在哪里。\n\n### 关于路由管理的更多细节\n\n**关于别名路由，和对路由的低级控制，请看[这里](./documentation/zh_CN/route_management.md)**。\n\n## 依赖管理\n\nGet有一个简单而强大的依赖管理器，它允许你只用1行代码就能检索到与你的Bloc或Controller相同的类，无需Provider context，无需inheritedWidget。\n\n```dart\nController controller = Get.put(Controller()); // 而不是 Controller controller = Controller();\n```\n\n- 注意：如果你使用的是Get的状态管理器，请多注意绑定api，这将使你的界面更容易连接到你的控制器。\n\n你是在Get实例中实例化它，而不是在你使用的类中实例化你的类，这将使它在整个App中可用。\n所以你可以正常使用你的控制器（或类Bloc）。\n\n**提示：** Get依赖管理与包的其他部分是解耦的，所以如果你的应用已经使用了一个状态管理器（任何一个，都没关系），你不需要全部重写，你可以使用这个依赖注入。\n\n```dart\ncontroller.fetchApi();\n```\n\n想象一下，你已经浏览了无数条路由，现在你需要拿到一个被遗留在控制器中的数据，那你需要一个状态管理器与Provider或Get_it一起使用来拿到它，对吗？用Get则不然，Get会自动为你的控制器找到你想要的数据，而你甚至不需要任何额外的依赖关系。\n\n```dart\nController controller = Get.find();\n//是的，它看起来像魔术，Get会找到你的控制器，并将其提供给你。你可以实例化100万个控制器，Get总会给你正确的控制器。\n```\n\n然后你就可以恢复你在后面获得的控制器数据。\n\n```dart\nText(controller.textFromApi);\n```\n\n### 关于依赖管理的更多细节\n\n**关于依赖管理的更深入解释请看[此处](./documentation/zh_CN/dependency_management.md)**。\n\n# 实用工具\n\n## 国际化\n\n### 翻译\n\n翻译被保存为一个简单的键值字典映射。\n要添加自定义翻译，请创建一个类并扩展`翻译`。\n\n```dart\nimport 'package:get/get.dart';\n\nclass Messages extends Translations {\n  @override\n  Map<String, Map<String, String>> get keys => {\n        'zh_CN': {\n          'hello': '你好 世界',\n        },\n        'de_DE': {\n          'hello': 'Hallo Welt',\n        }\n      };\n}\n```\n\n#### 使用翻译\n\n只要将`.tr`追加到指定的键上，就会使用`Get.locale`和`Get.fallbackLocale`的当前值进行翻译。\n\n```dart\nText('title'.tr);\n```\n\n### 语言\n\n传递参数给`GetMaterialApp`来定义语言和翻译。\n\n```dart\nreturn GetMaterialApp(\n    translations: Messages(), // 你的翻译\n    locale: Locale('zh', 'CN'), // 将会按照此处指定的语言翻译\n    fallbackLocale: Locale('en', 'US'), // 添加一个回调语言选项，以备上面指定的语言翻译不存在\n);\n```\n\n#### 改变语言\n\n调用`Get.updateLocale(locale)`来更新语言环境。然后翻译会自动使用新的locale。\n\n```dart\nvar locale = Locale('en', 'US');\nGet.updateLocale(locale);\n```\n\n#### 系统语言\n\n要读取系统语言，可以使用`window.locale`。\n\n```dart\nimport 'dart:ui' as ui;\n\nreturn GetMaterialApp(\n    locale: ui.window.locale,\n);\n```\n\n## 改变主题\n\n请不要使用比`GetMaterialApp`更高级别的widget来更新主题，这可能会造成键重复。很多人习惯于创建一个 \"ThemeProvider \"的widget来改变应用主题，这在**GetX™**中是绝对没有必要的。\n\n你可以创建你的自定义主题，并简单地将其添加到`Get.changeTheme`中，而无需任何模板。\n\n```dart\nGet.changeTheme(ThemeData.light());\n```\n\n如果你想在 \"onTap \"中创建类似于改变主题的按钮，你可以结合两个**GetX™** API来实现。\n\n- 检查是否使用了深色的 \"Theme \"的API，以及 \"Theme \"更改API。\n- 而`Theme` Change API，你可以把下面的代码放在`onPressed`里。\n\n```dart\nGet.changeTheme(Get.isDarkMode? ThemeData.light(): ThemeData.dark());\n```\n\n当`.darkmode`被激活时，它将切换到light主题，当light主题被激活时，它将切换到dark主题。\n\n## GetConnect\n\nGetConnect可以便捷的通过http或websockets进行前后台通信。\n\n### 默认配置\n\n你能轻松的通过extend GetConnect就能使用GET/POST/PUT/DELETE/SOCKET方法与你的Rest API或websockets通信。\n\n```dart\nclass UserProvider extends GetConnect {\n  // Get request\n  Future<Response> getUser(int id) => get('http://youapi/users/$id');\n  // Post request\n  Future<Response> postUser(Map data) => post('http://youapi/users', body: data);\n  // Post request with File\n  Future<Response<CasesModel>> postCases(List<int> image) {\n    final form = FormData({\n      'file': MultipartFile(image, filename: 'avatar.png'),\n      'otherFile': MultipartFile(image, filename: 'cover.png'),\n    });\n    return post('http://youapi/users/upload', form);\n  }\n\n  GetSocket userMessages() {\n    return socket('https://yourapi/users/socket');\n  }\n}\n```\n\n### 自定义配置\n\nGetConnect具有多种自定义配置。你可以配置base Url，配置响应，配置请求，添加权限验证，甚至是尝试认证的次数，除此之外，还可以定义一个标准的解码器，该解码器将把您的所有请求转换为您的模型，而不需要任何额外的配置。\n\n```dart\nclass HomeProvider extends GetConnect {\n  @override\n  void onInit() {\n    // All request will pass to jsonEncode so CasesModel.fromJson()\n    httpClient.defaultDecoder = CasesModel.fromJson;\n    httpClient.baseUrl = 'https://api.covid19api.com';\n    // baseUrl = 'https://api.covid19api.com'; // It define baseUrl to\n    // Http and websockets if used with no [httpClient] instance\n\n    // It's will attach 'apikey' property on header from all requests\n    httpClient.addRequestModifier((request) {\n      request.headers['apikey'] = '12345678';\n      return request;\n    });\n\n    // Even if the server sends data from the country \"Brazil\",\n    // it will never be displayed to users, because you remove\n    // that data from the response, even before the response is delivered\n    httpClient.addResponseModifier<CasesModel>((request, response) {\n      CasesModel model = response.body;\n      if (model.countries.contains('Brazil')) {\n        model.countries.remove('Brazilll');\n      }\n    });\n\n    httpClient.addAuthenticator((request) async {\n      final response = await get(\"http://yourapi/token\");\n      final token = response.body['token'];\n      // Set the header\n      request.headers['Authorization'] = \"$token\";\n      return request;\n    });\n\n    //Autenticator will be called 3 times if HttpStatus is\n    //HttpStatus.unauthorized\n    httpClient.maxAuthRetries = 3;\n  }\n\n  @override\n  Future<Response<CasesModel>> getCases(String path) => get(path);\n}\n```\n\n## GetPage 中间件\n\nGetPage现在有个新的参数可以把列表中的Get中间件按指定顺序执行。\n\n**注意**: 当GetPage有中间件时，所有的子page会自动有相同的中间件。\n\n### 优先级\n\n设置中间件的优先级定义Get中间件的执行顺序。\n\n```dart\nfinal middlewares = [\n  GetMiddleware(priority: 2),\n  GetMiddleware(priority: 5),\n  GetMiddleware(priority: 4),\n  GetMiddleware(priority: -8),\n];\n```\n\n这些中间件会按这个顺序执行 **-8 => 2 => 4 => 5**\n\n### Redirect\n\n当被调用路由的页面被搜索时，这个函数将被调用。它将RouteSettings作为重定向的结果。或者给它null，就没有重定向了。\n\n```dart\nRouteSettings redirect(String route) {\n  final authService = Get.find<AuthService>();\n  return authService.authed.value ? null : RouteSettings(name: '/login')\n}\n```\n\n### onPageCalled\n\n在调用页面时，创建任何东西之前，这个函数会先被调用。\n您可以使用它来更改页面的某些内容或给它一个新页面。\n\n```dart\nGetPage onPageCalled(GetPage page) {\n  final authService = Get.find<AuthService>();\n  return page.copyWith(title: 'Welcome ${authService.UserName}');\n}\n```\n\n### OnBindingsStart\n\n这个函数将在绑定初始化之前被调用。\n在这里，您可以更改此页面的绑定。\n\n```dart\nList<Bindings> onBindingsStart(List<Bindings> bindings) {\n  final authService = Get.find<AuthService>();\n  if (authService.isAdmin) {\n    bindings.add(AdminBinding());\n  }\n  return bindings;\n}\n```\n\n### OnPageBuildStart\n\n这个函数将在绑定初始化之后被调用。\n在这里，您可以在创建绑定之后和创建页面widget之前执行一些操作。\n\n```dart\nGetPageBuilder onPageBuildStart(GetPageBuilder page) {\n  print('bindings are ready');\n  return page;\n}\n```\n\n### OnPageBuilt\n\n这个函数将在GetPage.page调用后被调用，并给出函数的结果，并获取将要显示的widget。\n\n### OnPageDispose\n\n这个函数将在处理完页面的所有相关对象(Controllers, views, ...)之后被调用。\n\n## 其他高级API\n\n```dart\n// 给出当前页面的args。\nGet.arguments\n\n//给出以前的路由名称\nGet.previousRoute\n\n// 给出要访问的原始路由，例如，rawRoute.isFirst()\nGet.rawRoute\n\n// 允许从GetObserver访问Rounting API。\nGet.routing\n\n// 检查 snackbar 是否打开\nGet.isSnackbarOpen\n\n// 检查 dialog 是否打开\nGet.isDialogOpen\n\n// 检查 bottomsheet 是否打开\nGet.isBottomSheetOpen\n\n// 删除一个路由。\nGet.removeRoute()\n\n//反复返回，直到表达式返回真。\nGet.until()\n\n// 转到下一条路由，并删除所有之前的路由，直到表达式返回true。\nGet.offUntil()\n\n// 转到下一个命名的路由，并删除所有之前的路由，直到表达式返回true。\nGet.offNamedUntil()\n\n//检查应用程序在哪个平台上运行。\nGetPlatform.isAndroid\nGetPlatform.isIOS\nGetPlatform.isMacOS\nGetPlatform.isWindows\nGetPlatform.isLinux\nGetPlatform.isFuchsia\n\n//检查设备类型\nGetPlatform.isMobile\nGetPlatform.isDesktop\n//所有平台都是独立支持web的!\n//你可以知道你是否在浏览器内运行。\n//在Windows、iOS、OSX、Android等系统上。\nGetPlatform.isWeb\n\n\n// 相当于.MediaQuery.of(context).size.height,\n//但不可改变。\nGet.height\nGet.width\n\n// 提供当前上下文。\nGet.context\n\n// 在你的代码中的任何地方，在前台提供 snackbar/dialog/bottomsheet 的上下文。\nGet.contextOverlay\n\n// 注意：以下方法是对上下文的扩展。\n// 因为在你的UI的任何地方都可以访问上下文，你可以在UI代码的任何地方使用它。\n\n// 如果你需要一个可改变的高度/宽度（如桌面或浏览器窗口可以缩放），你将需要使用上下文。\ncontext.width\ncontext.height\n\n// 让您可以定义一半的页面、三分之一的页面等。\n// 对响应式应用很有用。\n// 参数： dividedBy (double) 可选 - 默认值：1\n// 参数： reducedBy (double) 可选 - 默认值：0。\ncontext.heightTransformer()\ncontext.widthTransformer()\n\n/// 类似于 MediaQuery.of(context).size。\ncontext.mediaQuerySize()\n\n/// 类似于 MediaQuery.of(context).padding。\ncontext.mediaQueryPadding()\n\n/// 类似于 MediaQuery.of(context).viewPadding。\ncontext.mediaQueryViewPadding()\n\n/// 类似于 MediaQuery.of(context).viewInsets。\ncontext.mediaQueryViewInsets()\n\n/// 类似于 MediaQuery.of(context).orientation;\ncontext.orientation()\n\n///检查设备是否处于横向模式\ncontext.isLandscape()\n\n///检查设备是否处于纵向模式。\ncontext.isPortrait()\n\n///类似于MediaQuery.of(context).devicePixelRatio。\ncontext.devicePixelRatio()\n\n///类似于MediaQuery.of(context).textScaleFactor。\ncontext.textScaleFactor()\n\n///查询设备最短边。\ncontext.mediaQueryShortestSide()\n\n///如果宽度大于800，则为真。\ncontext.showNavbar()\n\n///如果最短边小于600p，则为真。\ncontext.isPhone()\n\n///如果最短边大于600p，则为真。\ncontext.isSmallTablet()\n\n///如果最短边大于720p，则为真。\ncontext.isLargeTablet()\n\n///如果当前设备是平板电脑，则为真\ncontext.isTablet()\n\n///根据页面大小返回一个值<T>。\n///可以给值为：\n///watch：如果最短边小于300\n///mobile：如果最短边小于600\n///tablet：如果最短边（shortestSide）小于1200\n///desktop：如果宽度大于1200\ncontext.responsiveValue<T>()\n```\n\n### 可选的全局设置和手动配置\n\nGetMaterialApp为你配置了一切，但如果你想手动配置Get。\n\n```dart\nMaterialApp(\n  navigatorKey: Get.key,\n  navigatorObservers: [GetObserver()],\n);\n```\n\n你也可以在`GetObserver`中使用自己的中间件，这不会影响任何事情。\n\n```dart\nMaterialApp(\n  navigatorKey: Get.key,\n  navigatorObservers: [\n    GetObserver(MiddleWare.observer) // Here\n  ],\n);\n```\n\n你可以为 \"Get \"创建_全局设置。只需在推送任何路由之前将`Get.config`添加到你的代码中。\n或者直接在你的`GetMaterialApp`中做。\n\n```dart\nGetMaterialApp(\n  enableLog: true,\n  defaultTransition: Transition.fade,\n  opaqueRoute: Get.isOpaqueRouteDefault,\n  popGesture: Get.isPopGestureEnable,\n  transitionDuration: Get.defaultDurationTransition,\n  defaultGlobalState: Get.defaultGlobalState,\n);\n\nGet.config(\n  enableLog = true,\n  defaultPopGesture = true,\n  defaultTransition = Transitions.cupertino\n)\n```\n\n你可以选择重定向所有来自`Get`的日志信息。\n如果你想使用你自己喜欢的日志包，并想查看那里的日志。\n\n```dart\nGetMaterialApp(\n  enableLog: true,\n  logWriterCallback: localLogWriter,\n);\n\nvoid localLogWriter(String text, {bool isError = false}) {\n  // 在这里把信息传递给你最喜欢的日志包。\n  // 请注意，即使enableLog: false，日志信息也会在这个回调中被推送。\n  // 如果你想的话，可以通过GetConfig.isLogEnable来检查这个标志。\n}\n\n```\n\n### 局部状态组件\n\n这些Widgets允许您管理一个单一的值，并保持状态的短暂性和本地性。\n我们有Reactive和Simple两种风格。\n例如，你可以用它们来切换`TextField`中的obscureText，也许可以创建一个自定义的可扩展面板（Expandable Panel），或者在\"Scaffold \"的主体中改变内容的同时修改`BottomNavigationBar`中的当前索引。\n\n\n#### ValueBuilder\n\n`StatefulWidget`的简化，它与`.setState`回调一起工作，并接受更新的值。\n\n```dart\nValueBuilder<bool>(\n  initialValue: false,\n  builder: (value, updateFn) => Switch(\n    value: value,\n    onChanged: updateFn, // 你可以用( newValue )=> updateFn( newValue )。\n  ),\n  // 如果你需要调用 builder 方法之外的东西。\n  onUpdate: (value) => print(\"Value updated: $value\"),\n  onDispose: () => print(\"Widget unmounted\"),\n),\n```\n\n#### ObxValue\n\n类似于[`ValueBuilder`](#valuebuilder)，但这是Reactive版本，你需要传递一个Rx实例（还记得神奇的.obs吗？自动更新......是不是很厉害？）\n\n```dart\nObxValue((data) => Switch(\n        value: data.value,\n        onChanged: data, // Rx 有一个 _callable_函数! 你可以使用 (flag) => data.value = flag,\n    ),\n    false.obs,\n),\n```\n\n## 有用的提示\n\n`.obs`ervables (也称为_Rx_ Types)有各种各样的内部方法和操作符。\n\n> `.obs`的属性**是**实际值，不要搞错了!\n> 我们避免了变量的类型声明，因为Dart的编译器足够聪明，而且代码\n> 看起来更干净，但：\n\n```dart\nvar message = 'Hello world'.obs;\nprint( 'Message \"$message\" has Type ${message.runtimeType}');\n```\n\n即使`message` _prints_实际的字符串值，类型也是**RxString**！\n所以，你不能做`message.substring( 0, 4 )`。\n你必须在_observable_里面访问真正的`value`。\n最常用的方法是\".value\", 但是你也可以用...\n\n```dart\nfinal name = 'GetX'.obs;\n//只有在值与当前值不同的情况下，才会 \"更新 \"流。\nname.value = 'Hey';\n\n// 所有Rx属性都是 \"可调用 \"的，并返回新的值。\n//但这种方法不接受 \"null\"，UI将不会重建。\nname('Hello');\n\n// 就像一个getter，打印'Hello'。\nname() ;\n\n///数字。\n\nfinal count = 0.obs;\n\n// 您可以使用num基元的所有不可变操作!\ncount + 1;\n\n// 注意！只有当 \"count \"不是final时，这才有效，除了var\ncount += 1;\n\n// 你也可以与数值进行比较。\ncount > 2;\n\n/// booleans:\n\nfinal flag = false.obs;\n\n// 在真/假之间切换数值\nflag.toggle();\n\n\n/// 所有类型。\n\n// 将 \"value \"设为空。\nflag.nil();\n\n// 所有的toString()、toJson()操作都会向下传递到`value`。\nprint( count ); // 在内部调用 \"toString() \"来GetRxInt\n\nfinal abc = [0,1,2].obs;\n// 将值转换为json数组，打印RxList。\n// 所有Rx类型都支持Json!\nprint('json: ${jsonEncode(abc)}, type: ${abc.runtimeType}');\n\n// RxMap, RxList 和 RxSet 是特殊的 Rx 类型，扩展了它们的原生类型。\n// 但你可以像使用普通列表一样使用列表，尽管它是响应式的。\nabc.add(12); // 将12添加到列表中，并更新流。\nabc[3]; // 和Lists一样，读取索引3。\n\n\n// Rx和值是平等的，但hashCode总是从值中提取。\nfinal number = 12.obs;\nprint( number == 12 ); // prints > true\n\n///自定义Rx模型。\n\n// toJson(), toString()都是递延给子代的，所以你可以在它们上实现覆盖，并直接打印()可观察的内容。\n\nclass User {\n    String name, last;\n    int age;\n    User({this.name, this.last, this.age});\n\n    @override\n    String toString() => '$name $last, $age years old';\n}\n\nfinal user = User(name: 'John', last: 'Doe', age: 33).obs;\n\n// `user`是 \"响应式 \"的，但里面的属性却不是!\n// 所以，如果我们改变其中的一些变量：\nuser.value.name = 'Roi';\n// 小部件不会重建！ \n// 对于自定义类，我们需要手动 \"通知 \"改变。\nuser.refresh();\n\n// 或者我们可以使用`update()`方法!\nuser.update((value){\n  value.name='Roi';\n});\n\nprint( user );\n```\n\n#### GetView\n\n我很喜欢这个Widget，很简单，很有用。\n\n它是一个对已注册的`Controller`有一个名为`controller`的getter的`const Stateless`的Widget，仅此而已。\n\n```dart\n class AwesomeController extends GetxController {\n   final String title = 'My Awesome View';\n }\n\n  // 一定要记住传递你用来注册控制器的`Type`!\n class AwesomeView extends GetView<AwesomeController> {\n   @override\n   Widget build(BuildContext context) {\n     return Container(\n       padding: EdgeInsets.all(20),\n       child: Text( controller.title ), // 只需调用 \"controller.something\"。\n     );\n   }\n }\n```\n\n#### GetWidget\n\n大多数人都不知道这个Widget，或者完全搞不清它的用法。\n这个用例非常少见且特殊：它 \"缓存 \"了一个Controller，由于_cache_，不能成为一个 \"const Stateless\"（因为_cache_，所以不能成为一个`const Stateless`）。\n\n> 那么，什么时候你需要 \"缓存 \"一个Controller？\n\n如果你使用了**GetX**的另一个 \"不常见 \"的特性 `Get.create()`\n\n`Get.create(()=>Controller())` 会在每次调用时生成一个新的`Controller`\n`Get.find<Controller>()`\n\n你可以用它来保存Todo项目的列表，如果小组件被 \"重建\"，它将保持相同的控制器实例。\n\n#### GetxService\n\n这个类就像一个 \"GetxController\"，它共享相同的生命周期（\"onInit()\"、\"onReady()\"、\"onClose()\"）。\n但里面没有 \"逻辑\"。它只是通知**GetX**的依赖注入系统，这个子类**不能**从内存中删除。\n\n所以这对保持你的 \"服务 \"总是可以被`Get.find()`获取到并保持运行是超级有用的。比如\n`ApiService`，`StorageService`，`CacheService`。\n\n```dart\nFuture<void> main() async {\n  await initServices(); /// 等待服务初始化.\n  runApp(SomeApp());\n}\n\n/// 在你运行Flutter应用之前，让你的服务初始化是一个明智之举。\n////因为你可以控制执行流程（也许你需要加载一些主题配置，apiKey，由用户自定义的语言等，所以在运行ApiService之前加载SettingService。\n///所以GetMaterialApp()不需要重建，可以直接取值。\nvoid initServices() async {\n  print('starting services ...');\n  ///这里是你放get_storage、hive、shared_pref初始化的地方。\n  ///或者moor连接，或者其他什么异步的东西。\n  await Get.putAsync(() => DbService().init());\n  await Get.putAsync(SettingsService()).init();\n  print('All services started...');\n}\n\nclass DbService extends GetxService {\n  Future<DbService> init() async {\n    print('$runtimeType delays 2 sec');\n    await 2.delay();\n    print('$runtimeType ready!');\n    return this;\n  }\n}\n\nclass SettingsService extends GetxService {\n  void init() async {\n    print('$runtimeType delays 1 sec');\n    await 1.delay();\n    print('$runtimeType ready!');\n  }\n}\n\n```\n\n实际删除一个`GetxService`的唯一方法是使用`Get.reset()`，它就像\"热重启 \"你的应用程序。\n\n所以如果你需要在你的应用程序的生命周期内对一个类实例进行绝对的持久化，请使用`GetxService`。\n\n# 从2.0开始的兼容性变化\n\n1- Rx类型。\n\n| Before  | After      |\n| ------- | ---------- |\n| StringX | `RxString` |\n| IntX    | `RxInt`    |\n| MapX    | `RxMap`    |\n| ListX   | `RxList`   |\n| NumX    | `RxNum`    |\n| DoubleX | `RxDouble` |\n\n现在RxController和GetBuilder已经合并了，你不再需要记住你要用哪个控制器，只要用GetxController就可以了，它可以用于简单的状态管理，也可以用于响应式。\n\n2- 别名路由\n之前：\n\n```dart\nGetMaterialApp(\n  namedRoutes: {\n    '/': GetRoute(page: Home()),\n  }\n)\n```\n\n现在:\n\n```dart\nGetMaterialApp(\n  getPages: [\n    GetPage(name: '/', page: () => Home()),\n  ]\n)\n```\n\n为什么要做这样的改变？\n通常情况下，可能需要通过一个参数，或者一个登录令牌来决定显示哪个页面。\n将页面插入到一个函数中，大大降低了RAM的消耗，因为自从应用程序启动后，路由将不会在内存中分配。\n\n```dart\n\nGetStorage box = GetStorage();\n\nGetMaterialApp(\n  getPages: [\n    GetPage(name: '/', page:(){\n      return box.hasData('token') ? Home() : Login();\n    })\n  ]\n)\n```\n\n# 为什么选择Getx？\n\n1- Flutter更新后，很多时候，你的很多包都会坏掉。有时会发生编译错误，经常出现的错误，至今仍没有答案，开发者需要知道错误的来源，跟踪错误，才会尝试在相应的仓库中开一个问题，并看到其问题的解决。Get集中了开发的主要资源（状态、依赖和路由管理），让你可以在pubspec中添加一个包，然后开始工作。Flutter更新后，你唯一需要做的就是更新Get依赖，然后开始工作。Get还可以解决兼容性问题。有多少次，一个包的版本与另一个包的版本不兼容，因为一个包在一个版本中使用了依赖，而另一个包在另一个版本中使用了依赖？使用Get也不用担心这个问题，因为所有的东西都在同一个包里，是完全兼容的。\n\n2- Flutter很简单，Flutter很不可思议，但是Flutter仍然有一些代码，对于大多数开发者来说可能是不需要的，比如`Navigator.of(context).push (context, builder [...]`，你写了8行代码仅仅只为了调用一个路由。而使用Get只需`Get.to(Home())`就完成了，你将进入下一个页面。动态网页URL是目前Flutter中非常痛苦的一件事，而用GetX则非常简单。在Flutter中管理状态，管理依赖关系也产生了很多讨论，因为pub中的模式有上百种。但是没有什么比在你的变量末尾加一个\".obs \"更简单的了，把你的widget放在一个Obx里面，就这样，所有对这个变量的更新都会在页面上自动更新。\n\n3-轻松，不用担心性能。Flutter的性能已经很惊人了，但是想象一下，你使用一个状态管理器，和一个定位器来分布你的blocs/stores/controllers/等等类。当你不需要那个依赖的时候，你必须手动调用排除它。但是，你有没有想过简单地使用你的控制器，当它不再被任何人使用时，它会简单地从内存中删除？这就是GetX所做的。有了SmartManagement，所有不被使用的东西都会从内存中删除，除了编程，您不应该担心任何事情。GetX将保证您消耗的是最低限度的必要资源，甚至没有为此创建一个逻辑。\n\n4-实际解耦。你可能听说过 \"将界面与业务逻辑分离 \"的概念。这并不是BLoC、MVC、MVVM的特例，市面上的其他标准都有这个概念。但是，由于使用了上下文（context），这个概念在Flutter中往往可以得到缓解。\n如果你需要上下文来寻找InheritedWidget，你需要在界面中找到它，或者通过参数传递上下文。我特别觉得这种解决方案非常丑陋，要在团队中工作，我们总会对View的业务逻辑产生依赖。Getx与标准的做法不一样，虽然它并没有完全禁止使用StatefulWidgets、InitState等，但它总有类似的方法，可以更干净。控制器是有生命周期的，例如当你需要进行APIREST请求时，你不依赖于界面中的任何东西。你可以使用onInit来启动http调用，当数据到达时，变量将被填充。由于GetX是完全响应式的（真的，在流下工作），一旦项目被填充，所有使用该变量的widgets将在界面中自动更新。这使得具有UI专业知识的人只需要处理widget，除了用户事件（比如点击按钮）之外，不需要向业务逻辑发送任何东西，而处理业务逻辑的人将可以自由地单独创建和测试业务逻辑。\n\n这个库会一直更新和实现新的功能。欢迎提供PR，并为其做出贡献。\n\n# 社区\n\n## 社区渠道\n\nGetX拥有一个非常活跃且乐于助人的社区。如果你有问题，或者想得到关于这个框架使用的任何帮助，请加入我们的社区频道。这个资源库是提问、申请资源的专用库，欢迎随时加入GetX社区。\n\n| **Slack**                                                                                                                   | **Discord**                                                                                                                 | **Telegram**                                                                                                          |\n| :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------- |\n| [![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) |\n\n## 如何做贡献\n\n_想为项目做贡献吗？我们将自豪地强调你是我们的合作者之一。以下是您可以做出贡献并使Get（和Flutter）变得更好的几点。\n\n- 帮助将readme翻译成其他语言。\n- 为readme添加文档（Get的很多功能还没有被记录下来）。\n- 撰写文章或制作视频，教大家如何使用Get（它们将被记录到readme和未来的Wiki中）。\n- 提供代码/测试的PR。\n- 包括新功能。\n\n欢迎任何贡献\n\n## 文章和视频\n\n- [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).\n- [Complete GetX™ Navigation](https://www.youtube.com/watch?v=RaqPIoJSTtI) - Route management video by Amateur Coder.\n- [Complete GetX State Management](https://www.youtube.com/watch?v=CNpXbeI_slw) - State management video by Amateur Coder.\n- [GetX™ Other Features](https://youtu.be/ttQtlX_Q0eU) - utils, storage, bindings and other features video by Amateur Coder.\n- [Firestore User with GetX | Todo App](https://www.youtube.com/watch?v=BiV0DcXgk58) - Video by Amateur Coder.\n- [Firebase Auth with GetX | Todo App](https://www.youtube.com/watch?v=-H-T_BSgfOE) - Video by Amateur Coder.\n- [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).\n- [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.\n- [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.\n- [GetX Flutter Firebase Auth Example](https://medium.com/@jeffmcmorris/getx-flutter-firebase-auth-example-b383c1dd1de2) - Article by Jeff McMorris.\n- [Flutter State Management with GetX – Complete App](https://www.appwithflutter.com/flutter-state-management-with-getx/) - by App With Flutter.\n- [Flutter Routing with Animation using Get Package](https://www.appwithflutter.com/flutter-routing-using-get-package/) - by App With Flutter.\n- [Flutter GetX use --- simple charm!](https://github.com/CNAD666/getx_template/blob/main/docs/Use%20of%20Flutter%20GetX---simple%20charm!.md) - CNAD666\n  - [Flutter GetX使用---简洁的魅力！](https://juejin.cn/post/6924104248275763208)\n\n"
  },
  {
    "path": "_config.yml",
    "content": "theme: jekyll-theme-cayman"
  },
  {
    "path": "analysis_options.yaml",
    "content": "# Include option is buggy:\ninclude: package:flutter_lints/flutter.yaml\nanalyzer:\n  errors:\n    unintended_html_in_doc_comment: ignore\n# In case the include issue gets fixed, lines below INCLUDE_FIX\n# can be removed\n"
  },
  {
    "path": "documentation/ar_EG/dependency_management.md",
    "content": "# Dependency Management\n- [Dependency Management](#dependency-management)\n  - [Instancing methods](#instancing-methods)\n    - [Get.put()](#getput)\n    - [Get.lazyPut](#getlazyput)\n    - [Get.putAsync](#getputasync)\n    - [Get.create](#getcreate)\n  - [Using instantiated methods/classes](#using-instantiated-methodsclasses)\n  - [Specifying an alternate instance](#specifying-an-alternate-instance)\n  - [Differences between methods](#differences-between-methods)\n  - [Bindings](#bindings)\n    - [Bindings class](#bindings-class)\n    - [BindingsBuilder](#bindingsbuilder)\n    - [SmartManagement](#smartmanagement)\n      - [How to change](#how-to-change)\n      - [SmartManagement.full](#smartmanagementfull)\n      - [SmartManagement.onlyBuilders](#smartmanagementonlybuilders)\n      - [SmartManagement.keepFactory](#smartmanagementkeepfactory)\n    - [How bindings work under the hood](#how-bindings-work-under-the-hood)\n  - [Notes](#notes)\n\nGet 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:\n\n```dart\nController controller = Get.put(Controller()); // Rather Controller controller = Controller();\n```\n\nInstead 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.\nSo you can use your controller (or Bloc class) normally\n\n- 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.\n- 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\n\n## Instancing methods\nThe methods and it's configurable parameters are:\n\n### Get.put()\n\nThe most common way of inserting a dependency. Good for the controllers of your views for example.\n\n```dart\nGet.put<SomeClass>(SomeClass());\nGet.put<LoginController>(LoginController(), permanent: true);\nGet.put<ListItemController>(ListItemController, tag: \"some unique string\");\n```\n\nThis is all options you can set when using put:\n```dart\nGet.put<S>(\n  // mandatory: the class that you want to get to save, like a controller or anything\n  // note: \"S\" means that it can be a class of any type\n  S dependency\n\n  // optional: this is for when you want multiple classess that are of the same type\n  // since you normally get a class by using Get.find<Controller>(),\n  // you need to use tag to tell which instance you need\n  // must be unique string\n  String tag,\n\n  // optional: by default, get will dispose instances after they are not used anymore (example,\n  // the controller of a view that is closed), but you might need that the instance\n  // to be kept there throughout the entire app, like an instance of sharedPreferences or something\n  // so you use this\n  // defaults to false\n  bool permanent = false,\n\n  // optional: allows you after using an abstract class in a test, replace it with another one and follow the test.\n  // defaults to false\n  bool overrideAbstract = false,\n\n  // optional: allows you to create the dependency using function instead of the dependency itself.\n  // this one is not commonly used\n  InstanceBuilderCallback<S> builder,\n)\n```\n\n### Get.lazyPut\nIt 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.\n\n```dart\n/// ApiMock will only be called when someone uses Get.find<ApiMock> for the first time\nGet.lazyPut<ApiMock>(() => ApiMock());\n\nGet.lazyPut<FirebaseAuth>(\n  () {\n    // ... some logic if needed\n    return FirebaseAuth();\n  },\n  tag: Math.random().toString(),\n  fenix: true\n)\n\nGet.lazyPut<Controller>( () => Controller() )\n```\n\nThis is all options you can set when using lazyPut:\n```dart\nGet.lazyPut<S>(\n  // mandatory: a method that will be executed when your class is called for the first time\n  InstanceBuilderCallback builder,\n  \n  // optional: same as Get.put(), it is used for when you want multiple different instance of a same class\n  // must be unique\n  String tag,\n\n  // optional: It is similar to \"permanent\", the difference is that the instance is discarded when\n  // is not being used, but when it's use is needed again, Get will recreate the instance\n  // just the same as \"SmartManagement.keepFactory\" in the bindings api\n  // defaults to false\n  bool fenix = false\n  \n)\n```\n\n### Get.putAsync\nIf you want to register an asynchronous instance, you can use `Get.putAsync`:\n\n```dart\nGet.putAsync<SharedPreferences>(() async {\n  final prefs = await SharedPreferences.getInstance();\n  await prefs.setInt('counter', 12345);\n  return prefs;\n});\n\nGet.putAsync<YourAsyncClass>( () async => await YourAsyncClass() )\n```\n\nThis is all options you can set when using putAsync:\n```dart\nGet.putAsync<S>(\n\n  // mandatory: an async method that will be executed to instantiate your class\n  AsyncInstanceBuilderCallback<S> builder,\n\n  // optional: same as Get.put(), it is used for when you want multiple different instance of a same class\n  // must be unique\n  String tag,\n\n  // optional: same as in Get.put(), used when you need to maintain that instance alive in the entire app\n  // defaults to false\n  bool permanent = false\n)\n```\n\n### Get.create\n\nThis 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\n\n```dart\nGet.Create<SomeClass>(() => SomeClass());\nGet.Create<LoginController>(() => LoginController());\n```\n\nThis is all options you can set when using create:\n\n```dart\nGet.create<S>(\n  // required: a function that returns a class that will be \"fabricated\" every\n  // time `Get.find()` is called\n  // Example: Get.create<YourClass>(() => YourClass())\n  FcBuilderFunc<S> builder,\n\n  // optional: just like Get.put(), but it is used when you need multiple instances\n  // of a of a same class\n  // Useful in case you have a list that each item need it's own controller\n  // needs to be a unique string. Just change from tag to name\n  String name,\n\n  // optional: just like int`Get.put()`, it is for when you need to keep the\n  // instance alive thoughout the entire app. The difference is in Get.create\n  // permanent is true by default\n  bool permanent = true\n```\n\n## Using instantiated methods/classes\n\nImagine 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:\n\n```dart\nfinal controller = Get.find<Controller>();\n// OR\nController controller = Get.find();\n\n// Yes, it looks like Magic, Get will find your controller, and will deliver it to you.\n// You can have 1 million controllers instantiated, Get will always give you the right controller.\n```\n\nAnd then you will be able to recover your controller data that was obtained back there:\n\n```dart\nText(controller.textFromApi);\n```\n\nSince the returned value is a normal class, you can do anything you want:\n```dart\nint count = Get.find<SharedPreferences>().getInt('counter');\nprint(count); // out: 12345\n```\n\nTo remove an instance of Get:\n\n```dart\nGet.delete<Controller>(); //usually you don't need to do this because GetX already delete unused controllers\n```\n\n## Specifying an alternate instance\n\nA 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.\n\n```dart\nabstract class BaseClass {}\nclass ParentClass extends BaseClass {}\n\nclass ChildClass extends ParentClass {\n  bool isChild = true;\n}\n\n\nGet.put<BaseClass>(ParentClass());\n\nGet.replace<BaseClass>(ChildClass());\n\nfinal instance = Get.find<BaseClass>();\nprint(instance is ChildClass); //true\n\n\nclass OtherClass extends BaseClass {}\nGet.lazyReplace<BaseClass>(() => OtherClass());\n\nfinal instance = Get.find<BaseClass>();\nprint(instance is ChildClass); // false\nprint(instance is OtherClass); //true\n```\n\n## Differences between methods\n\nFirst, let's of the `fenix` of Get.lazyPut and the `permanent` of the other methods.\n\nThe fundamental difference between `permanent` and `fenix` is how you want to store your instances.\n\nReinforcing: by default, GetX deletes instances when they are not in use.\nIt 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.\n\nBut 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.\n\n`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.\n\nProceeding with the differences between methods:\n\n- 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.\n\n- 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.\n\n- 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.\n\n## Bindings\n\nOne of the great differentials of this package, perhaps, is the possibility of full integration of the routes, state manager and dependency manager.\nWhen 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.\nIn version 2.10 Get completely implemented the Bindings API.\nNow 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.\nThe Binding class is a class that will decouple dependency injection, while \"binding\" routes to the state manager and dependency manager.\nThis 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.\nIn 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.\n\n### Bindings class\n\n- Create a class and implements Binding\n\n```dart\nclass HomeBinding implements Bindings {}\n```\n\nYour 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:\n\n```dart\nclass HomeBinding implements Bindings {\n  @override\n  void dependencies() {\n    Get.lazyPut<HomeController>(() => HomeController());\n    Get.put<Service>(()=> Api());\n  }\n}\n\nclass DetailsBinding implements Bindings {\n  @override\n  void dependencies() {\n    Get.lazyPut<DetailsController>(() => DetailsController());\n  }\n}\n```\n\nNow you just need to inform your route, that you will use that binding to make the connection between route manager, dependencies and states.\n\n- Using named routes:\n\n```dart\ngetPages: [\n  GetPage(\n    name: '/',\n    page: () => HomeView(),\n    binding: HomeBinding(),\n  ),\n  GetPage(\n    name: '/details',\n    page: () => DetailsView(),\n    binding: DetailsBinding(),\n  ),\n];\n```\n\n- Using normal routes:\n\n```dart\nGet.to(Home(), binding: HomeBinding());\nGet.to(DetailsView(), binding: DetailsBinding())\n```\n\nThere, you don't have to worry about memory management of your application anymore, Get will do it for you.\n\nThe 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.\n\n```dart\nGetMaterialApp(\n  initialBinding: SampleBind(),\n  home: Home(),\n);\n```\n\n### BindingsBuilder\n\nThe default way of creating a binding is by creating a class that implements Bindings.\nBut alternatively, you can use `BindingsBuilder` callback so that you can simply use a function to instantiate whatever you desire.\n\nExample:\n\n```dart\ngetPages: [\n  GetPage(\n    name: '/',\n    page: () => HomeView(),\n    binding: BindingsBuilder(() {\n      Get.lazyPut<ControllerX>(() => ControllerX());\n      Get.put<Service>(()=> Api());\n    }),\n  ),\n  GetPage(\n    name: '/details',\n    page: () => DetailsView(),\n    binding: BindingsBuilder(() {\n      Get.lazyPut<DetailsController>(() => DetailsController());\n    }),\n  ),\n];\n```\n\nThat way you can avoid to create one Binding class for each route making this even simpler.\n\nBoth ways of doing work perfectly fine and we want you to use what most suit your tastes.\n\n### SmartManagement\n\nGetX by default disposes unused controllers from memory, even if a failure occurs and a widget that uses it is not properly disposed.\nThis is what is called the `full` mode of dependency management.\nBut if you want to change the way GetX controls the disposal of classes, you have `SmartManagement` class that you can set different behaviors.\n\n#### How to change\n\nIf you want to change this config (which you usually don't need) this is the way:\n\n```dart\nvoid main () {\n  runApp(\n    GetMaterialApp(\n      smartManagement: SmartManagement.onlyBuilders //here\n      home: Home(),\n    )\n  )\n}\n```\n\n#### SmartManagement.full\n\nIt 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.\n\n#### SmartManagement.onlyBuilders\nWith this option, only controllers started in `init:` or loaded into a Binding with `Get.lazyPut()` will be disposed.\n\nIf you use `Get.put()` or `Get.putAsync()` or any other approach, SmartManagement will not have permissions to exclude this dependency.\n\nWith the default behavior, even widgets instantiated with \"Get.put\" will be removed, unlike SmartManagement.onlyBuilders.\n\n#### SmartManagement.keepFactory\n\nJust 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.\n\n### How bindings work under the hood\nBindings 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.\nThis happens so fast that the analyzer will not even be able to register it.\nWhen 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.\nFactories take up little memory, they don't hold instances, but a function with the \"shape\" of that class you want.\nThis 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.\nUse whichever is most convenient for you.\n\n## Notes\n\n- 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.\n\n- 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.\nHowever, if you work with Services or any other abstraction, I recommend using Bindings for a better organization.\n"
  },
  {
    "path": "documentation/ar_EG/route_management.md",
    "content": "- [Route Management](#route-management)\n  - [How to use](#how-to-use)\n  - [Navigation without named routes](#navigation-without-named-routes)\n  - [Navigation with named routes](#navigation-with-named-routes)\n    - [Send data to named Routes](#send-data-to-named-routes)\n    - [Dynamic urls links](#dynamic-urls-links)\n    - [Middleware](#middleware)\n  - [Navigation without context](#navigation-without-context)\n    - [SnackBars](#snackbars)\n    - [Dialogs](#dialogs)\n    - [BottomSheets](#bottomsheets)\n  - [Nested Navigation](#nested-navigation)\n\n# Route Management\n\nThis is the complete explanation of all there is to Getx when the matter is route management.\n\n## How to use\n\nAdd this to your pubspec.yaml file:\n\n```yaml\ndependencies:\n  get:\n```\n\nIf 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!\n\n```dart\nGetMaterialApp( // Before: MaterialApp(\n  home: MyHome(),\n)\n```\n\n## Navigation without named routes\n\nTo navigate to a new screen:\n\n```dart\nGet.to(NextScreen());\n```\n\nTo close snackbars, dialogs, bottomsheets, or anything you would normally close with Navigator.pop(context);\n\n```dart\nGet.back();\n```\n\nTo go to the next screen and no option to go back to the previous screen (for use in SplashScreens, login screens and etc.)\n\n```dart\nGet.off(NextScreen());\n```\n\nTo go to the next screen and cancel all previous routes (useful in shopping carts, polls, and tests)\n\n```dart\nGet.offAll(NextScreen());\n```\n\nTo navigate to the next route, and receive or update data as soon as you return from it:\n\n```dart\nvar data = await Get.to(Payment());\n```\n\non other screen, send a data for previous route:\n\n```dart\nGet.back(result: 'success');\n```\n\nAnd use it:\n\nex:\n\n```dart\nif(data == 'success') madeAnything();\n```\n\nDon't you want to learn our syntax?\nJust change the Navigator (uppercase) to navigator (lowercase), and you will have all the functions of the standard navigation, without having to use context\nExample:\n\n```dart\n\n// Default Flutter navigator\nNavigator.of(context).push(\n  context,\n  MaterialPageRoute(\n    builder: (BuildContext context) {\n      return HomePage();\n    },\n  ),\n);\n\n// Get using Flutter syntax without needing context\nnavigator.push(\n  MaterialPageRoute(\n    builder: (_) {\n      return HomePage();\n    },\n  ),\n);\n\n// Get syntax (It is much better, but you have the right to disagree)\nGet.to(HomePage());\n\n\n```\n\n## Navigation with named routes\n\n- If you prefer to navigate by namedRoutes, Get also supports this.\n\nTo navigate to nextScreen\n\n```dart\nGet.toNamed(\"/NextScreen\");\n```\n\nTo navigate and remove the previous screen from the tree.\n\n```dart\nGet.offNamed(\"/NextScreen\");\n```\n\nTo navigate and remove all previous screens from the tree.\n\n```dart\nGet.offAllNamed(\"/NextScreen\");\n```\n\nTo define routes, use GetMaterialApp:\n\n```dart\nvoid main() {\n  runApp(\n    GetMaterialApp(\n      initialRoute: '/',\n      getPages: [\n        GetPage(name: '/', page: () => MyHomePage()),\n        GetPage(name: '/second', page: () => Second()),\n        GetPage(\n          name: '/third',\n          page: () => Third(),\n          transition: Transition.zoom  \n        ),\n      ],\n    )\n  );\n}\n```\n\nTo handle navigation to non-defined routes (404 error), you can define an unknownRoute page in GetMaterialApp.\n\n```dart\nvoid main() {\n  runApp(\n    GetMaterialApp(\n      unknownRoute: GetPage(name: '/notfound', page: () => UnknownRoutePage()),\n      initialRoute: '/',\n      getPages: [\n        GetPage(name: '/', page: () => MyHomePage()),\n        GetPage(name: '/second', page: () => Second()),\n      ],\n    )\n  );\n}\n```\n\n### Send data to named Routes\n\nJust send what you want for arguments. Get accepts anything here, whether it is a String, a Map, a List, or even a class instance.\n\n```dart\nGet.toNamed(\"/NextScreen\", arguments: 'Get is the best');\n```\n\non your class or controller:\n\n```dart\nprint(Get.arguments);\n//print out: Get is the best\n```\n\n### Dynamic urls links\n\nGet 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.\n\n```dart\nGet.offAllNamed(\"/NextScreen?device=phone&id=354&name=Enzo\");\n```\n\non your controller/bloc/stateful/stateless class:\n\n```dart\nprint(Get.parameters['id']);\n// out: 354\nprint(Get.parameters['name']);\n// out: Enzo\n```\n\nYou can also receive NamedParameters with Get easily:\n\n```dart\nvoid main() {\n  runApp(\n    GetMaterialApp(\n      initialRoute: '/',\n      getPages: [\n      GetPage(\n        name: '/',\n        page: () => MyHomePage(),\n      ),\n      GetPage(\n        name: '/profile/',\n        page: () => MyProfile(),\n      ),\n       //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.\n       GetPage(\n        name: '/profile/:user',\n        page: () => UserProfile(),\n      ),\n      GetPage(\n        name: '/third',\n        page: () => Third(),\n        transition: Transition.cupertino  \n      ),\n     ],\n    )\n  );\n}\n```\n\nSend data on route name\n\n```dart\nGet.toNamed(\"/profile/34954\");\n```\n\nOn second screen take the data by parameter\n\n```dart\nprint(Get.parameters['user']);\n// out: 34954\n```\n\nor send multiple parameters like this\n\n```dart\nGet.toNamed(\"/profile/34954?flag=true&country=italy\");\n```\nor\n```dart\nvar parameters = <String, String>{\"flag\": \"true\",\"country\": \"italy\",};\nGet.toNamed(\"/profile/34954\", parameters: parameters);\n```\n\nOn second screen take the data by parameters as usually\n\n```dart\nprint(Get.parameters['user']);\nprint(Get.parameters['flag']);\nprint(Get.parameters['country']);\n// out: 34954 true italy\n```\n\n\n\nAnd 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\n\n### Middleware\n\nIf you want to listen Get events to trigger actions, you can to use routingCallback to it\n\n```dart\nGetMaterialApp(\n  routingCallback: (routing) {\n    if(routing.current == '/second'){\n      openAds();\n    }\n  }\n)\n```\n\nIf you are not using GetMaterialApp, you can use the manual API to attach Middleware observer.\n\n```dart\nvoid main() {\n  runApp(\n    MaterialApp(\n      onGenerateRoute: Router.generateRoute,\n      initialRoute: \"/\",\n      navigatorKey: Get.key,\n      navigatorObservers: [\n        GetObserver(MiddleWare.observer), // HERE !!!\n      ],\n    ),\n  );\n}\n```\n\nCreate a MiddleWare class\n\n```dart\nclass MiddleWare {\n  static observer(Routing routing) {\n    /// You can listen in addition to the routes, the snackbars, dialogs and bottomsheets on each screen.\n    ///If you need to enter any of these 3 events directly here,\n    ///you must specify that the event is != Than you are trying to do.\n    if (routing.current == '/second' && !routing.isSnackbar) {\n      Get.snackbar(\"Hi\", \"You are on second route\");\n    } else if (routing.current =='/third'){\n      print('last route called');\n    }\n  }\n}\n```\n\nNow, use Get on your code:\n\n```dart\nclass First extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        leading: IconButton(\n          icon: Icon(Icons.add),\n          onPressed: () {\n            Get.snackbar(\"hi\", \"i am a modern snackbar\");\n          },\n        ),\n        title: Text('First Route'),\n      ),\n      body: Center(\n        child: ElevatedButton(\n          child: Text('Open route'),\n          onPressed: () {\n            Get.toNamed(\"/second\");\n          },\n        ),\n      ),\n    );\n  }\n}\n\nclass Second extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        leading: IconButton(\n          icon: Icon(Icons.add),\n          onPressed: () {\n            Get.snackbar(\"hi\", \"i am a modern snackbar\");\n          },\n        ),\n        title: Text('second Route'),\n      ),\n      body: Center(\n        child: ElevatedButton(\n          child: Text('Open route'),\n          onPressed: () {\n            Get.toNamed(\"/third\");\n          },\n        ),\n      ),\n    );\n  }\n}\n\nclass Third extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: Text(\"Third Route\"),\n      ),\n      body: Center(\n        child: ElevatedButton(\n          onPressed: () {\n            Get.back();\n          },\n          child: Text('Go back!'),\n        ),\n      ),\n    );\n  }\n}\n```\n\n## Navigation without context\n\n### SnackBars\n\nTo have a simple SnackBar with Flutter, you must get the context of Scaffold, or you must use a GlobalKey attached to your Scaffold\n\n```dart\nfinal snackBar = SnackBar(\n  content: Text('Hi!'),\n  action: SnackBarAction(\n    label: 'I am a old and ugly snackbar :(',\n    onPressed: (){}\n  ),\n);\n// Find the Scaffold in the widget tree and use\n// it to show a SnackBar.\nScaffold.of(context).showSnackBar(snackBar);\n```\n\nWith Get:\n\n```dart\nGet.snackbar('Hi', 'i am a modern snackbar');\n```\n\nWith Get, all you have to do is call your Get.snackbar from anywhere in your code or customize it however you want!\n\n```dart\nGet.snackbar(\n  \"Hey i'm a Get SnackBar!\", // title\n  \"It's unbelievable! I'm using SnackBar without context, without boilerplate, without Scaffold, it is something truly amazing!\", // message\n  icon: Icon(Icons.alarm),\n  shouldIconPulse: true,\n  onTap:(){},\n  barBlur: 20,\n  isDismissible: true,\n  duration: Duration(seconds: 3),\n);\n\n\n  ////////// ALL FEATURES //////////\n  //     Color colorText,\n  //     Duration duration,\n  //     SnackPosition snackPosition,\n  //     Widget titleText,\n  //     Widget messageText,\n  //     bool instantInit,\n  //     Widget icon,\n  //     bool shouldIconPulse,\n  //     double maxWidth,\n  //     EdgeInsets margin,\n  //     EdgeInsets padding,\n  //     double borderRadius,\n  //     Color borderColor,\n  //     double borderWidth,\n  //     Color backgroundColor,\n  //     Color leftBarIndicatorColor,\n  //     List<BoxShadow> boxShadows,\n  //     Gradient backgroundGradient,\n  //     TextButton mainButton,\n  //     OnTap onTap,\n  //     bool isDismissible,\n  //     bool showProgressIndicator,\n  //     AnimationController progressIndicatorController,\n  //     Color progressIndicatorBackgroundColor,\n  //     Animation<Color> progressIndicatorValueColor,\n  //     SnackStyle snackStyle,\n  //     Curve forwardAnimationCurve,\n  //     Curve reverseAnimationCurve,\n  //     Duration animationDuration,\n  //     double barBlur,\n  //     double overlayBlur,\n  //     Color overlayColor,\n  //     Form userInputForm\n  ///////////////////////////////////\n```\n\nIf 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\n`Get.rawSnackbar();` which provides the RAW API on which Get.snackbar was built.\n\n### Dialogs\n\nTo open dialog:\n\n```dart\nGet.dialog(YourDialogWidget());\n```\n\nTo open default dialog:\n\n```dart\nGet.defaultDialog(\n  onConfirm: () => print(\"Ok\"),\n  middleText: \"Dialog made in 3 lines of code\"\n);\n```\n\nYou can also use Get.generalDialog instead of showGeneralDialog.\n\nFor all other Flutter dialog widgets, including cupertinos, you can use Get.overlayContext instead of context, and open it anywhere in your code.\nFor widgets that don't use Overlay, you can use Get.context.\nThese 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.\n\n### BottomSheets\n\nGet.bottomSheet is like showModalBottomSheet, but don't need of context.\n\n```dart\nGet.bottomSheet(\n  Container(\n    child: Wrap(\n      children: <Widget>[\n        ListTile(\n          leading: Icon(Icons.music_note),\n          title: Text('Music'),\n          onTap: () {}\n        ),\n        ListTile(\n          leading: Icon(Icons.videocam),\n          title: Text('Video'),\n          onTap: () {},\n        ),\n      ],\n    ),\n  )\n);\n```\n\n## Nested Navigation\n\nGet made Flutter's nested navigation even easier.\nYou don't need the context, and you will find your navigation stack by Id.\n\n- 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.\n\nSee how simple it is:\n\n```dart\nNavigator(\n  key: Get.nestedKey(1), // create a key by index\n  initialRoute: '/',\n  onGenerateRoute: (settings) {\n    if (settings.name == '/') {\n      return GetPageRoute(\n        page: () => Scaffold(\n          appBar: AppBar(\n            title: Text(\"Main\"),\n          ),\n          body: Center(\n            child: TextButton(\n              color: Colors.blue,\n              onPressed: () {\n                Get.toNamed('/second', id:1); // navigate by your nested route by index\n              },\n              child: Text(\"Go to second\"),\n            ),\n          ),\n        ),\n      );\n    } else if (settings.name == '/second') {\n      return GetPageRoute(\n        page: () => Center(\n          child: Scaffold(\n            appBar: AppBar(\n              title: Text(\"Main\"),\n            ),\n            body: Center(\n              child:  Text(\"second\")\n            ),\n          ),\n        ),\n      );\n    }\n  }\n),\n```\n"
  },
  {
    "path": "documentation/ar_EG/state_management.md",
    "content": "* [State Management](#state-management)\n  + [Reactive State Manager](#reactive-state-manager)\n    - [Advantages](#advantages)\n    - [Maximum performance:](#maximum-performance)\n    - [Declaring a reactive variable](#declaring-a-reactive-variable)\n        - [Having a reactive state, is easy.](#having-a-reactive-state-is-easy)\n    - [Using the values in the view](#using-the-values-in-the-view)\n    - [Conditions to rebuild](#conditions-to-rebuild)\n    - [Where .obs can be used](#where-obs-can-be-used)\n    - [Note about Lists](#note-about-lists)\n    - [Why i have to use .value](#why-i-have-to-use-value)\n    - [Obx()](#obx)\n    - [Workers](#workers)\n  + [Simple State Manager](#simple-state-manager)\n    - [Advantages](#advantages-1)\n    - [Usage](#usage)\n    - [How it handles controllers](#how-it-handles-controllers)\n    - [You won't need StatefulWidgets anymore](#you-wont-need-statefulwidgets-anymore)\n    - [Why it exists](#why-it-exists)\n    - [Other ways of using it](#other-ways-of-using-it)\n    - [Unique IDs](#unique-ids)\n  + [Mixing the two state managers](#mixing-the-two-state-managers)\n  + [GetBuilder vs GetX vs Obx vs MixinBuilder](#getbuilder-vs-getx-vs-obx-vs-mixinbuilder)\n\n# State Management\n\nGetX does not use Streams or ChangeNotifier like other state managers. Why? In addition to building applications for android, iOS, web, linux, 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.\n\n* _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.\n* _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.\n\nWith GetX everything is reactive, and nothing depends on code generators, increasing your productivity in all aspects of your development.\n\n* _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.\n* _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.\n\nWith 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.\n\n* _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.\n\nMost (if not all) current state managers will rebuild on the screen.\n\n## Reactive State Manager\n\nReactive programming can alienate many people because it is said to be complicated. GetX turns reactive programming into something quite simple:\n\n* You won't need to create StreamControllers.\n* You won't need to create a StreamBuilder for each variable\n* You will not need to create a class for each state.\n* You will not need to create a get for an initial value.\n\nReactive programming with Get is as easy as using setState.\n\nLet's imagine that you have a name variable and want that every time you change it, all widgets that use it are automatically changed.\n\nThis is your count variable:\n\n``` dart\nvar name = 'Jonatas Borges';\n```\n\nTo make it observable, you just need to add \".obs\" to the end of it:\n\n``` dart\nvar name = 'Jonatas Borges'.obs;\n```\n\nThat's all. It's *that* simple.\n\nFrom now on, we might refer to this reactive-\".obs\"(ervables) variables as _Rx_.   \n\nWhat 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. \n\nThis is the **magic of GetX**, thanks to Dart's capabilities.\n\nBut, 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\". \n\nYou 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?\n\nNo, you don't need a `StreamBuilder` , but you are right about static classes.\n\nWell, in the view, we usually have a lot of boilerplate when we want to change a specific Widget, that's the Flutter way. \nWith **GetX** you can also forget about this boilerplate code. \n\n`StreamBuilder( … )` ? `initialValue: …` ? `builder: …` ? Nope, you just need to place this variable inside an `Obx()` Widget.\n\n``` dart\nObx (() => Text (controller.name));\n```\n\n_What do you need to memorize?_  Only `Obx(() =>` . \n\nYou are just passing that Widget through an arrow-function into an `Obx()` (the \"Observer\" of the _Rx_). \n\n`Obx` is pretty smart, and will only change if the value of `controller.name` changes. \n\nIf `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?**\n\n> So, what if I have 5 _Rx_ (observable) variables within an `Obx` ?\n\nIt will just update when **any** of them changes. \n\n> And if I have 30 variables in a class, when I update one, will it update **all** the variables that are in that class?\n\nNope, just the **specific Widget** that uses that _Rx_ variable.\n\nSo, **GetX** only updates the screen, when the _Rx_ variable changes it's value.\n\n``` \n\nfinal isOpen = false.obs;\n\n// NOTHING will happen... same value.\nvoid onButtonTap() => isOpen.value=false;\n```\n\n### Advantages\n\n**GetX()** helps you when you need **granular** control over what's being updated.\n\nIf you do not need `unique IDs` , because all your variables will be modified when you perform an action, then use `GetBuilder` , \nbecause it's a Simple State Updater (in blocks, like `setState()` ), made in just a few lines of code.\nIt 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.\n\nIf you need a **powerful** State Manager, you can't go wrong with **GetX**.\n\nIt doesn't work with variables, but __flows__, everything in it are `Streams` under the hood. \n\nYou can use _rxDart_ in conjunction with it, because everything are `Streams`, \nyou can listen to the `event` of each \"_Rx_ variable\", \nbecause everything in it are `Streams`. \n\nIt is literally a _BLoC_ approach, easier than _MobX_, and without code generators or decorations.\nYou can turn **anything** into an _\"Observable\"_ with just a `.obs` .\n\n### Maximum performance:\n\nIn addition to having a smart algorithm for minimal rebuilds, **GetX** uses comparators \nto make sure the State has changed. \n\nIf you experience any errors in your app, and send a duplicate change of State, \n**GetX** will ensure it will not crash.\n\nWith **GetX** the State only changes if the `value` change. \nThat's the main difference between **GetX**, and using _ `computed` from MobX_. \nWhen joining two __observables__, and one changes; the listener of that _observable_ will change as well.\n\nWith **GetX**, if you join two variables, `GetX()` (similar to `Observer()` ) will only rebuild if it implies a real change of State.\n\n### Declaring a reactive variable\n\nYou have 3 ways to turn a variable into an \"observable\".\n\n1 - The first is using **`Rx{Type}`**.\n\n``` dart\n// initial value is recommended, but not mandatory\nfinal name = RxString('');\nfinal isLogged = RxBool(false);\nfinal count = RxInt(0);\nfinal balance = RxDouble(0.0);\nfinal items = RxList<String>([]);\nfinal myMap = RxMap<String, int>({});\n```\n\n2 - The second is to use **`Rx`** and use Darts Generics, `Rx<Type>`\n\n``` dart\nfinal name = Rx<String>('');\nfinal isLogged = Rx<Bool>(false);\nfinal count = Rx<Int>(0);\nfinal balance = Rx<Double>(0.0);\nfinal number = Rx<Num>(0);\nfinal items = Rx<List<String>>([]);\nfinal myMap = Rx<Map<String, int>>({});\n\n// Custom classes - it can be any class, literally\nfinal user = Rx<User>();\n```\n\n3 - The third, more practical, easier and preferred approach, just add **`.obs`** as a property of your `value` :\n\n``` dart\nfinal name = ''.obs;\nfinal isLogged = false.obs;\nfinal count = 0.obs;\nfinal balance = 0.0.obs;\nfinal number = 0.obs;\nfinal items = <String>[].obs;\nfinal myMap = <String, int>{}.obs;\n\n// Custom classes - it can be any class, literally\nfinal user = User().obs;\n```\n\n##### Having a reactive state, is easy.\n\nAs we know, _Dart_ is now heading towards _null safety_.\nTo be prepared, from now on, you should always start your _Rx_ variables with an **initial value**.\n\n> Transforming a variable into an _observable_ + _initial value_ with **GetX** is the simplest, and most practical approach.\n\nYou will literally add a \" `.obs` \" to the end of your variable, and **that’s it**, you’ve made it observable, \nand its `.value` , well, will be the _initial value_).\n\n### Using the values in the view\n\n``` dart\n// controller file\nfinal count1 = 0.obs;\nfinal count2 = 0.obs;\nint get sum => count1.value + count2.value;\n```\n\n``` dart\n// view file\nGetX<Controller>(\n  builder: (controller) {\n    print(\"count 1 rebuild\");\n    return Text('${controller.count1.value}');\n  },\n),\nGetX<Controller>(\n  builder: (controller) {\n    print(\"count 2 rebuild\");\n    return Text('${controller.count2.value}');\n  },\n),\nGetX<Controller>(\n  builder: (controller) {\n    print(\"count 3 rebuild\");\n    return Text('${controller.sum}');\n  },\n),\n```\n\nIf we increment `count1.value++` , it will print:\n\n* `count 1 rebuild`\n\n* `count 3 rebuild`\n\nbecause `count1` has a value of `1` , and `1 + 0 = 1` , changing the `sum` getter value.\n\nIf we change `count2.value++` , it will print:\n\n* `count 2 rebuild`\n\n* `count 3 rebuild`\n\nbecause `count2.value` changed, and the result of the `sum` is now `2` .\n\n* NOTE: By default, the very first event will rebuild the widget, even if it is the same `value`.\n\n This behavior exists due to Boolean variables.\n\nImagine you did this:\n\n``` dart\nvar isLogged = false.obs;\n```\n\nAnd then, you checked if a user is \"logged in\" to trigger an event in `ever` .\n\n``` dart\n@override\nonInit() async {\n  ever(isLogged, fireRoute);\n  isLogged.value = await Preferences.hasToken();\n}\n\nfireRoute(logged) {\n  if (logged) {\n   Get.off(Home());\n  } else {\n   Get.off(Login());\n  }\n}\n```\n\nif `hasToken` was `false` , there would be no change to `isLogged` , so `ever()` would never be called.\nTo avoid this type of behavior, the first change to an _observable_ will always trigger an event, \neven if it contains the same `.value` .\n\nYou can remove this behavior if you want, using:\n `isLogged.firstRebuild = false;`\n\n### Conditions to rebuild\n\nIn addition, Get provides refined state control. You can condition an event (such as adding an object to a list), on a certain condition.\n\n``` dart\n// First parameter: condition, must return true or false.\n// Second parameter: the new value to apply if the condition is true.\nlist.addIf(item < limit, item);\n```\n\nWithout decorations, without a code generator, without complications :smile:\n\nDo you know Flutter's counter app? Your Controller class might look like this:\n\n``` dart\nclass CountController extends GetxController {\n  final count = 0.obs;\n}\n```\n\nWith a simple:\n\n``` dart\ncontroller.count.value++\n```\n\nYou could update the counter variable in your UI, regardless of where it is stored.\n\n### Where .obs can be used\n\nYou can transform anything on obs. Here are two ways of doing it:\n\n* You can convert your class values to obs\n\n``` dart\nclass RxUser {\n  final name = \"Camila\".obs;\n  final age = 18.obs;\n}\n```\n\n* or you can convert the entire class to be an observable\n\n``` dart\nclass User {\n  User({String name, int age});\n  var name;\n  var age;\n}\n\n// when instantianting:\nfinal user = User(name: \"Camila\", age: 18).obs;\n```\n\n### Note about Lists\n\nLists 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.\n\nYou also don't need to use \".value\" with lists, the amazing dart api allowed us to remove that.\nUnfortunaly 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.\n\n``` dart\n// On the controller\nfinal String title = 'User Info:'.obs\nfinal list = List<User>().obs;\n\n// on the view\nText(controller.title.value), // String need to have .value in front of it\nListView.builder (\n  itemCount: controller.list.length // lists don't need it\n)\n```\n\nWhen you are making your own classes observable, there is a different way to update them:\n\n``` dart\n// on the model file\n// we are going to make the entire class observable instead of each attribute\nclass User() {\n  User({this.name = '', this.age = 0});\n  String name;\n  int age;\n}\n\n// on the controller file\nfinal user = User().obs;\n// when you need to update the user variable:\nuser.update( (user) { // this parameter is the class itself that you want to update\nuser.name = 'Jonny';\nuser.age = 18;\n});\n// an alternative way of update the user variable:\nuser(User(name: 'João', age: 35));\n\n// on view:\nObx(()=> Text(\"Name ${user.value.name}: Age: ${user.value.age}\"))\n// you can also access the model values without the .value:\nuser().name; // notice that is the user variable, not the class (variable has lowercase u)\n```\n\nYou don't have to work with sets if you don't want to. you can use the \"assign 'and\" assignAll \"api.\nThe \"assign\" api will clear your list, and add a single object that you want to start there.\nThe \"assignAll\" api will clear the existing list and add any iterable objects that you inject into it.\n\n### Why i have to use .value\n\nWe 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.\n\nYou 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.\n\nThe 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.\n\nIf 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.\n\nIf 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.\n\nObviously, 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.\n\n### Obx()\n\nTyping 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.\nObviously, 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<Controller>()` .value or Controller.to.value to retrieve the value.\n\n### Workers\n\nWorkers will assist you, triggering specific callbacks when an event occurs.\n\n``` dart\n/// Called every time `count1` changes.\never(count1, (_) => print(\"$_ has been changed\"));\n\n/// Called only first time the variable $_ is changed\nonce(count1, (_) => print(\"$_ was changed once\"));\n\n/// Anti DDos - Called every time the user stops typing for 1 second, for example.\ndebounce(count1, (_) => print(\"debouce$_\"), time: Duration(seconds: 1));\n\n/// Ignore all changes within 1 second.\ninterval(count1, (_) => print(\"interval $_\"), time: Duration(seconds: 1));\n```\n\nAll workers (except `debounce` ) have a `condition` named parameter, which can be a `bool` or a callback that returns a `bool` .\nThis `condition` defines when the `callback` function executes.\n\nAll workers returns a `Worker` instance, that you can use to cancel ( via `dispose()` ) the worker.\n \n\n* **`ever`**\n\n is called every time the _Rx_ variable emits a new value.\n\n* **`everAll`**\n\n Much like `ever` , but it takes a `List` of _Rx_ values Called every time its variable is changed. That's it.\n\n* **`once`**\n\n'once' is called only the first time the variable has been changed.\n\n* **`debounce`**\n\n'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.\n\n* **`interval`**\n\n'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 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.\n\n* 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).\n\n## Simple State Manager\n\nGet 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.\n\nGetBuilder 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.\n\nThat 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.\n\n### Advantages\n\n1. Update only the required widgets.\n\n2. Does not use changeNotifier, it is the state manager that uses less memory (close to 0mb).\n\n3. 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.\n\n4. Organize your project for real! Controllers must not be in your UI, place your TextEditController, or any controller you use within your Controller class.\n\n5. 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.\n\n6. 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.\n\n7. 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).\n\n8. 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.\n\n9. 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.\n\n### Usage\n\n``` dart\n// Create controller class and extends GetxController\nclass Controller extends GetxController {\n  int counter = 0;\n  void increment() {\n    counter++;\n    update(); // use update() to update counter variable on UI when increment be called\n  }\n}\n// On your Stateless/Stateful class, use GetBuilder to update Text when increment be called\nGetBuilder<Controller>(\n  init: Controller(), // INIT IT ONLY THE FIRST TIME\n  builder: (_) => Text(\n    '${_.counter}',\n  ),\n)\n//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.\n```\n\n**Done!**\n\n* You have already learned how to manage states with Get.\n\n* 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.\n\nIf you navigate many routes and need data that was in your previously used controller, you just need to use GetBuilder Again (with no init):\n\n``` dart\nclass OtherClass extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      body: Center(\n        child: GetBuilder<Controller>(\n          builder: (s) => Text('${s.counter}'),\n        ),\n      ),\n    );\n  }\n\n```\n\nIf 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<Controller>()` )\n\n``` dart\nclass Controller extends GetxController {\n\n  /// You do not need that. I recommend using it just for ease of syntax.\n  /// with static method: Controller.to.increment();\n  /// with no static method: Get.find<Controller>().increment();\n  /// 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.\n  static Controller get to => Get.find(); // add this line\n\n  int counter = 0;\n  void increment() {\n    counter++;\n    update();\n  }\n}\n```\n\nAnd then you can access your controller directly, that way:\n\n``` dart\nFloatingActionButton(\n  onPressed: () {\n    Controller.to.increment(),\n  } // This is incredibly simple!\n  child: Text(\"${Controller.to.counter}\"),\n),\n```\n\nWhen you press FloatingActionButton, all widgets that are listening to the 'counter' variable will be updated automatically.\n\n### How it handles controllers\n\nLet's say we have this:\n\n `Class a => Class B (has controller X) => Class C (has controller X)`\n\nIn 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.\n\n### You won't need StatefulWidgets anymore\n\nUsing 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.\nThe 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!\nUnless you need to use a mixin, like TickerProviderStateMixin, it will be totally unnecessary to use a StatefulWidget with Get.\n\nYou can call all methods of a StatefulWidget directly from a GetBuilder.\nIf you need to call initState() or dispose() method for example, you can call them directly;\n\n``` dart\nGetBuilder<Controller>(\n  initState: (_) => Controller.to.fetchApi(),\n  dispose: (_) => Controller.to.closeStreams(),\n  builder: (s) => Text('${s.username}'),\n),\n```\n\nA much better approach than this is to use the onInit() and onClose() method directly from your controller.\n\n``` dart\n@override\nvoid onInit() {\n  fetchApi();\n  super.onInit();\n}\n```\n\n* 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.\n\n### Why it exists\n\nThe 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.\n\nSo to simplify this:\nYou 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.\nYou 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.\n\nDo 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:\n\n``` dart\nclass Controller extends GetxController {\n  StreamController<User> user = StreamController<User>();\n  StreamController<String> name = StreamController<String>();\n\n  /// close stream = onClose method, not dispose.\n  @override\n  void onClose() {\n    user.close();\n    name.close();\n    super.onClose();\n  }\n}\n```\n\nController life cycle:\n\n* onInit() where it is created.\n* onClose() where it is closed to make any changes in preparation for the delete method\n* 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.\n\n### Other ways of using it\n\nYou can use Controller instance directly on GetBuilder value:\n\n``` dart\nGetBuilder<Controller>(\n  init: Controller(),\n  builder: (value) => Text(\n    '${value.counter}', //here\n  ),\n),\n```\n\nYou may also need an instance of your controller outside of your GetBuilder, and you can use these approaches to achieve this:\n\n``` dart\nclass Controller extends GetxController {\n  static Controller get to => Get.find();\n[...]\n}\n// on you view:\nGetBuilder<Controller>(  \n  init: Controller(), // use it only first time on each controller\n  builder: (_) => Text(\n    '${Controller.to.counter}', //here\n  )\n),\n```\n\nor\n\n``` dart\nclass Controller extends GetxController {\n // static Controller get to => Get.find(); // with no static get\n[...]\n}\n// on stateful/stateless class\nGetBuilder<Controller>(  \n  init: Controller(), // use it only first time on each controller\n  builder: (_) => Text(\n    '${Get.find<Controller>().counter}', //here\n  ),\n),\n```\n\n* 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:\n\n``` dart\nController controller = Controller();\n[...]\nGetBuilder<Controller>(\n  init: controller, //here\n  builder: (_) => Text(\n    '${controller.counter}', // here\n  ),\n),\n\n```\n\n### Unique IDs\n\nIf you want to refine a widget's update control with GetBuilder, you can assign them unique IDs:\n\n``` dart\nGetBuilder<Controller>(\n  id: 'text'\n  init: Controller(), // use it only first time on each controller\n  builder: (_) => Text(\n    '${Get.find<Controller>().counter}', //here\n  ),\n),\n```\n\nAnd update it this form:\n\n``` dart\nupdate(['text']);\n```\n\nYou can also impose conditions for the update:\n\n``` dart\nupdate(['text'], counter < 10);\n```\n\nGetX 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).\n\n## Mixing the two state managers\n\nSome 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.\n\nExtending 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.\n\n## StateMixin\n\nAnother way to handle your `UI` state is use the `StateMixin<T>` .\nTo implement it, use the `with` to add the `StateMixin<T>`\nto your controller which allows a T model.\n\n``` dart\nclass Controller extends GetController with StateMixin<User>{}\n```\n\nThe `change()` method change the State whenever we want.\nJust pass the data and the status in this way:\n\n```dart\nchange(data, status: RxStatus.success());\n```\n\nRxStatus allow these status:\n\n``` dart\nRxStatus.loading();\nRxStatus.success();\nRxStatus.empty();\nRxStatus.error('message');\n```\n\nTo represent it in the UI, use:\n\n```dart\nclass OtherClass extends GetView<Controller> {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n\n      body: controller.obx(\n        (state)=>Text(state.name),\n        \n        // here you can put your custom loading indicator, but\n        // by default would be Center(child:CircularProgressIndicator())\n        onLoading: CustomLoadingIndicator(),\n        onEmpty: Text('No data found'),\n\n        // here also you can set your own error widget, but by\n        // default will be an Center(child:Text(error))\n        onError: (error)=>Text(error),\n      ),\n    );\n}\n```\n\n## GetBuilder vs GetX vs Obx vs MixinBuilder\n\nIn a decade working with programming I was able to learn some valuable lessons.\n\nMy first contact with reactive programming was so \"wow, this is incredible\" and in fact reactive programming is incredible.\nHowever, 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.\n\nReactive 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.\n\nWith 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.\n\nGetBuilder 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).\n\nHowever, GetBuilder is still a mechanical state manager, you need to call update() just like you would need to call Provider's notifyListeners().\n\nThere 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.\n\nGetX 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.\n"
  },
  {
    "path": "documentation/en_US/dependency_management.md",
    "content": "# Dependency Management\n- [Dependency Management](#dependency-management)\n  - [Instancing methods](#instancing-methods)\n    - [Get.put()](#getput)\n    - [Get.lazyPut](#getlazyput)\n    - [Get.putAsync](#getputasync)\n    - [Get.create](#getcreate)\n  - [Using instantiated methods/classes](#using-instantiated-methodsclasses)\n  - [Specifying an alternate instance](#specifying-an-alternate-instance)\n  - [Differences between methods](#differences-between-methods)\n  - [Bindings](#bindings)\n    - [Bindings class](#bindings-class)\n    - [BindingsBuilder](#bindingsbuilder)\n    - [SmartManagement](#smartmanagement)\n      - [How to change](#how-to-change)\n      - [SmartManagement.full](#smartmanagementfull)\n      - [SmartManagement.onlyBuilder](#smartmanagementonlybuilder)\n      - [SmartManagement.keepFactory](#smartmanagementkeepfactory)\n    - [How bindings work under the hood](#how-bindings-work-under-the-hood)\n  - [Notes](#notes)\n\nGet 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:\n\n```dart\nController controller = Get.put(Controller()); // Rather Controller controller = Controller();\n```\n\nInstead 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.\nSo you can use your controller (or Bloc class) normally\n\n- 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.\n- 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\n\n## Instancing methods\nThe methods and it's configurable parameters are:\n\n### Get.put()\n\nThe most common way of inserting a dependency. Good for the controllers of your views for example.\n\n```dart\nGet.put<SomeClass>(SomeClass());\nGet.put<LoginController>(LoginController(), permanent: true);\nGet.put<ListItemController>(ListItemController, tag: \"some unique string\");\n```\n\nThis is all options you can set when using put:\n```dart\nGet.put<S>(\n  // mandatory: the class that you want to get to save, like a controller or anything\n  // note: \"S\" means that it can be a class of any type\n  S dependency\n\n  // optional: this is for when you want multiple classess that are of the same type\n  // since you normally get a class by using Get.find<Controller>(),\n  // you need to use tag to tell which instance you need\n  // must be unique string\n  String tag,\n\n  // optional: by default, get will dispose instances after they are not used anymore (example,\n  // the controller of a view that is closed), but you might need that the instance\n  // to be kept there throughout the entire app, like an instance of sharedPreferences or something\n  // so you use this\n  // defaults to false\n  bool permanent = false,\n\n  // optional: allows you after using an abstract class in a test, replace it with another one and follow the test.\n  // defaults to false\n  bool overrideAbstract = false,\n\n  // optional: allows you to create the dependency using function instead of the dependency itself.\n  // this one is not commonly used\n  InstanceBuilderCallback<S> builder,\n)\n```\n\n### Get.lazyPut\nIt 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.\n\n```dart\n/// ApiMock will only be called when someone uses Get.find<ApiMock> for the first time\nGet.lazyPut<ApiMock>(() => ApiMock());\n\nGet.lazyPut<FirebaseAuth>(\n  () {\n    // ... some logic if needed\n    return FirebaseAuth();\n  },\n  tag: Math.random().toString(),\n  fenix: true\n)\n\nGet.lazyPut<Controller>( () => Controller() )\n```\n\nThis is all options you can set when using lazyPut:\n```dart\nGet.lazyPut<S>(\n  // mandatory: a method that will be executed when your class is called for the first time\n  InstanceBuilderCallback builder,\n  \n  // optional: same as Get.put(), it is used for when you want multiple different instance of a same class\n  // must be unique\n  String tag,\n\n  // optional: It is similar to \"permanent\", the difference is that the instance is discarded when\n  // is not being used, but when it's use is needed again, Get will recreate the instance\n  // just the same as \"SmartManagement.keepFactory\" in the bindings api\n  // defaults to false\n  bool fenix = false\n  \n)\n```\n\n### Get.putAsync\nIf you want to register an asynchronous instance, you can use `Get.putAsync`:\n\n```dart\nGet.putAsync<SharedPreferences>(() async {\n  final prefs = await SharedPreferences.getInstance();\n  await prefs.setInt('counter', 12345);\n  return prefs;\n});\n\nGet.putAsync<YourAsyncClass>( () async => await YourAsyncClass() )\n```\n\nThis is all options you can set when using putAsync:\n```dart\nGet.putAsync<S>(\n\n  // mandatory: an async method that will be executed to instantiate your class\n  AsyncInstanceBuilderCallback<S> builder,\n\n  // optional: same as Get.put(), it is used for when you want multiple different instance of a same class\n  // must be unique\n  String tag,\n\n  // optional: same as in Get.put(), used when you need to maintain that instance alive in the entire app\n  // defaults to false\n  bool permanent = false\n)\n```\n\n### Get.create\n\nThis 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\n\n```dart\nGet.Create<SomeClass>(() => SomeClass());\nGet.Create<LoginController>(() => LoginController());\n```\n\nThis is all options you can set when using create:\n\n```dart\nGet.create<S>(\n  // required: a function that returns a class that will be \"fabricated\" every\n  // time `Get.find()` is called\n  // Example: Get.create<YourClass>(() => YourClass())\n  FcBuilderFunc<S> builder,\n\n  // optional: just like Get.put(), but it is used when you need multiple instances\n  // of a of a same class\n  // Useful in case you have a list that each item need it's own controller\n  // needs to be a unique string. Just change from tag to name\n  String name,\n\n  // optional: just like int`Get.put()`, it is for when you need to keep the\n  // instance alive thoughout the entire app. The difference is in Get.create\n  // permanent is true by default\n  bool permanent = true\n```\n\n## Using instantiated methods/classes\n\nImagine 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:\n\n```dart\nfinal controller = Get.find<Controller>();\n// OR\nController controller = Get.find();\n\n// Yes, it looks like Magic, Get will find your controller, and will deliver it to you.\n// You can have 1 million controllers instantiated, Get will always give you the right controller.\n```\n\nAnd then you will be able to recover your controller data that was obtained back there:\n\n```dart\nText(controller.textFromApi);\n```\n\nSince the returned value is a normal class, you can do anything you want:\n```dart\nint count = Get.find<SharedPreferences>().getInt('counter');\nprint(count); // out: 12345\n```\n\nTo remove an instance of Get:\n\n```dart\nGet.delete<Controller>(); //usually you don't need to do this because GetX already delete unused controllers\n```\n\n## Specifying an alternate instance\n\nA 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.\n\n```dart\nabstract class BaseClass {}\nclass ParentClass extends BaseClass {}\n\nclass ChildClass extends ParentClass {\n  bool isChild = true;\n}\n\n\nGet.put<BaseClass>(ParentClass());\n\nGet.replace<BaseClass>(ChildClass());\n\nfinal instance = Get.find<BaseClass>();\nprint(instance is ChildClass); //true\n\n\nclass OtherClass extends BaseClass {}\nGet.lazyReplace<BaseClass>(() => OtherClass());\n\nfinal instance = Get.find<BaseClass>();\nprint(instance is ChildClass); // false\nprint(instance is OtherClass); //true\n```\n\n## Differences between methods\n\nFirst, let's of the `fenix` of Get.lazyPut and the `permanent` of the other methods.\n\nThe fundamental difference between `permanent` and `fenix` is how you want to store your instances.\n\nReinforcing: by default, GetX deletes instances when they are not in use.\nIt 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.\n\nBut 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.\n\n`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.\n\nProceeding with the differences between methods:\n\n- 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.\n\n- 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.\n\n- 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.\n\n## Bindings\n\nOne of the great differentials of this package, perhaps, is the possibility of full integration of the routes, state manager and dependency manager.\nWhen 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.\nIn version 2.10 Get completely implemented the Bindings API.\nNow 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.\nThe Binding class is a class that will decouple dependency injection, while \"binding\" routes to the state manager and dependency manager.\nThis 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.\nIn 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.\n\n### Bindings class\n\n- Create a class and implements Binding\n\n```dart\nclass HomeBinding implements Bindings {}\n```\n\nYour 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:\n\n```dart\nclass HomeBinding implements Bindings {\n  @override\n  void dependencies() {\n    Get.lazyPut<HomeController>(() => HomeController());\n    Get.put<Service>(()=> Api());\n  }\n}\n\nclass DetailsBinding implements Bindings {\n  @override\n  void dependencies() {\n    Get.lazyPut<DetailsController>(() => DetailsController());\n  }\n}\n```\n\nNow you just need to inform your route, that you will use that binding to make the connection between route manager, dependencies and states.\n\n- Using named routes:\n\n```dart\ngetPages: [\n  GetPage(\n    name: '/',\n    page: () => HomeView(),\n    binding: HomeBinding(),\n  ),\n  GetPage(\n    name: '/details',\n    page: () => DetailsView(),\n    binding: DetailsBinding(),\n  ),\n];\n```\n\n- Using normal routes:\n\n```dart\nGet.to(Home(), binding: HomeBinding());\nGet.to(DetailsView(), binding: DetailsBinding())\n```\n\nThere, you don't have to worry about memory management of your application anymore, Get will do it for you.\n\nThe 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.\n\n```dart\nGetMaterialApp(\n  initialBinding: SampleBind(),\n  home: Home(),\n);\n```\n\n### BindingsBuilder\n\nThe default way of creating a binding is by creating a class that implements Bindings.\nBut alternatively, you can use `BindingsBuilder` callback so that you can simply use a function to instantiate whatever you desire.\n\nExample:\n\n```dart\ngetPages: [\n  GetPage(\n    name: '/',\n    page: () => HomeView(),\n    binding: BindingsBuilder(() {\n      Get.lazyPut<ControllerX>(() => ControllerX());\n      Get.put<Service>(()=> Api());\n    }),\n  ),\n  GetPage(\n    name: '/details',\n    page: () => DetailsView(),\n    binding: BindingsBuilder(() {\n      Get.lazyPut<DetailsController>(() => DetailsController());\n    }),\n  ),\n];\n```\n\nThat way you can avoid to create one Binding class for each route making this even simpler.\n\nBoth ways of doing work perfectly fine and we want you to use what most suit your tastes.\n\n### SmartManagement\n\nGetX by default disposes unused controllers from memory, even if a failure occurs and a widget that uses it is not properly disposed.\nThis is what is called the `full` mode of dependency management.\nBut if you want to change the way GetX controls the disposal of classes, you have `SmartManagement` class that you can set different behaviors.\n\n#### How to change\n\nIf you want to change this config (which you usually don't need) this is the way:\n\n```dart\nvoid main () {\n  runApp(\n    GetMaterialApp(\n      smartManagement: SmartManagement.onlyBuilder //here\n      home: Home(),\n    )\n  )\n}\n```\n\n#### SmartManagement.full\n\nIt 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.\n\n#### SmartManagement.onlyBuilder\nWith this option, only controllers started in `init:` or loaded into a Binding with `Get.lazyPut()` will be disposed.\n\nIf you use `Get.put()` or `Get.putAsync()` or any other approach, SmartManagement will not have permissions to exclude this dependency.\n\nWith the default behavior, even widgets instantiated with \"Get.put\" will be removed, unlike SmartManagement.onlyBuilder.\n\n#### SmartManagement.keepFactory\n\nJust 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.\n\n### How bindings work under the hood\nBindings 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.\nThis happens so fast that the analyzer will not even be able to register it.\nWhen 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.\nFactories take up little memory, they don't hold instances, but a function with the \"shape\" of that class you want.\nThis 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.\nUse whichever is most convenient for you.\n\n## Notes\n\n- 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.\n\n- 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.\nHowever, if you work with Services or any other abstraction, I recommend using Bindings for a better organization.\n"
  },
  {
    "path": "documentation/en_US/route_management.md",
    "content": "- [Route Management](#route-management)\n  - [How to use](#how-to-use)\n  - [Navigation without named routes](#navigation-without-named-routes)\n  - [Navigation with named routes](#navigation-with-named-routes)\n    - [Send data to named Routes](#send-data-to-named-routes)\n    - [Dynamic urls links](#dynamic-urls-links)\n    - [Middleware](#middleware)\n  - [Navigation without context](#navigation-without-context)\n    - [SnackBars](#snackbars)\n    - [Dialogs](#dialogs)\n    - [BottomSheets](#bottomsheets)\n  - [Nested Navigation](#nested-navigation)\n\n# Route Management\n\nThis is the complete explanation of all there is to Getx when the matter is route management.\n\n## How to use\n\nAdd this to your pubspec.yaml file:\n\n```yaml\ndependencies:\n  get:\n```\n\nIf 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!\n\n```dart\nGetMaterialApp( // Before: MaterialApp(\n  home: MyHome(),\n)\n```\n\n## Navigation without named routes\n\nTo navigate to a new screen:\n\n```dart\nGet.to(NextScreen());\n```\n\nTo close snackbars, dialogs, bottomsheets, or anything you would normally close with Navigator.pop(context);\n\n```dart\nGet.back();\n```\n\nTo go to the next screen and no option to go back to the previous screen (for use in SplashScreens, login screens and etc.)\n\n```dart\nGet.off(NextScreen());\n```\n\nTo go to the next screen and cancel all previous routes (useful in shopping carts, polls, and tests)\n\n```dart\nGet.offAll(NextScreen());\n```\n\nTo navigate to the next route, and receive or update data as soon as you return from it:\n\n```dart\nvar data = await Get.to(Payment());\n```\n\non other screen, send a data for previous route:\n\n```dart\nGet.back(result: 'success');\n```\n\nAnd use it:\n\nex:\n\n```dart\nif(data == 'success') madeAnything();\n```\n\nDon't you want to learn our syntax?\nJust change the Navigator (uppercase) to navigator (lowercase), and you will have all the functions of the standard navigation, without having to use context\nExample:\n\n```dart\n\n// Default Flutter navigator\nNavigator.of(context).push(\n  context,\n  MaterialPageRoute(\n    builder: (BuildContext context) {\n      return HomePage();\n    },\n  ),\n);\n\n// Get using Flutter syntax without needing context\nnavigator.push(\n  MaterialPageRoute(\n    builder: (_) {\n      return HomePage();\n    },\n  ),\n);\n\n// Get syntax (It is much better, but you have the right to disagree)\nGet.to(HomePage());\n\n\n```\n\n## Navigation with named routes\n\n- If you prefer to navigate by namedRoutes, Get also supports this.\n\nTo navigate to nextScreen\n\n```dart\nGet.toNamed(\"/NextScreen\");\n```\n\nTo navigate and remove the previous screen from the tree.\n\n```dart\nGet.offNamed(\"/NextScreen\");\n```\n\nTo navigate and remove all previous screens from the tree.\n\n```dart\nGet.offAllNamed(\"/NextScreen\");\n```\n\nTo define routes, use GetMaterialApp:\n\n```dart\nvoid main() {\n  runApp(\n    GetMaterialApp(\n      initialRoute: '/',\n      getPages: [\n        GetPage(name: '/', page: () => MyHomePage()),\n        GetPage(name: '/second', page: () => Second()),\n        GetPage(\n          name: '/third',\n          page: () => Third(),\n          transition: Transition.zoom  \n        ),\n      ],\n    )\n  );\n}\n```\n\nTo handle navigation to non-defined routes (404 error), you can define an unknownRoute page in GetMaterialApp.\n\n```dart\nvoid main() {\n  runApp(\n    GetMaterialApp(\n      unknownRoute: GetPage(name: '/notfound', page: () => UnknownRoutePage()),\n      initialRoute: '/',\n      getPages: [\n        GetPage(name: '/', page: () => MyHomePage()),\n        GetPage(name: '/second', page: () => Second()),\n      ],\n    )\n  );\n}\n```\n\n### Send data to named Routes\n\nJust send what you want for arguments. Get accepts anything here, whether it is a String, a Map, a List, or even a class instance.\n\n```dart\nGet.toNamed(\"/NextScreen\", arguments: 'Get is the best');\n```\n\non your class or controller:\n\n```dart\nprint(Get.arguments);\n//print out: Get is the best\n```\n\n### Dynamic urls links\n\nGet 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.\n\n```dart\nGet.offAllNamed(\"/NextScreen?device=phone&id=354&name=Enzo\");\n```\n\non your controller/bloc/stateful/stateless class:\n\n```dart\nprint(Get.parameters['id']);\n// out: 354\nprint(Get.parameters['name']);\n// out: Enzo\n```\n\nYou can also receive NamedParameters with Get easily:\n\n```dart\nvoid main() {\n  runApp(\n    GetMaterialApp(\n      initialRoute: '/',\n      getPages: [\n      GetPage(\n        name: '/',\n        page: () => MyHomePage(),\n      ),\n      GetPage(\n        name: '/profile/',\n        page: () => MyProfile(),\n      ),\n       //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.\n       GetPage(\n        name: '/profile/:user',\n        page: () => UserProfile(),\n      ),\n      GetPage(\n        name: '/third',\n        page: () => Third(),\n        transition: Transition.cupertino  \n      ),\n     ],\n    )\n  );\n}\n```\n\nSend data on route name\n\n```dart\nGet.toNamed(\"/profile/34954\");\n```\n\nOn second screen take the data by parameter\n\n```dart\nprint(Get.parameters['user']);\n// out: 34954\n```\n\nor send multiple parameters like this\n\n```dart\nGet.toNamed(\"/profile/34954?flag=true&country=italy\");\n```\nor\n```dart\nvar parameters = <String, String>{\"flag\": \"true\",\"country\": \"italy\",};\nGet.toNamed(\"/profile/34954\", parameters: parameters);\n```\n\nOn second screen take the data by parameters as usually\n\n```dart\nprint(Get.parameters['user']);\nprint(Get.parameters['flag']);\nprint(Get.parameters['country']);\n// out: 34954 true italy\n```\n\n\n\nAnd 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\n\n### Middleware\n\nIf you want to listen Get events to trigger actions, you can to use routingCallback to it\n\n```dart\nGetMaterialApp(\n  routingCallback: (routing) {\n    if(routing.current == '/second'){\n      openAds();\n    }\n  }\n)\n```\n\nIf you are not using GetMaterialApp, you can use the manual API to attach Middleware observer.\n\n```dart\nvoid main() {\n  runApp(\n    MaterialApp(\n      onGenerateRoute: Router.generateRoute,\n      initialRoute: \"/\",\n      navigatorKey: Get.key,\n      navigatorObservers: [\n        GetObserver(MiddleWare.observer), // HERE !!!\n      ],\n    ),\n  );\n}\n```\n\nCreate a MiddleWare class\n\n```dart\nclass MiddleWare {\n  static observer(Routing routing) {\n    /// You can listen in addition to the routes, the snackbars, dialogs and bottomsheets on each screen.\n    ///If you need to enter any of these 3 events directly here,\n    ///you must specify that the event is != Than you are trying to do.\n    if (routing.current == '/second' && !routing.isSnackbar) {\n      Get.snackbar(\"Hi\", \"You are on second route\");\n    } else if (routing.current =='/third'){\n      print('last route called');\n    }\n  }\n}\n```\n\nNow, use Get on your code:\n\n```dart\nclass First extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        leading: IconButton(\n          icon: Icon(Icons.add),\n          onPressed: () {\n            Get.snackbar(\"hi\", \"i am a modern snackbar\");\n          },\n        ),\n        title: Text('First Route'),\n      ),\n      body: Center(\n        child: ElevatedButton(\n          child: Text('Open route'),\n          onPressed: () {\n            Get.toNamed(\"/second\");\n          },\n        ),\n      ),\n    );\n  }\n}\n\nclass Second extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        leading: IconButton(\n          icon: Icon(Icons.add),\n          onPressed: () {\n            Get.snackbar(\"hi\", \"i am a modern snackbar\");\n          },\n        ),\n        title: Text('second Route'),\n      ),\n      body: Center(\n        child: ElevatedButton(\n          child: Text('Open route'),\n          onPressed: () {\n            Get.toNamed(\"/third\");\n          },\n        ),\n      ),\n    );\n  }\n}\n\nclass Third extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: Text(\"Third Route\"),\n      ),\n      body: Center(\n        child: ElevatedButton(\n          onPressed: () {\n            Get.back();\n          },\n          child: Text('Go back!'),\n        ),\n      ),\n    );\n  }\n}\n```\n\n## Navigation without context\n\n### SnackBars\n\nTo have a simple SnackBar with Flutter, you must get the context of Scaffold, or you must use a GlobalKey attached to your Scaffold\n\n```dart\nfinal snackBar = SnackBar(\n  content: Text('Hi!'),\n  action: SnackBarAction(\n    label: 'I am a old and ugly snackbar :(',\n    onPressed: (){}\n  ),\n);\n// Find the Scaffold in the widget tree and use\n// it to show a SnackBar.\nScaffold.of(context).showSnackBar(snackBar);\n```\n\nWith Get:\n\n```dart\nGet.snackbar('Hi', 'i am a modern snackbar');\n```\n\nWith Get, all you have to do is call your Get.snackbar from anywhere in your code or customize it however you want!\n\n```dart\nGet.snackbar(\n  \"Hey i'm a Get SnackBar!\", // title\n  \"It's unbelievable! I'm using SnackBar without context, without boilerplate, without Scaffold, it is something truly amazing!\", // message\n  icon: Icon(Icons.alarm),\n  shouldIconPulse: true,\n  onTap:(){},\n  barBlur: 20,\n  isDismissible: true,\n  duration: Duration(seconds: 3),\n);\n\n\n  ////////// ALL FEATURES //////////\n  //     Color colorText,\n  //     Duration duration,\n  //     SnackPosition snackPosition,\n  //     Widget titleText,\n  //     Widget messageText,\n  //     bool instantInit,\n  //     Widget icon,\n  //     bool shouldIconPulse,\n  //     double maxWidth,\n  //     EdgeInsets margin,\n  //     EdgeInsets padding,\n  //     double borderRadius,\n  //     Color borderColor,\n  //     double borderWidth,\n  //     Color backgroundColor,\n  //     Color leftBarIndicatorColor,\n  //     List<BoxShadow> boxShadows,\n  //     Gradient backgroundGradient,\n  //     TextButton mainButton,\n  //     OnTap onTap,\n  //     bool isDismissible,\n  //     bool showProgressIndicator,\n  //     AnimationController progressIndicatorController,\n  //     Color progressIndicatorBackgroundColor,\n  //     Animation<Color> progressIndicatorValueColor,\n  //     SnackStyle snackStyle,\n  //     Curve forwardAnimationCurve,\n  //     Curve reverseAnimationCurve,\n  //     Duration animationDuration,\n  //     double barBlur,\n  //     double overlayBlur,\n  //     Color overlayColor,\n  //     Form userInputForm\n  ///////////////////////////////////\n```\n\nIf 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\n`Get.rawSnackbar();` which provides the RAW API on which Get.snackbar was built.\n\n### Dialogs\n\nTo open dialog:\n\n```dart\nGet.dialog(YourDialogWidget());\n```\n\nTo open default dialog:\n\n```dart\nGet.defaultDialog(\n  onConfirm: () => print(\"Ok\"),\n  middleText: \"Dialog made in 3 lines of code\"\n);\n```\n\nTo close the dialog and return a result use `Get.closeDialog` providing the `result` to return to the awaited `Get.dialog` call.\n```dart\nWidget buttonWithResult({\n  required final String text,\n  required final bool result,\n}) => TextButton(\n          onPressed: () {\n            Get.closeDialog(result: result);\n          },\n          child: Text(text),\n        );\n\nbool? delete = await Get.dialog(\n    AlertDialog(\n      content: const Text('Are you sure you would like to delete?'),\n      actions: [\n        buttonWithResult(text: 'No', result: false),\n        buttonWithResult(text: 'Yes', result: true),\n      ],\n    ),\n  );\n\nif (delete != null && delete) {\n  // Perform the deletion\n}\n```\n\nYou can also use Get.generalDialog instead of showGeneralDialog.\n\nFor all other Flutter dialog widgets, including cupertinos, you can use Get.overlayContext instead of context, and open it anywhere in your code.\nFor widgets that don't use Overlay, you can use Get.context.\nThese 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.\n\n### BottomSheets\n\nGet.bottomSheet is like showModalBottomSheet, but don't need of context.\n\n```dart\nGet.bottomSheet(\n  Container(\n    child: Wrap(\n      children: <Widget>[\n        ListTile(\n          leading: Icon(Icons.music_note),\n          title: Text('Music'),\n          onTap: () {}\n        ),\n        ListTile(\n          leading: Icon(Icons.videocam),\n          title: Text('Video'),\n          onTap: () {},\n        ),\n      ],\n    ),\n  )\n);\n```\n\n## Nested Navigation\n\nGet made Flutter's nested navigation even easier.\nYou don't need the context, and you will find your navigation stack by Id.\n\n- 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.\n\nSee how simple it is:\n\n```dart\nNavigator(\n  key: Get.nestedKey(1), // create a key by index\n  initialRoute: '/',\n  onGenerateRoute: (settings) {\n    if (settings.name == '/') {\n      return GetPageRoute(\n        page: () => Scaffold(\n          appBar: AppBar(\n            title: Text(\"Main\"),\n          ),\n          body: Center(\n            child: TextButton(\n              color: Colors.blue,\n              onPressed: () {\n                Get.toNamed('/second', id:1); // navigate by your nested route by index\n              },\n              child: Text(\"Go to second\"),\n            ),\n          ),\n        ),\n      );\n    } else if (settings.name == '/second') {\n      return GetPageRoute(\n        page: () => Center(\n          child: Scaffold(\n            appBar: AppBar(\n              title: Text(\"Main\"),\n            ),\n            body: Center(\n              child:  Text(\"second\")\n            ),\n          ),\n        ),\n      );\n    }\n  }\n),\n```\n"
  },
  {
    "path": "documentation/en_US/state_management.md",
    "content": "* [State Management](#state-management)\n  + [Reactive State Manager](#reactive-state-manager)\n    - [Advantages](#advantages)\n    - [Maximum performance:](#maximum-performance)\n    - [Declaring a reactive variable](#declaring-a-reactive-variable)\n        - [Having a reactive state, is easy.](#having-a-reactive-state-is-easy)\n    - [Using the values in the view](#using-the-values-in-the-view)\n    - [Conditions to rebuild](#conditions-to-rebuild)\n    - [Where .obs can be used](#where-obs-can-be-used)\n    - [Note about Lists](#note-about-lists)\n    - [Why i have to use .value](#why-i-have-to-use-value)\n    - [Obx()](#obx)\n    - [Workers](#workers)\n  + [Simple State Manager](#simple-state-manager)\n    - [Advantages](#advantages-1)\n    - [Usage](#usage)\n    - [How it handles controllers](#how-it-handles-controllers)\n    - [You won't need StatefulWidgets anymore](#you-wont-need-statefulwidgets-anymore)\n    - [Why it exists](#why-it-exists)\n    - [Other ways of using it](#other-ways-of-using-it)\n    - [Unique IDs](#unique-ids)\n  + [Mixing the two state managers](#mixing-the-two-state-managers)\n  + [GetBuilder vs GetX vs Obx vs MixinBuilder](#getbuilder-vs-getx-vs-obx-vs-mixinbuilder)\n\n# State Management\n\nGetX 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.\n\n* _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.\n* _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.\n\nWith GetX everything is reactive, and nothing depends on code generators, increasing your productivity in all aspects of your development.\n\n* _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.\n* _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.\n\nWith 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.\n\n* _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.\n\nMost (if not all) current state managers will rebuild on the screen.\n\n## Reactive State Manager\n\nReactive programming can alienate many people because it is said to be complicated. GetX turns reactive programming into something quite simple:\n\n* You won't need to create StreamControllers.\n* You won't need to create a StreamBuilder for each variable\n* You will not need to create a class for each state.\n* You will not need to create a get for an initial value.\n\nReactive programming with Get is as easy as using setState.\n\nLet's imagine that you have a name variable and want that every time you change it, all widgets that use it are automatically changed.\n\nThis is your count variable:\n\n``` dart\nvar name = 'Jonatas Borges';\n```\n\nTo make it observable, you just need to add \".obs\" to the end of it:\n\n``` dart\nvar name = 'Jonatas Borges'.obs;\n```\n\nThat's all. It's *that* simple.\n\nFrom now on, we might refer to this reactive-\".obs\"(ervables) variables as _Rx_.   \n\nWhat 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. \n\nThis is the **magic of GetX**, thanks to Dart's capabilities.\n\nBut, 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\". \n\nYou 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?\n\nNo, you don't need a `StreamBuilder` , but you are right about static classes.\n\nWell, in the view, we usually have a lot of boilerplate when we want to change a specific Widget, that's the Flutter way. \nWith **GetX** you can also forget about this boilerplate code. \n\n`StreamBuilder( … )` ? `initialValue: …` ? `builder: …` ? Nope, you just need to place this variable inside an `Obx()` Widget.\n\n``` dart\nObx (() => Text (controller.name));\n```\n\n_What do you need to memorize?_  Only `Obx(() =>` . \n\nYou are just passing that Widget through an arrow-function into an `Obx()` (the \"Observer\" of the _Rx_). \n\n`Obx` is pretty smart, and will only change if the value of `controller.name` changes. \n\nIf `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?**\n\n> So, what if I have 5 _Rx_ (observable) variables within an `Obx` ?\n\nIt will just update when **any** of them changes. \n\n> And if I have 30 variables in a class, when I update one, will it update **all** the variables that are in that class?\n\nNope, just the **specific Widget** that uses that _Rx_ variable.\n\nSo, **GetX** only updates the screen, when the _Rx_ variable changes it's value.\n\n``` \n\nfinal isOpen = false.obs;\n\n// NOTHING will happen... same value.\nvoid onButtonTap() => isOpen.value=false;\n```\n\n### Advantages\n\n**GetX()** helps you when you need **granular** control over what's being updated.\n\nIf you do not need `unique IDs` , because all your variables will be modified when you perform an action, then use `GetBuilder` , \nbecause it's a Simple State Updater (in blocks, like `setState()` ), made in just a few lines of code.\nIt 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.\n\nIf you need a **powerful** State Manager, you can't go wrong with **GetX**.\n\nIt doesn't work with variables, but __flows__, everything in it are `Streams` under the hood. \n\nYou can use _rxDart_ in conjunction with it, because everything are `Streams`, \nyou can listen to the `event` of each \"_Rx_ variable\", \nbecause everything in it are `Streams`. \n\nIt is literally a _BLoC_ approach, easier than _MobX_, and without code generators or decorations.\nYou can turn **anything** into an _\"Observable\"_ with just a `.obs` .\n\n### Maximum performance:\n\nIn addition to having a smart algorithm for minimal rebuilds, **GetX** uses comparators \nto make sure the State has changed. \n\nIf you experience any errors in your app, and send a duplicate change of State, \n**GetX** will ensure it will not crash.\n\nWith **GetX** the State only changes if the `value` change. \nThat's the main difference between **GetX**, and using _ `computed` from MobX_. \nWhen joining two __observables__, and one changes; the listener of that _observable_ will change as well.\n\nWith **GetX**, if you join two variables, `GetX()` (similar to `Observer()` ) will only rebuild if it implies a real change of State.\n\n### Declaring a reactive variable\n\nYou have 3 ways to turn a variable into an \"observable\".\n\n1 - The first is using **`Rx{Type}`**.\n\n``` dart\n// initial value is recommended, but not mandatory\nfinal name = RxString('');\nfinal isLogged = RxBool(false);\nfinal count = RxInt(0);\nfinal balance = RxDouble(0.0);\nfinal items = RxList<String>([]);\nfinal myMap = RxMap<String, int>({});\n```\n\n2 - The second is to use **`Rx`** and use Darts Generics, `Rx<Type>`\n\n``` dart\nfinal name = Rx<String>('');\nfinal isLogged = Rx<Bool>(false);\nfinal count = Rx<Int>(0);\nfinal balance = Rx<Double>(0.0);\nfinal number = Rx<Num>(0);\nfinal items = Rx<List<String>>([]);\nfinal myMap = Rx<Map<String, int>>({});\n\n// Custom classes - it can be any class, literally\nfinal user = Rx<User>();\n```\n\n3 - The third, more practical, easier and preferred approach, just add **`.obs`** as a property of your `value` :\n\n``` dart\nfinal name = ''.obs;\nfinal isLogged = false.obs;\nfinal count = 0.obs;\nfinal balance = 0.0.obs;\nfinal number = 0.obs;\nfinal items = <String>[].obs;\nfinal myMap = <String, int>{}.obs;\n\n// Custom classes - it can be any class, literally\nfinal user = User().obs;\n```\n\n##### Having a reactive state, is easy.\n\nAs we know, _Dart_ is now heading towards _null safety_.\nTo be prepared, from now on, you should always start your _Rx_ variables with an **initial value**.\n\n> Transforming a variable into an _observable_ + _initial value_ with **GetX** is the simplest, and most practical approach.\n\nYou will literally add a \" `.obs` \" to the end of your variable, and **that’s it**, you’ve made it observable, \nand its `.value` , well, will be the _initial value_).\n\n### Using the values in the view\n\n``` dart\n// controller file\nfinal count1 = 0.obs;\nfinal count2 = 0.obs;\nint get sum => count1.value + count2.value;\n```\n\n``` dart\n// view file\nGetX<Controller>(\n  builder: (controller) {\n    print(\"count 1 rebuild\");\n    return Text('${controller.count1.value}');\n  },\n),\nGetX<Controller>(\n  builder: (controller) {\n    print(\"count 2 rebuild\");\n    return Text('${controller.count2.value}');\n  },\n),\nGetX<Controller>(\n  builder: (controller) {\n    print(\"count 3 rebuild\");\n    return Text('${controller.sum}');\n  },\n),\n```\n\nIf we increment `count1.value++` , it will print:\n\n* `count 1 rebuild`\n\n* `count 3 rebuild`\n\nbecause `count1` has a value of `1` , and `1 + 0 = 1` , changing the `sum` getter value.\n\nIf we change `count2.value++` , it will print:\n\n* `count 2 rebuild`\n\n* `count 3 rebuild`\n\nbecause `count2.value` changed, and the result of the `sum` is now `2` .\n\n* NOTE: By default, the very first event will rebuild the widget, even if it is the same `value`.\n\n This behavior exists due to Boolean variables.\n\nImagine you did this:\n\n``` dart\nvar isLogged = false.obs;\n```\n\nAnd then, you checked if a user is \"logged in\" to trigger an event in `ever` .\n\n``` dart\n@override\nonInit() async {\n  ever(isLogged, fireRoute);\n  isLogged.value = await Preferences.hasToken();\n}\n\nfireRoute(logged) {\n  if (logged) {\n   Get.off(Home());\n  } else {\n   Get.off(Login());\n  }\n}\n```\n\nif `hasToken` was `false` , there would be no change to `isLogged` , so `ever()` would never be called.\nTo avoid this type of behavior, the first change to an _observable_ will always trigger an event, \neven if it contains the same `.value` .\n\nYou can remove this behavior if you want, using:\n `isLogged.firstRebuild = false;`\n\n### Conditions to rebuild\n\nIn addition, Get provides refined state control. You can condition an event (such as adding an object to a list), on a certain condition.\n\n``` dart\n// First parameter: condition, must return true or false.\n// Second parameter: the new value to apply if the condition is true.\nlist.addIf(item < limit, item);\n```\n\nWithout decorations, without a code generator, without complications :smile:\n\nDo you know Flutter's counter app? Your Controller class might look like this:\n\n``` dart\nclass CountController extends GetxController {\n  final count = 0.obs;\n}\n```\n\nWith a simple:\n\n``` dart\ncontroller.count.value++\n```\n\nYou could update the counter variable in your UI, regardless of where it is stored.\n\n### Where .obs can be used\n\nYou can transform anything on obs. Here are two ways of doing it:\n\n* You can convert your class values to obs\n\n``` dart\nclass RxUser {\n  final name = \"Camila\".obs;\n  final age = 18.obs;\n}\n```\n\n* or you can convert the entire class to be an observable\n\n``` dart\nclass User {\n  User({String name, int age});\n  var name;\n  var age;\n}\n\n// when instantianting:\nfinal user = User(name: \"Camila\", age: 18).obs;\n```\n\n### Note about Lists\n\nLists 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.\n\nYou also don't need to use \".value\" with lists, the amazing dart api allowed us to remove that.\nUnfortunaly 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.\n\n``` dart\n// On the controller\nfinal String title = 'User Info:'.obs\nfinal list = List<User>().obs;\n\n// on the view\nText(controller.title.value), // String need to have .value in front of it\nListView.builder (\n  itemCount: controller.list.length // lists don't need it\n)\n```\n\nWhen you are making your own classes observable, there is a different way to update them:\n\n``` dart\n// on the model file\n// we are going to make the entire class observable instead of each attribute\nclass User() {\n  User({this.name = '', this.age = 0});\n  String name;\n  int age;\n}\n\n// on the controller file\nfinal user = User().obs;\n// when you need to update the user variable:\nuser.update( (user) { // this parameter is the class itself that you want to update\nuser.name = 'Jonny';\nuser.age = 18;\n});\n// an alternative way of update the user variable:\nuser(User(name: 'João', age: 35));\n\n// on view:\nObx(()=> Text(\"Name ${user.value.name}: Age: ${user.value.age}\"))\n// you can also access the model values without the .value:\nuser().name; // notice that is the user variable, not the class (variable has lowercase u)\n```\n\nYou don't have to work with sets if you don't want to. you can use the \"assign 'and\" assignAll \"api.\nThe \"assign\" api will clear your list, and add a single object that you want to start there.\nThe \"assignAll\" api will clear the existing list and add any iterable objects that you inject into it.\n\n### Why i have to use .value\n\nWe 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.\n\nYou 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.\n\nThe 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.\n\nIf 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.\n\nIf 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.\n\nObviously, 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.\n\n### Obx()\n\nTyping 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.\nObviously, 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<Controller>()` .value or Controller.to.value to retrieve the value.\n\n### Workers\n\nWorkers will assist you, triggering specific callbacks when an event occurs.\n\n``` dart\n/// Called every time `count1` changes.\never(count1, (_) => print(\"$_ has been changed\"));\n\n/// Called only first time the variable $_ is changed\nonce(count1, (_) => print(\"$_ was changed once\"));\n\n/// Anti DDos - Called every time the user stops typing for 1 second, for example.\ndebounce(count1, (_) => print(\"debouce$_\"), time: Duration(seconds: 1));\n\n/// Ignore all changes within 1 second.\ninterval(count1, (_) => print(\"interval $_\"), time: Duration(seconds: 1));\n```\n\nAll workers (except `debounce` ) have a `condition` named parameter, which can be a `bool` or a callback that returns a `bool` .\nThis `condition` defines when the `callback` function executes.\n\nAll workers returns a `Worker` instance, that you can use to cancel ( via `dispose()` ) the worker.\n \n\n* **`ever`**\n\n is called every time the _Rx_ variable emits a new value.\n\n* **`everAll`**\n\n Much like `ever` , but it takes a `List` of _Rx_ values Called every time its variable is changed. That's it.\n\n* **`once`**\n\n'once' is called only the first time the variable has been changed.\n\n* **`debounce`**\n\n'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.\n\n* **`interval`**\n\n'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.\n\n* 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).\n\n## Simple State Manager\n\nGet 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.\n\nGetBuilder 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.\n\nThat 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.\n\n### Advantages\n\n1. Update only the required widgets.\n\n2. Does not use changeNotifier, it is the state manager that uses less memory (close to 0mb).\n\n3. 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.\n\n4. Organize your project for real! Controllers must not be in your UI, place your TextEditController, or any controller you use within your Controller class.\n\n5. 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.\n\n6. 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.\n\n7. 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).\n\n8. 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.\n\n9. 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.\n\n### Usage\n\n``` dart\n// Create controller class and extends GetxController\nclass Controller extends GetxController {\n  int counter = 0;\n  void increment() {\n    counter++;\n    update(); // use update() to update counter variable on UI when increment be called\n  }\n}\n// On your Stateless/Stateful class, use GetBuilder to update Text when increment be called\nGetBuilder<Controller>(\n  init: Controller(), // INIT IT ONLY THE FIRST TIME\n  builder: (_) => Text(\n    '${_.counter}',\n  ),\n)\n//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.\n```\n\n**Done!**\n\n* You have already learned how to manage states with Get.\n\n* 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.\n\nIf you navigate many routes and need data that was in your previously used controller, you just need to use GetBuilder Again (with no init):\n\n``` dart\nclass OtherClass extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      body: Center(\n        child: GetBuilder<Controller>(\n          builder: (s) => Text('${s.counter}'),\n        ),\n      ),\n    );\n  }\n\n```\n\nIf 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<Controller>()` )\n\n``` dart\nclass Controller extends GetxController {\n\n  /// You do not need that. I recommend using it just for ease of syntax.\n  /// with static method: Controller.to.increment();\n  /// with no static method: Get.find<Controller>().increment();\n  /// 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.\n  static Controller get to => Get.find(); // add this line\n\n  int counter = 0;\n  void increment() {\n    counter++;\n    update();\n  }\n}\n```\n\nAnd then you can access your controller directly, that way:\n\n``` dart\nFloatingActionButton(\n  onPressed: () {\n    Controller.to.increment(),\n  } // This is incredibly simple!\n  child: Text(\"${Controller.to.counter}\"),\n),\n```\n\nWhen you press FloatingActionButton, all widgets that are listening to the 'counter' variable will be updated automatically.\n\n### How it handles controllers\n\nLet's say we have this:\n\n `Class a => Class B (has controller X) => Class C (has controller X)`\n\nIn 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.\n\n### You won't need StatefulWidgets anymore\n\nUsing 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.\nThe 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!\nUnless you need to use a mixin, like TickerProviderStateMixin, it will be totally unnecessary to use a StatefulWidget with Get.\n\nYou can call all methods of a StatefulWidget directly from a GetBuilder.\nIf you need to call initState() or dispose() method for example, you can call them directly;\n\n``` dart\nGetBuilder<Controller>(\n  initState: (_) => Controller.to.fetchApi(),\n  dispose: (_) => Controller.to.closeStreams(),\n  builder: (s) => Text('${s.username}'),\n),\n```\n\nA much better approach than this is to use the onInit() and onClose() method directly from your controller.\n\n``` dart\n@override\nvoid onInit() {\n  fetchApi();\n  super.onInit();\n}\n```\n\n* 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.\n\n### Why it exists\n\nThe 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.\n\nSo to simplify this:\nYou 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.\nYou 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.\n\nDo 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:\n\n``` dart\nclass Controller extends GetxController {\n  StreamController<User> user = StreamController<User>();\n  StreamController<String> name = StreamController<String>();\n\n  /// close stream = onClose method, not dispose.\n  @override\n  void onClose() {\n    user.close();\n    name.close();\n    super.onClose();\n  }\n}\n```\n\nController life cycle:\n\n* onInit() where it is created.\n* onClose() where it is closed to make any changes in preparation for the delete method\n* 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.\n\n### Other ways of using it\n\nYou can use Controller instance directly on GetBuilder value:\n\n``` dart\nGetBuilder<Controller>(\n  init: Controller(),\n  builder: (value) => Text(\n    '${value.counter}', //here\n  ),\n),\n```\n\nYou may also need an instance of your controller outside of your GetBuilder, and you can use these approaches to achieve this:\n\n``` dart\nclass Controller extends GetxController {\n  static Controller get to => Get.find();\n[...]\n}\n// on you view:\nGetBuilder<Controller>(  \n  init: Controller(), // use it only first time on each controller\n  builder: (_) => Text(\n    '${Controller.to.counter}', //here\n  )\n),\n```\n\nor\n\n``` dart\nclass Controller extends GetxController {\n // static Controller get to => Get.find(); // with no static get\n[...]\n}\n// on stateful/stateless class\nGetBuilder<Controller>(  \n  init: Controller(), // use it only first time on each controller\n  builder: (_) => Text(\n    '${Get.find<Controller>().counter}', //here\n  ),\n),\n```\n\n* 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:\n\n``` dart\nController controller = Controller();\n[...]\nGetBuilder<Controller>(\n  init: controller, //here\n  builder: (_) => Text(\n    '${controller.counter}', // here\n  ),\n),\n\n```\n\n### Unique IDs\n\nIf you want to refine a widget's update control with GetBuilder, you can assign them unique IDs:\n\n``` dart\nGetBuilder<Controller>(\n  id: 'text'\n  init: Controller(), // use it only first time on each controller\n  builder: (_) => Text(\n    '${Get.find<Controller>().counter}', //here\n  ),\n),\n```\n\nAnd update it this form:\n\n``` dart\nupdate(['text']);\n```\n\nYou can also impose conditions for the update:\n\n``` dart\nupdate(['text'], counter < 10);\n```\n\nGetX 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).\n\n## Mixing the two state managers\n\nSome 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.\n\nExtending 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.\n\n## StateMixin\n\nAnother way to handle your `UI` state is use the `StateMixin<T>` .\nTo implement it, use the `with` to add the `StateMixin<T>`\nto your controller which allows a T model.\n\n``` dart\nclass Controller extends GetController with StateMixin<User>{}\n```\n\nThe `change()` method change the State whenever we want.\nJust pass the data and the status in this way:\n\n```dart\nchange(data, status: RxStatus.success());\n```\n\nRxStatus allow these status:\n\n``` dart\nRxStatus.loading();\nRxStatus.success();\nRxStatus.empty();\nRxStatus.error('message');\n```\n\nTo represent it in the UI, use:\n\n```dart\nclass OtherClass extends GetView<Controller> {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n\n      body: controller.obx(\n        (state)=>Text(state.name),\n        \n        // here you can put your custom loading indicator, but\n        // by default would be Center(child:CircularProgressIndicator())\n        onLoading: CustomLoadingIndicator(),\n        onEmpty: Text('No data found'),\n\n        // here also you can set your own error widget, but by\n        // default will be an Center(child:Text(error))\n        onError: (error)=>Text(error),\n      ),\n    );\n}\n```\n\n## GetBuilder vs GetX vs Obx vs MixinBuilder\n\nIn a decade working with programming I was able to learn some valuable lessons.\n\nMy first contact with reactive programming was so \"wow, this is incredible\" and in fact reactive programming is incredible.\nHowever, 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.\n\nReactive 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.\n\nWith 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.\n\nGetBuilder 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).\n\nHowever, GetBuilder is still a mechanical state manager, you need to call update() just like you would need to call Provider's notifyListeners().\n\nThere 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.\n\nGetX 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.\n"
  },
  {
    "path": "documentation/es_ES/dependency_management.md",
    "content": "- [Gestión de dependencias](#gestión-de-dependencias)\n  - [Simple Instance Manager](#simple-instance-manager)\n  - [Options](#options)\n  - [Bindings](#bindings)\n    - [Cómo utilizar](#cómo-utilizar)\n  - [SmartManagement](#smartmanagement)\n\n\n# Gestión de dependencias\n\n## Simple Instance Manager\n\n- Nota: si está utilizando el gestor de estado de GetX, no tiene que preocuparse por esto, solo lea para obtener información, pero preste más atención a la API de bindings, que hará todo esto automáticamente por usted.\n\n¿Ya estás utilizando GetX y quieres que tu proyecto sea lo más ágil posible? GetX tiene un gestor de dependencias simple y poderoso que le permite recuperar la misma clase que su BLoC o Controller con solo una líneas de código, sin contexto de Provider, sin inheritedWidget:\n\n```dart\nController controller = Get.put(Controller()); // Rather Controller controller = Controller();\n```\n\nEn lugar de crear una instancia de su clase dentro de la clase que está utilizando, la está creando dentro de la instancia GetX, que la hará disponible en toda su aplicación. Entonces puede usar su Controller (o BLoC) normalmente.\n\n```dart\ncontroller.fetchApi();\n```\n\nImagine que ha navegado a través de numerosas rutas y necesita datos que quedaron en su controlador, necesitaría un gestor de estado combinado con Providere o Get_it, ¿correcto? No con GetX. Solo necesita pedirle a GetX que \"encuentre\" su controlador, no necesita dependencias adicionales:\n\n```dart\nController controller = Get.find();\n//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.\n```\n\nY luego podrá recuperar los datos de su controlador que se obtuvieron allí:\n\n```dart\nText(controller.textFromApi);\n```\n\n¿Buscando lazy loading? Puede declarar todos sus controladores, y se llamará solo cuando alguien lo necesite. Puedes hacer esto con:\n\n```dart\nGet.lazyPut<Service>(()=> ApiMock());\n/// ApiMock will only be called when someone uses Get.find<Service> for the first time\n```\n\nSi desea registrar una instancia asincrónica, puede usar Get.putAsync.\n\n```dart\nGet.putAsync<SharedPreferences>(() async {\n    final prefs = await SharedPreferences.getInstance();\n    await prefs.setInt('counter', 12345);\n    return prefs;\n});\n```\n\nuso:\n\n```dart\n  int count = Get.find<SharedPreferences>().getInt('counter');\n  print(count);\n  // out: 12345\n}\n```\n\nPara eliminar una instancia de GetX:\n\n```dart\nGet.delete<Controller>();\n```\n\n## Instancing methods\n\nAlthough Getx already delivers very good settings for use, it is possible to refine them even more so that it become more useful to the programmer. The methods and it's configurable parameters are:\n\n- Get.put():\n\n```dart\nGet.put<S>(\n  // mandatory: the class that you want to get to save, like a controller or anything\n  // note: that \"S\" means that it can be anything\n  S dependency\n\n  // optional: this is for when you want multiple classess that are of the same type\n  // since you normally get a class by using Get.find<Controller>(),\n  // you need to use tag to tell which instance you need\n  // must be unique string\n  String tag,\n\n  // optional: by default, get will dispose instances after they are not used anymore (example,\n  // the controller of a view that is closed), but you might need that the instance\n  // to be kept there throughout the entire app, like an instance of sharedPreferences or something\n  // so you use this\n  // defaults to false\n  bool permanent = false,\n\n  // optional: allows you after using an abstract class in a test, replace it with another one and follow the test.\n  // defaults to false\n  bool overrideAbstract = false,\n\n  // optional: allows you to create the dependency using function instead of the dependency itself.\n  InstanceBuilderCallback<S> builder,\n)\n```\n\n- Get.lazyPut:\n\n```dart\nGet.lazyPut<S>(\n  // mandatory: a method that will be executed when your class is called for the first time\n  // Example: Get.lazyPut<Controller>( () => Controller() )\n  InstanceBuilderCallback builder,\n  \n  // optional: same as Get.put(), it is used for when you want multiple different instance of a same class\n  // must be unique\n  String tag,\n\n  // optional: It is similar to \"permanent\", the difference is that the instance is discarded when\n  // is not being used, but when it's use is needed again, Get will recreate the instance\n  // just the same as \"SmartManagement.keepFactory\" in the bindings api\n  // defaults to false\n  bool fenix = false\n  \n)\n```\n\n- Get.putAsync:\n\n```dart\nGet.putAsync<S>(\n\n  // mandatory: an async method that will be executed to instantiate your class\n  // Example: Get.putAsync<YourAsyncClass>( () async => await YourAsyncClass() )\n  AsyncInstanceBuilderCallback<S> builder,\n\n  // optional: same as Get.put(), it is used for when you want multiple different instance of a same class\n  // must be unique\n  String tag,\n\n  // optional: same as in Get.put(), used when you need to maintain that instance alive in the entire app\n  // defaults to false\n  bool permanent = false\n```\n\n- Get.create:\n\n```dart\nGet.create<S>(\n  // required: a function that returns a class that will be \"fabricated\" every\n  // time `Get.find()` is called\n  // Example: Get.create<YourClass>(() => YourClass())\n  FcBuilderFunc<S> builder,\n  // optional: just like Get.put(), but it is used when you need multiple instances\n  // of a of a same class\n  // Useful in case you have a list that each item need it's own controller\n  // needs to be a unique string. Just change from tag to name\n  String name,\n  // optional: just like int`Get.put()`, it is for when you need to keep the\n  // instance alive thoughout the entire app. The difference is in Get.create\n  // permanent is true by default\n  bool permanent = true\n```\n\n### Diferences between methods:\n\nFirst, let's of the `fenix` of Get.lazyPut and the `permanent` of the other methods.\n\nThe fundamental difference between `permanent` and `fenix` is how you want to store your instances.\nReinforcing: by default, GetX deletes instances when they are not is use.\nIt 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.offName()`) the controller 1 lost it's use so it will be erased.\nBut if you want to opt to `permanent:true`, then the controller will not be lost in this transition - which is very usefult for services that you want to keep alive thoughout the entire application.\n`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 that, it will \"recreate from the ashes\" a new instance.\n\nProceeding with the differences between methods: \n\n- Get.put and Get.putAsync follow the same creation order, with the difference that asyn opt for applying a asynchronous method: those two methods create and initialize 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 porpuse 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.\n\n- Get.create: As the name implies, it will \"create\" your dependency! Similar to `Get.put()`, it also call 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.\n\n- 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 responsable 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.\n\n\n## Bindings\n\nUna de las grandes diferencias de este paquete, tal vez, es la posibilidad de una integración completa de las rutas, gestor de estado y dependencias.\n\nCuando se elimina una ruta del stack, todos los controladores, variables e instancias de objetos relacionados con ella se eliminan de la memoria. Si está utilizando stream o timers, se cerrarán automáticamente y no tendrá que preocuparse por nada de eso.\n\nEn la versión 2.10 GetX se implementó por completo la API de bindings.\n\nAhora ya no necesita usar el método init. Ni siquiera tiene que escribir sus controladores si no lo desea. Puede iniciar sus controladores y servicios en un lugar apropiado para eso.\n\nLa clase Binding es una clase que desacoplará la inyección de dependencia, al tiempo que vinculará rutas con el gestor de estado y el gestor de dependencias.\n\nEsto permite conocer qué pantalla se muestra cuando se utiliza un controlador en particular y saber dónde y cómo descartarlo.\n\nAdemás, la clase Binding le permitirá tener el control de configuración SmartManager. Puede configurar las dependencias que se organizarán al eliminar una ruta de la pila, o cuando el widget que lo usó se presenta, o ninguno de los dos. Tendrá una gestión inteligente de dependencias que funcione para usted, pero aun así, puede configurarla como desee.\n\n### Cómo utilizar\n\n- Crea una clase e implementa Binding\n\n```dart\nclass HomeBinding implements Bindings{\n```\n\nSu IDE le pedirá automáticamente que anule el método de \"dependencies\", y solo necesita hacer clic en la lámpara, anular el método e insertar todas las clases que va a utilizar en esa ruta:\n\n```dart\nclass HomeBinding implements Bindings{\n  @override\n  void dependencies() {\n    Get.lazyPut<ControllerX>(() => ControllerX());\n    Get.lazyPut<Service>(()=> Api());\n  }\n}\n```\n\nAhora solo necesita informar su ruta, que utilizará ese binding para establecer la conexión entre el gestor de rutas, las dependencias y los estados.\n\n- Uso de rutas nombradas:\n\n```dart\ngetPages: [\n  GetPage(name: '/', page: () => Home(), binding: HomeBinding()),\n]\n```\n\n- Usando rutas normales:\n\n```dart\nGet.to(Home(), binding: HomeBinding());\n```\n\nAllí, ya no tiene que preocuparse por la administración de memoria de su aplicación, GetX lo hará por usted.\n\nLa clase Binding se llama cuando se llama una ruta, puede crear un initialBinding en su GetMaterialApp para insertar todas las dependencias que se crearán.\n\n```dart\nGetMaterialApp(\n  initialBinding: SampleBind(),\n  home: Home(),\n);\n```\n\n## SmartManagement\n\nSiempre prefiera usar SmartManagement estándar (full), no necesita configurar nada para eso, GetX ya se lo proporciona de forma predeterminada. Seguramente eliminará todos los controladores en desuso de la memoria, ya que su control refinado elimina la dependencia, incluso si se produce un error y un widget que lo utiliza no se elimina correctamente.\n\nEl modo \"full\" también es lo suficientemente seguro como para usarlo con StatelessWidget, ya que tiene numerosos callbacks de seguridad que evitarán que un controlador permanezca en la memoria si ningún widget lo está utilizando, y los disposers no son importante aquí. Sin embargo, si le molesta el comportamiento predeterminado, o simplemente no quiere que suceda, GetX ofrece otras opciones más indulgentes para la administración inteligente de la memoria, como SmartManagement.onlyBuilders, que dependerá de la eliminación efectiva de los widgets que estén usando el controller para eliminarlo, y puede evitar que se implemente un controlador usando \"autoRemove: false\" en su GetBuilder/GetX.\n\nCon esta opción, solo se eliminarán los controladores iniciados en \"init:\" o cargados en un enlace con \"Get.lazyPut\"; si usa Get.put o cualquier otro enfoque, SmartManagement no tendrá permisos para excluir esta dependencia.\n\nCon el comportamiento predeterminado, incluso los widgets instanciados con \"Get.put\" se eliminarán, a diferencia de SmartManagement.onlyBuilders.\n\nSmartManagement.keepFactory es como SmartManagement.full, con una diferencia. SmartManagement.full purga los factories de las premises, de modo que Get.lazyPut() solo podrá llamarse una vez y su factory y sus referencias se autodestruirán. SmartManagement.keepFactory eliminará sus dependencias cuando sea necesario, sin embargo, mantendrá la \"forma\" de estas, para hacer una igual si necesita una instancia de eso nuevamente.\n\nEn lugar de usar SmartManagement.keepFactory, puede usar Bindings.\n\nBindings crea factories transitorios, que se crean en el momento en que hace clic para ir a otra pantalla, y se destruirán tan pronto como ocurra la animación de cambio de pantalla. Es tan poco tiempo que el analizador ni siquiera podrá registrarlo. Cuando navegue de nuevo a esta pantalla, se llamará a una nueva factory temporal, por lo que es preferible usar SmartManagement.keepFactory, pero si no desea crear enlaces o desea mantener todas sus dependencias en el mismo enlace, sin duda te ayudará. Las factories ocupan poca memoria, no tienen instancias, sino una función con la \"forma\" de esa clase que desea. Esto es muy poco, pero dado que el propósito de esta lib es obtener el máximo rendimiento posible utilizando los recursos mínimos, GetX elimina incluso las factories por defecto. Use el que sea más conveniente para usted.\n\n- NOTA: NO USE SmartManagement.keepFactory si está utilizando bindings múltiples. Fue diseñado para usarse sin bindings, o con uno único vinculado en el binding inicial de GetMaterialApp.\n\n- NOTA2: El uso de bindings es completamente opcional, puede usar Get.put() y Get.find() en clases que usan un controlador dado sin ningún problema.\n\nSin embargo, si trabaja con Servicios o cualquier otra abstracción, le recomiendo usar binding para una organización más grande.\n"
  },
  {
    "path": "documentation/es_ES/route_management.md",
    "content": "- [Gestión de Rutas](#gestión-de-rutas)\n  - [¿Cómo utilizarlo](#cómo-utilizarlo)\n  - [Navegación sin rutas nombradas](#navegación-sin-rutas-nombradas)\n  - [Navegación con rutas nombradas](#navegación-con-rutas-nombradas)\n    - [Enviar datos a rutas nombradas](#enviar-datos-a-rutas-nombradas)\n    - [Enlaces de URL dinámicos](#enlaces-de-url-dinámicos)\n    - [Middleware](#middleware)\n  - [Navegación sin contexto](#navegación-sin-contexto)\n    - [SnackBars](#snackbars)\n    - [Diálogos](#diálogos)\n    - [BottomSheets](#bottomsheets)\n  - [Navegación anidada](#navegación-anidada)\n\n# Gestión de Rutas\n\nCualquier contribución es bienvenida!\n\n## ¿Cómo utilizarlo\n\nAgregue esto a su archivo pubspec.yaml:\n\n```yaml\ndependencies:\n  get:\n```\n\nSi va a utilizar rutas/snackbars/dialogs/bottomsheets sin contexto, o las APIs de GetX de alto nivel, simplemente debe agregar \"Get\" antes de su MaterialApp, ¡convertirlo en GetMaterialApp y disfrutar!\n\n```dart\nGetMaterialApp( // Before: MaterialApp(\n  home: MyHome(),\n)\n```\n\n## Navegación sin rutas nombradas\n\nPara navegar a una nueva pantalla:\n\n```dart\nGet.to(NextScreen());\n```\n\nPara cerrar snackbars, dialogs, bottomsheets o cualquier cosa que normalmente cierre con Navigator.pop(contexto);\n\n```dart\nGet.back();\n```\n\nPara ir a la siguiente pantalla, sin opción a volver (util por ejemplo en SplashScreens, LoginScreen, etc.)\n\n```dart\nGet.off(NextScreen());\n```\n\nPara ir a la siguiente pantalla y cancelar todas las rutas anteriores (útil en carritos de compras, encuestas y exámenes)\n\n```dart\nGet.offAll(NextScreen());\n```\n\nPara navegar a la siguiente ruta y recibir o actualizar datos tan pronto como se regrese de ella:\n\n```dart\nvar data = await Get.to(Payment());\n```\n\nen la otra pantalla, envíe los datos para la ruta anterior:\n\n```dart\nGet.back(result: 'success');\n```\n\nY luego usarlo:\n\nej:\n\n```dart\nif(data == 'success') madeAnything();\n```\n\n¿No quieres aprender nuestra sintaxis?\n\nSimplemente cambie Navigator (mayúsculas) a navigator (minúsculas), y tendrá todas las funciones de la navegación estándar, pero sin tener que usar el contexto.\n\nEjemplo:\n\n```dart\n// Default Flutter navigator\nNavigator.of(context).push(\n  context,\n  MaterialPageRoute(\n    builder: (BuildContext context) {\n      return HomePage();\n    },\n  ),\n);\n\n// Get using Flutter syntax without needing context\nnavigator.push(\n  MaterialPageRoute(\n    builder: (_) {\n      return HomePage();\n    },\n  ),\n);\n\n// Get syntax (It is much better, but you have the right to disagree)\nGet.to(HomePage());\n```\n\n## Navegación con rutas nombradas\n\n- Si prefiere navegar con rutas nombradas, con GetX también es posible.\n\nPara navegar a la siguiente pantalla\n\n```dart\nGet.toNamed(\"/NextScreen\");\n```\n\nPara navegar y eliminar la pantalla anterior del árbol.\n\n```dart\nGet.offNamed(\"/NextScreen\");\n```\n\nPara navegar y eliminar todas las pantallas anteriores del árbol.\n\n```dart\nGet.offAllNamed(\"/NextScreen\");\n```\n\nPara definir rutas, use GetMaterialApp:\n\n```dart\nvoid main() {\n  runApp(\n    GetMaterialApp(\n      initialRoute: '/',\n      getPages: [\n        GetPage(name: '/', page: () => MyHomePage()),\n        GetPage(name: '/second', page: () => Second()),\n        GetPage(\n          name: '/third',\n          page: () => Third(),\n          transition: Transition.zoom  \n        ),\n      ],\n    )\n  );\n}\n```\n\nPara manejar la navegación a rutas no definidas (error 404), puede definir una página de ruta desconocida en GetMaterialApp.\n\n```dart\nvoid main() {\n  runApp(\n    GetMaterialApp(\n      unknownRoute: GetPage(name: '/notfound', page: () => UnknownRoutePage()),\n      initialRoute: '/',\n      getPages: [\n        GetPage(name: '/', page: () => MyHomePage()),\n        GetPage(name: '/second', page: () => Second()),\n      ],\n    )\n  );\n}\n```\n\n### Enviar datos a rutas nombradas\n\nEnvía lo que quieras usando el parámetro arguments. GetX acepta cualquier cosa aquí, ya sea un String, Map, List o incluso una instancia de clase.\n\n```dart\nGet.toNamed(\"/NextScreen\", arguments: 'Get is the best');\n```\n\nluego en su clase o controlador:\n\n```dart\nprint(Get.arguments);\n//print out: Get is the best\n```\n\n### Enlaces de URL dinámicos\n\nGetX ofrece URLs dinámicas avanzadas como en la Web. Los desarrolladores web probablemente ya quisieron esta característica en Flutter, y lo más probable es que hayan visto un paquete que promete esta característica y pero que ofrece una sintaxis totalmente diferente a la que una URL tendría en la web, pero GetX lo resuelve.\n\n```dart\nGet.offAllNamed(\"/NextScreen?device=phone&id=354&name=Enzo\");\n```\n\ny luego en su clase controller/bloc/stateful/stateless:\n\n```dart\nprint(Get.parameters['id']);\n// out: 354\nprint(Get.parameters['name']);\n// out: Enzo\n```\n\nTambién puede recibir parámetros nombrados fácilmente:\n\n```dart\nvoid main() {\n  runApp(\n    GetMaterialApp(\n      initialRoute: '/',\n      getPages: [\n      GetPage(\n        name: '/',\n        page: () => MyHomePage(),\n      ),\n      GetPage(\n        name: '/profile/',\n        page: () => MyProfile(),\n      ),\n       //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.\n       GetPage(\n        name: '/profile/:user',\n        page: () => UserProfile(),\n      ),\n      GetPage(\n        name: '/third',\n        page: () => Third(),\n        transition: Transition.cupertino  \n      ),\n     ],\n    )\n  );\n}\n```\n\nEnviar datos sobre el nombre de la ruta\n\n```dart\nGet.toNamed(\"/second/34954\");\n```\n\nY en la segunda pantalla tome los datos por parámetro\n\n```dart\nprint(Get.parameters['user']);\n// salida: 34954\n```\n\no envie multiples parametros de la siguiente manera\n\n```dart\nGet.toNamed(\"/profile/34954?flag=true\");\n```\n\nEn la segunda pantalla tome los parametros como lo haria normalmente\n\n```dart\nprint(Get.parameters['user']);\nprint(Get.parameters['flag']);\n// salida: 34954 true\n```\n\nY ahora, todo lo que necesita hacer es usar Get.toNamed() para navegar por sus rutas nombradas, sin ningún contexto (puede llamar a sus rutas directamente desde su clase BLoC o Controller), y cuando su aplicación se compila para web, sus rutas aparecerán en la url del navegador <3\n\n### Middleware\n\nSi desea escuchar eventos  de GetX para activar acciones, puede usar el routingCallback:\n\n```dart\nGetMaterialApp(\n  routingCallback: (routing) {\n    if(routing.current == '/second'){\n      openAds();\n    }\n  }\n)\n```\n\nSi no está usando GetMaterialApp, puede usar la API para adjuntar el observador de Middleware.\n\n```dart\nvoid main() {\n  runApp(\n    MaterialApp(\n      onGenerateRoute: Router.generateRoute,\n      initialRoute: \"/\",\n      navigatorKey: Get.key,\n      navigatorObservers: [\n        GetObserver(MiddleWare.observer), // HERE !!!\n      ],\n    ),\n  );\n}\n```\n\nCrear la clase MiddleWare:\n\n```dart\nclass MiddleWare {\n  static observer(Routing routing) {\n    /// You can listen in addition to the routes, the snackbars, dialogs and bottomsheets on each screen.\n    ///If you need to enter any of these 3 events directly here,\n    ///you must specify that the event is != Than you are trying to do.\n    if (routing.current == '/second' && !routing.isSnackbar) {\n      Get.snackbar(\"Hi\", \"You are on second route\");\n    } else if (routing.current =='/third'){\n      print('last route called');\n    }\n  }\n}\n```\n\nAhora, usa GetX en tu código:\n\n```dart\nclass First extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        leading: IconButton(\n          icon: Icon(Icons.add),\n          onPressed: () {\n            Get.snackbar(\"hi\", \"i am a modern snackbar\");\n          },\n        ),\n        title: Text('First Route'),\n      ),\n      body: Center(\n        child: ElevatedButton(\n          child: Text('Open route'),\n          onPressed: () {\n            Get.toNamed(\"/second\");\n          },\n        ),\n      ),\n    );\n  }\n}\n\nclass Second extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        leading: IconButton(\n          icon: Icon(Icons.add),\n          onPressed: () {\n            Get.snackbar(\"hi\", \"i am a modern snackbar\");\n          },\n        ),\n        title: Text('second Route'),\n      ),\n      body: Center(\n        child: ElevatedButton(\n          child: Text('Open route'),\n          onPressed: () {\n            Get.toNamed(\"/third\");\n          },\n        ),\n      ),\n    );\n  }\n}\n\nclass Third extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: Text(\"Third Route\"),\n      ),\n      body: Center(\n        child: ElevatedButton(\n          onPressed: () {\n            Get.back();\n          },\n          child: Text('Go back!'),\n        ),\n      ),\n    );\n  }\n}\n```\n\n## Navegación sin contexto\n\n### SnackBars\n\nPara tener simple SnackBar con Flutter, debe obtener el contexto de Scaffold, o debe utilizar una GlobalKey:\n\n```dart\nfinal snackBar = SnackBar(\n  content: Text('Hi!'),\n  action: SnackBarAction(\n    label: 'I am a old and ugly snackbar :(',\n    onPressed: (){}\n  ),\n);\n// Find the Scaffold in the widget tree and use\n// it to show a SnackBar.\nScaffold.of(context).showSnackBar(snackBar);\n```\n\nCon GetX esto se resume en:\n\n```dart\nGet.snackbar('Hi', 'i am a modern snackbar');\n```\n\nTodo lo que tiene que hacer es llamar a Get.snackbar desde cualquier parte de su código y personalizarlo como desee:\n\n```dart\nGet.snackbar(\n  \"Hey i'm a Get SnackBar!\", // title\n  \"It's unbelievable! I'm using SnackBar without context, without boilerplate, without Scaffold, it is something truly amazing!\", // message\n  icon: Icon(Icons.alarm),\n  shouldIconPulse: true,\n  onTap:(){},\n  barBlur: 20,\n  isDismissible: true,\n  duration: Duration(seconds: 3),\n);\n\n\n  ////////// ALL FEATURES //////////\n  //     Color colorText,\n  //     Duration duration,\n  //     SnackPosition snackPosition,\n  //     Widget titleText,\n  //     Widget messageText,\n  //     bool instantInit,\n  //     Widget icon,\n  //     bool shouldIconPulse,\n  //     double maxWidth,\n  //     EdgeInsets margin,\n  //     EdgeInsets padding,\n  //     double borderRadius,\n  //     Color borderColor,\n  //     double borderWidth,\n  //     Color backgroundColor,\n  //     Color leftBarIndicatorColor,\n  //     List<BoxShadow> boxShadows,\n  //     Gradient backgroundGradient,\n  //     TextButton mainButton,\n  //     OnTap onTap,\n  //     bool isDismissible,\n  //     bool showProgressIndicator,\n  //     AnimationController progressIndicatorController,\n  //     Color progressIndicatorBackgroundColor,\n  //     Animation<Color> progressIndicatorValueColor,\n  //     SnackStyle snackStyle,\n  //     Curve forwardAnimationCurve,\n  //     Curve reverseAnimationCurve,\n  //     Duration animationDuration,\n  //     double barBlur,\n  //     double overlayBlur,\n  //     Color overlayColor,\n  //     Form userInputForm\n  ///////////////////////////////////\n```\n\nSi prefiere el snackbar tradicional, o desea personalizarlo desde cero, inclyendo reducirlo a una sola línea de código (dado que Get.snackbar utiliza al menos un título y un mensaje obligatorios), puede usar `Get.rawSnackbar();` que proporciona la API en la que se creó el Get.snackbar.\n\n### Diálogos\n\nPara abrir el dialog:\n\n```dart\nGet.dialog(YourDialogWidget());\n```\n\nPara abrir un dialog predeterminado:\n\n```dart\nGet.defaultDialog(\n  onConfirm: () => print(\"Ok\"),\n  middleText: \"Dialog made in 3 lines of code\"\n);\n```\n\nTambién puede usar Get.generalDialog en lugar de showGeneralDialog.\n\nPara todos los demás dialogs de Flutter, incluidos los cupertinos, puede usar Get.overlayContext en lugar de context, y abrirlo en cualquier parte de su código.\n\nPara los widgets que no usan Overlay, puede usar Get.context.\n\nEstos dos contexts funcionarán en el 99% de los casos para reemplazar el context de su UI, excepto en los casos donde inheritedWidget es usado sin un contexto de navegación.\n\n### BottomSheets\n\nGet.bottomSheet es como showModalBottomSheet, pero no necesita contexto.\n\n```dart\nGet.bottomSheet(\n  Container(\n    child: Wrap(\n      children: <Widget>[\n        ListTile(\n          leading: Icon(Icons.music_note),\n          title: Text('Music'),\n          onTap: () {}\n        ),\n        ListTile(\n          leading: Icon(Icons.videocam),\n          title: Text('Video'),\n          onTap: () {},\n        ),\n      ],\n    ),\n  )\n);\n```\n\n## Navegación anidada\n\nGetX hizo la navegación anidada de Flutter aún más fácil.\n\nNo necesita el contexto, y encontrará su pila de navegación por Id.\n\n- NOTA: Crear pilas de navegación paralelas puede ser peligroso. Lo ideal es no usar NestedNavigators o hacerlo con moderación. Si su proyecto lo requiere, continúe, pero tenga en cuenta que mantener múltiples pilas de navegación en la memoria puede no ser una buena idea para el consumo de RAM.\n\nMira qué simple es:\n\n```dart\nNavigator(\n  key: Get.nestedKey(1), // create a key by index\n  initialRoute: '/',\n  onGenerateRoute: (settings) {\n    if (settings.name == '/') {\n      return GetPageRoute(\n        page: () => Scaffold(\n          appBar: AppBar(\n            title: Text(\"Main\"),\n          ),\n          body: Center(\n            child: TextButton(\n              color: Colors.blue,\n              onPressed: () {\n                Get.toNamed('/second', id:1); // navigate by your nested route by index\n              },\n              child: Text(\"Go to second\"),\n            ),\n          ),\n        ),\n      );\n    } else if (settings.name == '/second') {\n      return GetPageRoute(\n        page: () => Center(\n          child: Scaffold(\n            appBar: AppBar(\n              title: Text(\"Main\"),\n            ),\n            body: Center(\n              child:  Text(\"second\")\n            ),\n          ),\n        ),\n      );\n    }\n  }\n),\n```\n"
  },
  {
    "path": "documentation/es_ES/state_management.md",
    "content": "- [Gestión del Estado](#gestión-del-estado)\n  - [Gestor de Estado Simple](#gestor-de-estado-simple)\n    - [Ventajas](#ventajas)\n    - [Uso](#uso)\n    - [Cómo maneja los Controllers](#cómo-maneja-los-controllers)\n    - [Ya no necesitará StatefulWidgets](#ya-no-necesitará-statefulwidgets)\n    - [Por qué existe](#por-qué-existe)\n    - [Otras formas de usarlo](#otras-formas-de-usarlo)\n    - [ID únicos](#id-únicos)\n  - [Reactivo STATE_MANAGER](#reactivo-state_manager)\n    - [Ventajas](#ventajas-1)\n    - [Uso](#uso-1)\n    - [Donde se pueden usar .obs](#donde-se-pueden-usar-obs)\n    - [Nota sobre listas](#nota-sobre-listas)\n    - [¿Por qué tengo que usar .value](#por-qué-tengo-que-usar-value)\n    - [Obx()](#obx)\n    - [Workers](#workers)\n  - [Mezclando los dos State Managers](#mezclando-los-dos-state-managers)\n  - [GetBuilder vs GetX vs Obx vs MixinBuilder](#getbuilder-vs-getx-vs-obx-vs-mixinbuilder)\n\n# Gestión del Estado\n\nActualmente hay varios State Managers para Flutter. Sin embargo, con la mayoría de ellos implica utilizar ChangeNotifier para actualizar widgets y este es un enfoque malo y muy malo para el rendimiento de aplicaciones medianas o grandes. Puede verificar en la documentación oficial de Flutter que [ChangeNotifier debe usarse con 1 o un máximo de 2 listeners](https://api.Flutter.dev/Flutter/foundation/ChangeNotifier-class.html), por lo que es prácticamente inutilizable para cualquier aplicación mediana o grande.\n\nOtros state managers son buenos, pero tienen sus matices:\n\n- BLoC es muy seguro y eficiente, pero es muy complejo para principiantes, lo que ha impedido que las personas se desarrollen con Flutter.\n\n- MobX es más fácil que BLoC y reactivo, casi perfecto, diría, pero necesita usar un generador de código, que para aplicaciones grandes, reduce la productividad, ya que necesitará beber muchos cafés hasta que su código esté listo nuevamente después de un `flutter clean` (¡Y esto no es culpa de MobX, sino del codegen que es realmente lento!).\n\n- Provider usa InheritedWidget para entregar el mismo listener, como una forma de resolver el problema mencionado anteriormente con ChangeNotifier, lo que implica que cualquier acceso a su clase ChangeNotifier debe estar dentro del árbol de widgets debido al contexto necesario para acceder.\n\nGetX no es mejor ni peor que cualquier otro gestor de estado, pero debe analizar estos puntos, así como los puntos que se mencionan a continuación, para elegir entre usar GetX en forma pura (vanilla) o usarlo junto con otro gestor de estado.\n\nDefinitivamente, GetX no es enemigo de ningún otro gestor de estado, porque GetX es más bien un microframework, no solo un gestor de estado, y se puede usar solo o en combinación con ellos.\n\n## Gestor de Estado Simple\n\nGetX tiene un gestor de estado que es extremadamente ligero y fácil de implementar, especialmente para aquellos nuevos en Flutter, que no utiliza ChangeNotifier, y satisface la necesidad, y no causará problemas en aplicaciones grandes.\n\n### Ventajas\n\n1. Actualiza solo los widgets necesarios.\n\n2. No usa changeNotifier, es el gestor de estados que usa menos memoria (cerca de 0mb).\n\n3. ¡Olvídate de StatefulWidget! Con GetX nunca lo necesitarás. Con los otros state managers, probablemente tendrá que usar un StatefulWidget para obtener la instancia de su Provider,BLoC,MobX Controller, etc. Pero alguna vez se detuvo para pensar que su appBar, su Scaffold y la mayoría de los widgets que están en tu clase son Stateless? Entonces, ¿por qué guardar el estado de una clase completa, si puede guardar solo el estado del widget que es Stateful? GetX también resuelve eso. Crea una clase Stateless, haz todo Stateless. Si necesita actualizar un solo componente, envuélvalo con GetBuilder, y se mantendrá su estado.\n\n4. ¡Organiza tu proyecto de verdad! Los Controllers no deben estar en su UI, colocar su TextEditController o cualquier controller que utilice dentro de su clase Controller.\n\n5. ¿Necesita activar un evento para actualizar un widget tan pronto como este se dibuje? GetBuilder tiene la propiedad \"initState\", al igual que en un StatefulWidget, y puede llamar a eventos desde su Controller, directamente desde él, sin que se coloquen más eventos en su initState.\n\n6. ¿Necesita activar una acción como cerrar streams, timers, etc.? GetBuilder también tiene la propiedad dispose, donde puede llamar a eventos tan pronto como se destruya ese widget.\n\n7. Use streams solo si es necesario. Puede usar sus StreamControllers dentro de su Controller normalmente, y usar StreamBuilder también normalmente, pero recuerde, un stream consume una cantidad azonablemente de memoria, la programación reactiva es hermosa, pero no debe abusar de ella. 30 streams abiertos simultáneamente pueden ser peores que un changeNotifier (y changeNotifier es muy malo).\n\n8. Actualice los widgets sin consumir ram por eso. GetX almacena solo el creator ID de GetBuilder y lo actualiza cuando es necesario. El consumo de memoria del almacenamiento del Get ID en la memoria es muy bajo, incluso para miles de GetBuilders. Cuando crea un nuevo GetBuilder, en realidad está compartiendo el estado de GetBuilder que tiene un creator ID. No se crea un nuevo estado para cada GetBuilder, lo que ahorra MUCHA RAM para aplicaciones grandes. Básicamente, su aplicación será completamente Stateless, y los pocos Widgets que serán Stateful (dentro de GetBuilder) tendrán un solo estado y por lo tanto actualizar uno los actualizará a todos. El estado es solo uno.\n\n9. GetX es omnisciente y, en la mayoría de los casos, sabe exactamente el momento de sacar un Controller de la memoria. No debe preocuparse por eso, GetX conoce el mejor momento para hacerlo.\n\n### Uso\n\n```dart\n// Create controller class and extends GetXController\nclass Controller extends GetXController {\n  int counter = 0;\n  void increment() {\n    counter++;\n    update(); // use update() to update counter variable on UI when increment be called\n  }\n}\n// On your Stateless/Stateful class, use GetBuilder to update Text when increment be called\nGetBuilder<Controller>(\n  init: Controller(), // INIT IT ONLY THE FIRST TIME\n  builder: (_) => Text(\n    '${_.counter}',\n  ),\n)\n//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.\n```\n\n**¡Listo!**\n\n- Ya has aprendido a gestionar estados con GetX.\n\n- Nota: es posible que desee una organización más grande y no usar la propiedad init. Para eso, puede crear una clase y extender la clase Bindings, dentro de ella mencionar los Controllers que necesita crear dentro de esa ruta. Pero los Controllers no se crearán en ese momento, por el contrario, esto será solo una declaración, por lo que, la primera vez que use un Controller, GetX sabrá dónde buscarlo. GetX seguirá siendo lazyLoad y se ocupará de eliminar los controllers cuando ya no sean necesarios. Vea el ejemplo pub.dev para ver cómo funciona.\n\nSi navega por muchas rutas y necesita datos que estaban en su Controller utilizado previamente, solo necesita usar nuevamente GetBuilder (sin init):\n\n```dart\nclass OtherClass extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      body: Center(\n        child: GetBuilder<Controller>(\n          builder: (s) => Text('${s.counter}'),\n        ),\n      ),\n    );\n  }\n```\n\nSi necesita usar su Controller en muchos otros lugares y fuera de GetBuilder, simplemente cree un get en su Controller y obténgalo fácilmente. (o use `Get.find <Controller>()`)\n\n```dart\nclass Controller extends GetXController {\n\n  /// You do not need that. I recommend using it just for ease of syntax.\n  /// with static method: Controller.to.increment();\n  /// with no static method: Get.find<Controller>().increment();\n  /// 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.\n  static Controller get to => Get.find(); // add this line\n\n  int counter = 0;\n  void increment() {\n    counter++;\n    update();\n  }\n}\n```\n\nY luego puede acceder a su Controller directamente, de esa manera:\n\n```dart\nFloatingActionButton(\n  onPressed: () {\n    Controller.to.increment(),\n  } // This is incredibly simple!\n  child: Text(\"${Controller.to.counter}\"),\n),\n```\n\nCuando presiona FloatingActionButton, todos los widgets que escuchan la variable 'counter' se actualizarán automáticamente.\n\n### Cómo maneja los Controllers\n\nDigamos que tenemos esto:\n\n`Class a => Class B (has controller X) => Class C (has controller X)`\n\nEn la clase A, el Controller aún no está en la memoria, porque aún no lo ha utilizado (GetX es lazyLoad). En la clase B usaste el Controller y entró en la memoria. En la clase C usó el mismo Controller que en la clase B, GetX compartirá el estado del Controller B con el Controller C, y el mismo Controller todavía está en la memoria. Si cierra la pantalla C y la pantalla B, GetX eliminará automáticamente Controller X de la memoria y liberará recursos, porque la clase A no está utilizando Controller. Si navega nuevamente hacia B, Controller X ingresará nuevamente a la memoria, si en lugar de ir a la clase C, regresa nuevamente a la clase A, GetX eliminará el Controller de la misma manera. Si la clase C no usó el Controller, y usted sacó la clase B de la memoria, ninguna clase estaría usando Controller X y de la misma manera se eliminaría. La única excepción que puede interferir con GetX es si elimina B de la ruta de forma inesperada e intenta utilizar el Controller en C. En este caso, se eliminó el creator ID del Controller que estaba en B y GetX se programó para eliminar de la memoria cada controller que no tiene creator ID. Si tiene la intención de hacer esto, agregue el indicador \"autoRemove: false\" al GetBuilder de clase B y use \"adoptID = true;\" en GetBuilder de la clase C.\n\n### Ya no necesitará StatefulWidgets\n\nUsar StatefulWidgets significa almacenar el estado de pantallas enteras innecesariamente, incluso si necesita reconstruir mínimamente un widget, lo incrustará en un Consumer/Observer/BlocProvider/GetBuilder/GetX/Obx, que será será también otro StatefulWidget.\n\nLa clase StatefulWidget es una clase más grande que StatelessWidget, que asignará más RAM, y esto puede no hacer una diferencia significativa entre una o dos clases, ¡pero sin duda lo hará cuando tenga 100 de ellas!\nA menos que necesite usar un mixin, como TickerProviderStateMixin, será totalmente innecesario usar un StatefulWidget con GetX.\n\nPuede 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;\n\n```dart\nGetBuilder<Controller>(\n  initState: (_) => Controller.to.fetchApi(),\n  dispose: (_) => Controller.to.closeStreams(),\n  builder: (s) => Text('${s.username}'),\n),\n```\n\nUn enfoque mucho mejor que esto es utilizar el método onInit() y onClose() directamente desde su Controller.\n\n```dart\n@override\nvoid onInit() {\n  fetchApi();\n  super.onInit();\n}\n```\n\n- NOTA: Si desea iniciar un método en el momento en que se llama al Controller por primera vez, NO NECESITA usar constructores para esto, de hecho, usando un paquete orientado al rendimiento como GetX, esto sería casi una mala práctica, debido a que se desvía de la lógica en la que los controllers son creados o asignados (si crea una instancia de este controller, se llamará al constructor inmediatamente, completará un Controller antes de que se use, estará asignando memoria sin ser usado, esto definitivamente perjudica los principios de esta biblioteca). Los métodos onInit(); y onClose(); fueron creados para esto, se los llamará cuando se cree el controller, o se use por primera vez, dependiendo de si está utilizando GetX.lazyPut o no. Si desea, por ejemplo, hacer una llamada a su API para llenar datos, puede olvidarse del viejo método initState/dispose, simplemente inicie su llamada a la API en onInit y si necesita ejecutar algún comando como cerrar streams, use onClose() para eso.\n\n### Por qué existe\n\nEl propósito de este paquete es precisamente brindarle una solución completa para la navegación de rutas, la gestión de dependencias y de estados, utilizando la menor cantidad de dependencias posibles, con un alto grado de desacoplamiento. GetX se acopla internamente a todas las API de Flutter de alto y bajo nivel, para garantizar que trabaje con el menor acoplamiento posible. Centralizamos todo en un solo paquete, para garantizar que no tenga ningún otro tipo de acoplamiento en su proyecto. De esa manera, puede poner solo widgets en su vista y dejar libre la parte de su equipo que trabaja con la lógica de negocios, sin depender de ningún elemento de la vista. Esto proporciona un entorno de trabajo mucho más limpio y ordenado, de modo tal que parte de su equipo trabajará solo con widgets, sin preocuparse por tener que enviar datos a su Controller, mientras la otra parte de su equipo trabajará solo con lógica de negocios, sin depender de ningún elemento de la UI.\n\nEntonces, para simplificar esto:\n\nNo necesita llamar a métodos en initState y enviarlos por parámetro a su Controller, ni usar un constructor Controller. Para eso tiene el método onInit() que se llamará en el momento adecuado para que sus servicios sean iniciados. No necesita llamar a dispose(), dado que dispone del método onClose() que se llamará en el momento exacto en que su Controller ya no se necesita, y se eliminará de la memoria. De esa manera, deje las vistas solo para widgets, y abstenerse de incluír cualquier tipo de lógica de negocios.\n\nNo llame a un método dispose() dentro de GetXController, no hará nada, recuerde que Controller no es un widget, no debe \"eliminarlo\" y GetX lo eliminará de forma automática e inteligente de la memoria. Si utilizó algún stream en él y desea cerrarlo, simplemente insértelo en el método de cierre.\n\nEjemplo:\n\n```dart\nclass Controller extends GetXController {\n  StreamController<User> user = StreamController<User>();\n  StreamController<String> name = StreamController<String>();\n\n  /// close stream = onClose method, not dispose.\n  @override\n  void onClose() {\n    user.close();\n    name.close();\n    super.onClose();\n  }\n}\n```\n\nCiclo de vida del Controller:\n\n- onInit() donde se crea.\n- onClose() donde está cerrado para cualquier tipo de modificación en preparación para ser removido.\n- deleted: no tiene acceso a esta API porque literalmente el Controller está eliminando de la memoria, sin dejar rastro (literal).\n\n### Otras formas de usarlo\n\nPuede usar la instancia de Controller directamente en el value de GetBuilder:\n\n```dart\nGetBuilder<Controller>(\n  init: Controller(),\n  builder: (value) => Text(\n    '${value.counter}', //here\n  ),\n),\n```\n\nTambién puede necesitar una instancia de su Controller fuera de su GetBuilder, y puede usar estos enfoques para lograr esto:\n\n```dart\nclass Controller extends GetXController {\n  static Controller get to => Get.find();\n[...]\n}\n// on you view:\nGetBuilder<Controller>(  \n  init: Controller(), // use it only first time on each controller\n  builder: (_) => Text(\n    '${Controller.to.counter}', //here\n  )\n),\n```\n\no\n\n```dart\nclass Controller extends GetXController {\n // static Controller get to => Get.find(); // with no static get\n[...]\n}\n// on stateful/stateless class\nGetBuilder<Controller>(  \n  init: Controller(), // use it only first time on each controller\n  builder: (_) => Text(\n    '${Get.find<Controller>().counter}', //here\n  ),\n),\n```\n\n- Puede utilizar enfoques \"no canónicos\" para hacer esto. Si está utilizando algún otro gestor de dependencias, como get_it, modular, etc., y solo desea entregar la instancia de Controller, puede hacer esto:\n\n```dart\nController controller = Controller();\n[...]\nGetBuilder<Controller>(\n  init: controller, //here\n  builder: (_) => Text(\n    '${controller.counter}', // here\n  ),\n),\n```\n\n### ID únicos\n\nSi desea refinar el control de actualización de widgets con GetBuilder, puede asignarles ID únicos:\n\n```dart\nGetBuilder<Controller>(\n  id: 'text'\n  init: Controller(), // use it only first time on each controller\n  builder: (_) => Text(\n    '${Get.find<Controller>().counter}', //here\n  ),\n),\n```\n\nY actualízalo de esta forma:\n\n```dart\nupdate(['text']);\n```\n\nTambién puede imponer condiciones para la actualización:\n\n```dart\nupdate(['text'], counter < 10);\n```\n\nGetX hace esto automáticamente y solo reconstruye el widget que usa la variable exacta que se modificó, 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 (ej. si se muestra 3 en pantalla y la variable cambia a 3 nuevamente, en la mayoría de los gestores de estados, esto provocará una nueva reconstrucción, pero con GetX el widget solo se reconstruirá si efectivamente su estado ha sido modificado).\n\n## Reactivo STATE_MANAGER\n\nLa programación reactiva puede alienar a muchas personas porque se dice que es complicada. GetX convierte la programación reactiva en algo tan simple que puede ser aprendido y utilizado por aquellos que comenzaron en ese mismo momento en Flutter. No, no necesitará crear StreamControllers. Tampoco necesitará crear un StreamBuilder para cada variable. No necesitará crear una clase para cada estado. No necesitará crear un get para un valor inicial. La programación reactiva con GetX es tan fácil como usar setState (¡o incluso más fácil!).\n\nImaginemos que tiene una variable \"name\" y desea que cada vez que la modifique, todos los widgets que la usan cambien automáticamente.\n\nEj. esta es tu variable \"name\":\n\n```dart\nvar name = 'Jonatas Borges';\n```\n\nPara que sea observable, solo necesita agregar \".obs\" al final:\n\n```dart\nvar name = 'Jonatas Borges'.obs;\n```\n\nEsto raya en lo absurdo cuando se trata de practicidad. ¿Qué hicimos, debajo del capó? Creamos un stream de Strings, asignamos el valor inicial \"Jonatas Borges\", advertimos a todos los widgets que usan \"Jonatas Borges\" que ahora pertenecen a esta variable, y cuando se modifica, ellos también lo harán. Esta es la magia de GetX, que solo Dart nos permite hacer.\n\nDe acuerdo, pero como sabemos, un widget solo se puede modificar si está dentro de una función, porque las clases estáticas no tienen el poder de \"auto-change\". Tendrá que crear un StreamBuilder, suscribirse para escuchar esta variable y crear una \"cascada\" de StreamBuilder si desea cambiar multiples variables en el mismo scope, ¿verdad?\nNo, no necesitas un StreamBuilder, pero tienes razón sobre las clases estáticas.\n\nBueno, en la vista, generalmente tenemos mucho boilerplate cuando queremos cambiar un widget específico. Con GetX también puedes olvidarte de esto. ¿StreamBuilder? ¿initialValue? ¿builder? No, solo necesitas jugar con esta variable dentro de un widget Obx.\n\n```dart\nObx(() => Text (controller.name));\n```\n\n¿Qué necesitas memorizar? \"Obx(() =>\"\n\nSimplemente está pasando ese widget a través de una función de flecha en un Obx. Obx es inteligente, y solo se cambiará si se modifica el valor de \"name\". Si el nombre es \"John\" y usted lo cambia \"John\", no tendrá ningún cambio en la pantalla, y Obx simplemente ignorará este cambio y no reconstruirá ningún widget, para ahorrar recursos. ¿No es increíble?\n\n¿Qué pasa si tengo 5 variables observables dentro de un Obx? Se actualizará cuando se modifique alguna de ellos. Y si tengo 30 variables en una clase, cuando actualizo una, ¿actualizará todas las variables que están en esa clase? No, solo el widget específico que usa esa variable. Y si ametrallo mi variable observable mil millones de veces con el mismo valor, ¿me congelaré en la pantalla para reconstrucciones innecesarias? No, GetX solo actualiza la pantalla cuando la variable cambia en la pantalla, si la pantalla sigue siendo la misma, no reconstruirá nada.\n\n### Ventajas\n\nGetBuilder está dirigido precisamente al control de múltiples estados. Imagine que agregó 30 productos a un carrito, hace clic en eliminar uno, al mismo tiempo que se actualiza la lista, se actualiza el precio y la insignia en el carrito de compras a un número menor. Este tipo de enfoque hace que GetBuilder sea superior, porque agrupa estados y los cambia todos a la vez sin ninguna \"lógica computacional\" para eso. GetBuilder se creó con este tipo de situación en mente, ya que para un cambio de estado efímero, puede usar setState y no necesitaría un gestor de estado. Sin embargo, hay situaciones en las que solo desea que el widget donde una determinada variable ha sido modificada sea reconstruida, y esto es lo que GetX hace con un dominio nunca antes visto.\n\nDe esa manera, si desea un controlador individual, puede asignar un ID o usar GetX. Esto depende de usted, recordando que cuantos más widgets \"individuales\" tenga, más se destacará el rendimiento de GetX, mientras que el rendimiento de GetBuilder debería ser superior cuando haya un cambio múltiple de estado.\n\nPuede usar ambos en cualquier situación, pero si desea ajustar su aplicación al máximo rendimiento posible, diría que:\n\n- si sus variables se cambian en diferentes momentos, use GetX, porque no hay competencia para ello cuando el tema es para reconstruir solo lo que es necesario,\n- si no necesita ID únicos, porque todas sus variables cambiarán cuando realice una acción, use GetBuilder, porque es un simple actualizador de estado en bloques, hecho en unas pocas líneas de código, para que haga exactamente lo que promete hacer: actualizar el estado en bloques. No hay forma de comparar RAM, CPU o cualquier otra cosa, desde un gestor de estado gigante a un simple StatefulWidget (como GetBuilder) que se actualiza cuando se llama a update(). Se hizo de una manera simple, para involucrar la menor lógica computacional, para cumplir con un solo propósito y consumiendo la menor cantidad de recursos posibles.\n\nSi quieres un poderoso gestor de estado, puedes ir sin temor a GetX. No funciona con variables, pero fluye, todo lo que contiene son streams bajo el capó. Puede usar rxDart junto con él, porque todo es streams, puede escuchar el evento de cada \"variable\", porque todo en él es streams, es literalmente BLoC, más fácil que MobX, y sin generador de código o decoraciones.\n\nSi quieres poder, GetX te ofrece el gestor de estado más avanzado que puedas tener.\n\nGetX fue construido 100% basado en Streams, y le brinda toda la potencia de fuego que BLoC le brindó, con una instalación más fácil que al de MobX.\n\nSin decoraciones, puede convertir cualquier cosa en Observable con solo un \".obs\".\n\nMáximo rendimiento: además de tener un algoritmo inteligente para una reconstrucción mínima, GetX utiliza comparadores para asegurarse de que el estado realmente haya cambiado. Si experimenta algún error en su aplicación y envía un cambio de estado duplicado, GetX se asegurará de que su aplicación no se colapse.\n\nEl estado solo cambia si los valores son modificados. Esa es la principal diferencia entre GetX y usar Computed de MobX. Al unir dos observables, cuando se cambia uno, la audiencia de ese observable cambiará. Con GetX, si une dos variables (lo cual sería innecesario), GetX (similar a Observer) solo cambiará si implica un cambio de estado real.\n\n### Uso\n\nTienes 3 formas de convertir una variable en observable.\n\nEl primero es usar Rx{Type}.\n\n```dart\nvar count = RxString();\n```\n\nEl segundo es usar Rx y escribirlo con `Rx<Type>`\n\n```dart\nvar count = Rx<String>();\n```\n\nEl tercer enfoque, más práctico, fácil e increíble, es simplemente agregar un .obs a su variable.\n\n```dart\nvar count = 0.obs;\n\n// or Rxint count = 0.obs;\n// or Rx<int> count = 0.obs;\n```\n\nComo sabemos, Dart ahora se dirige hacia el null safety. Con eso es una buena idea, de ahora en adelante, que comience a usar sus variables siempre con un valor inicial.\n\nTransformar una variable en observable con un valor inicial con GetX es el enfoque más simple y práctico que existe actualmente en Flutter. Literalmente agregará un \".obs\" al final de su variable, y eso es todo, lo ha hecho observable, y su valor será el valor inicial, ¡esto es fantástico!\n\nPuede agregar variables, y si desea escribir un widget que le permita obtener su controlador dentro, solo necesita usar el widget GetX en lugar de Obx\n\n```dart\nfinal count1 = 0.obs;\nfinal count2 = 0.obs;\nint get sum => count1.value + count2.value;\n```\n\n```dart\nGetX<Controller>(\n  builder: (value) {\n    print(\"count 1 rebuild\");\n    return Text('${value.count1.value}');\n  },\n),\nGetX<Controller>(\n  builder: (_) {\n    print(\"count 2 rebuild\");\n    return Text('${_.count2.value}');\n  },\n),\nGetX<Controller>(\n  builder: (_) {\n    print(\"count 3 rebuild\");\n    return Text('${_.sum}');\n  },\n),\n```\n\nSi incrementamos el número de counter1, solo se reconstruyen el counter1 y el counter3, porque el counter1 ahora tiene un valor de 1 y 1 + 0 = 1, cambiando el valor de la suma.\n\nSi cambiamos el counter2, solo se reconstruyen el counter2 y 3, porque el valor de 2 ha cambiado y el resultado de la suma ahora es 2.\n\nSi agregamos el número 1 para counter1, que ya contiene 1, no se reconstruye ningún widget. Si agregamos un valor de 1 para el counter1 y un valor de 2 para el counter2, solo se reconstruirán 2 y 3, porque GetX además de cambiar solo lo que es necesario, evita la duplicación de eventos.\n\n- NOTA: Por defecto, el primer evento permitirá la reconstrucción incluso si es igual. Creamos este comportamiento debido a variables dualistas, como Boolean.\n\nImaginemos que hiciste esto:\n\n```dart\nvar isLogged = false.obs;\n```\n\ny luego verifica si un usuario ha iniciado sesión para activar un evento en \"ever\".\n\n```dart\nonInit(){\n  ever(isLogged, fireRoute);\n  isLogged.value = await Preferences.hasToken();\n}\n\nfireRoute(logged) {\n  if (logged) {\n   Get.off(Home());\n  } else {\n   Get.off(Login());\n  }\n}\n```\n\nsi hasToken fuera falso, no habría cambios en isLogged, por lo que nunca se llamaría. Para evitar este tipo de comportamiento, el primer cambio a un observable siempre desencadenará un evento, incluso si es el mismo.\n\nPuede eliminar este comportamiento si lo desea, utilizando:\n`isLogged.firstRebuild = false;`\n\nAdemás, GetX proporciona control de estado refinado. Puede condicionar un evento (como agregar un objeto a una lista), en una determinada condición:\n\n```dart\nlist.addIf(item < limit, item);\n```\n\nSin decoraciones, sin un generador de código, sin complicaciones, GetX cambiará la forma en que administra sus estados en Flutter, y eso no es una promesa, ¡es una certeza!\n\n¿Conoces el counter de Flutter? Su clase de controlador podría verse así:\n\n```dart\nclass CountCtl extends GetxController {\n  final count = 0.obs;\n}\n```\n\nCon un simple:\n\n```dart\nctl.count.value++\n```\n\nPuede actualizar la variable de contador en su IU, independientemente de dónde esté almacenada.\n\n### Donde se pueden usar .obs\n\nPuedes transformar cualquier cosa en obs:\n\n```dart\nclass RxUser {\n  final name = \"Camila\".obs;\n  final age = 18.obs;\n}\n\nclass User {\n  User({String name, int age});\n  final rx = RxUser();\n\n  String get name => rx.name.value;\n  set name(String value) => rx.name.value = value;\n\n  int get age => rx.age.value;\n  set age(int value) => rx.age.value = value;\n}\n```\n\n```dart\nvoid main() {\n  final user = User();\n  print(user.name);\n  user.age = 23;\n  user.rx.age.listen((int age) => print(age));\n  user.age = 24;\n  user.age = 25;\n}\n___________\nout:\nCamila\n23\n24\n25\n```\n\n### Nota sobre listas\n\nTrabajar con listas usando GetX es lo mejor y lo más divertido del mundo. Son completamente observables como lo son los objetos dentro de él. De esa manera, si agrega un valor a una lista, reconstruirá automáticamente los widgets que lo usan.\n\nTampoco necesita usar \".value\" con las listas, la increíble api de Dart nos permitió eliminar eso, los tipos primitivos desafortunados como String e int no se pueden extender, haciendo que el uso de .value sea obligatorio, pero eso no será un problema si trabajas con gets y setters para estos.\n\n```dart\nfinal list = List<User>().obs;\n```\n\n```dart\nListView.builder (\n  itemCount: list.length\n)\n```\n\nNo tiene que trabajar con Sets si no lo desea. puede usar la api \"assign\" y \"assignAll\".\n\nLa API \"assign\" borrará su lista y agregará un solo objeto, con el que quiere comenzar allí.\n\nLa API \"assignAll\" borrará la lista existente y agregará cualquier objeto iterable que le inyecte.\n\n### ¿Por qué tengo que usar .value\n\nPodríamos eliminar la obligación de usar 'value' para String e int con una simple decoración y generador de código, pero el propósito de esta biblioteca es, precisamente, no necesitar ninguna dependencia externa. Ofrecer un entorno listo para la programación, que incluya lo esencial (gestión de rutas, dependencias y estados), de una manera simple, ligera y de gran rendimiento sin necesidad de ningún otro paquete externo. Literalmente, agrega GetX a su pubspec y puede comenzar a programar.\n\nTodas las soluciones incluidas por defecto, desde gestión de rutas a gestión de estádo, apuntan a la facilidad, la productividad y el rendimiento. El peso total de esta biblioteca es menor que el de un solo gestor de estado, aunque es una solución completa, y eso es lo que debe comprender.\n\nSi le molesta el \".value\" y, como además si se trata de un generador de código, MobX ya es una gran alternativa, puede simplemente usarlo junto con GetX.\n\nPara aquellos que desean agregar una sola dependencia en pubspec y comenzar a programar sin preocuparse de que la versión de un paquete sea incompatible con otra, o si el error de una actualización de estado proviene de gestor de estado o dependencia, o aún, no quieren preocuparse por la disponibilidad de controladores, ya sea literalmente \"solo programación\", GetX es simplemente perfecto.\n\nSi no tiene ningún problema con el generador de código de MobX, o no tiene ningún problema con el boilerplate de BLoC, simplemente puede usar GetX para las rutas y olvidar que incluye un gestor de estado. GetX, SEM y RSM nacieron por necesidad, mi empresa tenía un proyecto con más de 90 controladores, y el generador de código tardó más de 30 minutos en completar sus tareas después de un Flutter Clean en una máquina razonablemente buena. Si su proyecto tiene 5, 10, 15 controladores, cualquier gestor de estado te vendrá bien. Si tiene un proyecto absurdamente grande y el generador de código es un problema para usted, se le ha otorgado esta solución.\n\nObviamente, si alguien quiere contribuir al proyecto y crear un generador de código, o algo similar, lo añadiré a este archivo como una alternativa, mi necesidad no es la necesidad de todos los desarrolladores, pero lo que ahora digo es que hay buenas soluciones que ya hacen eso, como MobX.\n\n### Obx()\n\nEl Typing en GetX usando Bindings es innecesario. Puede usar el widget Obx (en lugar de GetX), que solo recibe la función anónima que crea un widget.\n\nObviamente, si no usa un tipo, necesitará tener una instancia de su controlador para usar las variables, o usar `Get.find <Controller>()` .value o Controller.to.value para recuperar el valor.\n\n### Workers\n\nLos workers lo ayudarán, activando callbacks específicos cuando ocurra un evento.\n\n```dart\n/// Called every time the variable $_ is changed\never(count1, (_) => print(\"$_ has been changed\"));\n\n/// Called only first time the variable $_ is changed\nonce(count1, (_) => print(\"$_ was changed once\"));\n\n/// Anti DDos - Called every time the user stops typing for 1 second, for example.\ndebounce(count1, (_) => print(\"debouce$_\"), time: Duration(seconds: 1));\n\n/// Ignore all changes within 1 second.\ninterval(count1, (_) => print(\"interval $_\"), time: Duration(seconds: 1));\n```\n\n- ever: se llama cada vez que se cambia su variable. Eso es.\n\n- once: se llama solo la primera vez que se ha cambiado la variable.\n\n- debounce: es muy útil en las funciones de búsqueda, donde solo desea que se llame a la API cuando el usuario termina de escribir. Si el usuario escribe \"JONNY\", tendrá 5 búsquedas en las API, por la letra J, O, N, N e Y. Con GetX esto no sucede, porque tendrá un worker \"debounce\" que solo se activará al final de la escritura.\n\n- interval: es diferente del debouce. Con debouce si el usuario realiza 1000 cambios en una variable dentro de 1 segundo, enviará solo el último después del timer estipulado (el valor predeterminado es 800 milisegundos). En cambio, el interval ignorará todas las acciones del usuario durante el período estipulado. Si envía eventos durante 1 minuto, 1000 por segundo, la función antirrebote solo le enviará el último, cuando el usuario deje de enviar eventos. Interval entregará eventos cada segundo, y si se establece en 3 segundos, entregará 20 eventos ese minuto. Esto se recomienda para evitar abusos, en funciones en las que el usuario puede hacer clic rápidamente en algo y obtener alguna ventaja (imagine que el usuario puede ganar monedas haciendo clic en algo, si hace clic 300 veces en el mismo minuto, tendría 300 monedas, usando el interval, puede establecer un time frame de 3 segundos, e incluso luego hacer clic 300 o mil veces, el máximo que obtendría en 1 minuto sería 20 monedas, haciendo clic 300 o 1 millón de veces). El debouce es adecuado para anti-DDos, para funciones como la búsqueda donde cada cambio en onChange provocaría una consulta en su API. Debounce esperará a que el usuario deje de escribir el nombre para realizar la solicitud. Si se usara en el escenario de monedas mencionado anteriormente, el usuario solo ganaría 1 moneda, ya que solo se ejecuta cuando el usuario \"hace una pausa\" durante el tiempo establecido.\n\n- NOTE: Los Workers siempre deben usarse al iniciar un controlador o clase, por lo que siempre debe estar en onInit (recomendado), Class Constructor o initState de un StatefulWidget (esta práctica no se recomienda en la mayoría de los casos, pero no debería tener efectos secundarios).\n\n## Mezclando los dos State Managers\n\nAlgunas personas abrieron una feature request, ya que querían usar solo un tipo de variable reactiva, y la otra mecánica, y necesitaban insertar un Obx en un GetBuilder para esto. Pensando en ello, se creó MixinBuilder. Permite cambios reactivos cambiando las variables \".obs\" y actualizaciones mecánicas a través de update(). Sin embargo, de los 4 widgets, 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 update de su controlador.\n\nExtender GetxController es importante, ya que tienen ciclos de vida y pueden \"iniciar\" y \"finalizar\" eventos en sus métodos onInit() y onClose(). Puede usar cualquier clase para esto, pero le recomiendo que use la clase GetxController para colocar sus variables, sean observables o no.\n\n## GetBuilder vs GetX vs Obx vs MixinBuilder\n\nEn una década trabajando con programación pude aprender algunas lecciones valiosas.\n\nMi primer contacto con la programación reactiva fue tan \"guau, esto es increíble\" y, de hecho, la programación reactiva es increíble.\n\nSin embargo, no es adecuado para todas las situaciones. A menudo, todo lo que necesita es cambiar el estado de 2 o 3 widgets al mismo tiempo, o un cambio de estado efímero, en cuyo caso la programación reactiva no es mala, pero no es apropiada.\n\nLa programación reactiva tiene un mayor consumo de RAM que se puede compensar con el workflow individual, lo que garantizará que solo se reconstruya un widget y cuando sea necesario, pero crear una lista con 80 objetos, cada uno con varios streams no es una buena idea. Abra el dart inspector y compruebe cuánto consume un StreamBuilder, y comprenderá lo que estoy tratando de decirle.\n\nCon eso en mente, creé el Simple State Manager. Es simple, y eso es exactamente lo que debe exigirle: actualizar el estado en bloques de una manera simple y de la manera más económica.\n\nGetBuilder es muy económico en RAM, y es difícil que haya un enfoque más económico que él (al menos no puedo imaginar uno, si existe, háganoslo saber).\n\nSin embargo, GetBuilder sigue siendo un gestor de estado mecánico, debe llamar a update() al igual que necesitaría llamar a notifyListeners() con Provider.\n\nHay 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 eso en mente, GetX fue creado para proporcionar todo lo más moderno y avanzado en un gestor de estado. Actualiza solo lo necesario y solo si es necesario, si tiene un error y envía 300 cambios de estado simultáneamente, GetX lo filtrará y actualizará la pantalla solo si el estado realmente fue modificado.\n\nGetX 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 con el objetivo de maximizar el consumo de recursos es que se creó Obx. A diferencia de GetX y GetBuilder, no podrá inicializar un controlador dentro de un Obx, es solo un Widget con una stream suscription que recibe eventos de cambio de sus children, eso es todo. Es más económico que GetX, pero pierde con GetBuilder, lo que era de esperar, ya que es reactivo, y GetBuilder tiene el enfoque más simplista que existe, de almacenar el código hash de un widget y su StateSetter. Con Obx no necesita escribir su tipo de controlador, y puede escuchar el cambio desde varios controladores diferentes, pero debe inicializarse antes, ya sea utilizando el enfoque de ejemplo al comienzo de este archivo o utilizando la clase Bindings.\n"
  },
  {
    "path": "documentation/fr_FR/dependency_management.md",
    "content": "# Gestion des dépendances\n- [Gestion des dépendances](#Gestion-des-dépendances)\n  - [Instanciation des methodes](#Instanciation-des-methodes)\n    - [Get.put()](#getput)\n    - [Get.lazyPut](#getlazyput)\n    - [Get.putAsync](#getputasync)\n    - [Get.create](#getcreate)\n  - [Utilisation de méthodes/classes instanciées](#utilisation-de-mthodes-classes-instancies)\n  - [Différences entre les méthodes](#differences-entre-les-methodes)\n  - [Bindings](#bindings)\n    - [Classe Bindings](#classe-bindings)\n    - [BindingsBuilder](#bindingsbuilder)\n    - [SmartManagement](#smartmanagement)\n      - [Comment changer](#comment-changer)\n      - [SmartManagement.full](#smartmanagementfull)\n      - [SmartManagement.onlyBuilders](#smartmanagementonlybuilders)\n      - [SmartManagement.keepFactory](#smartmanagementkeepfactory)\n    - [Comment Bindings fonctionne sous le capot](#comment-bindings-fonctionne-sous-le-capot)\n  - [Notes](#notes)\n\nGet a un gestionnaire de dépendances simple et puissant qui vous permet de récupérer la même classe que votre Bloc ou Controller avec une seule ligne de code, pas de context Provider, pas d' inheritedWidget:\n\n```dart\nController controller = Get.put(Controller()); // Au lieu de Controller controller = Controller();\n```\n\nAu lieu d'instancier votre classe dans la classe que vous utilisez, vous l'instanciez dans l'instance Get, qui la rendra disponible dans toute votre application.\nVous pouvez donc utiliser votre contrôleur (ou classe Bloc) normalement\n\n- Note: Si vous utilisez le gestionnaire d'état de Get, faites plus attention à l'API [Bindings] (# bindings), qui facilitera la connexion de votre vue à votre contrôleur.\n- Note²: La gestion des dépendances est découplée des autres parties du package, donc si, par exemple, votre application utilise déjà un gestionnaire d'état (n'importe lequel, peu importe), vous n'avez pas besoin de changer cela, vous pouvez utiliser ce manager d'injection de dépendance sans aucun problème.\n\n## Instanciation des methodes\nLes méthodes et leurs paramètres configurables sont:\n\n### Get.put()\n\nLa manière la plus courante d'insérer une dépendance. Bon pour les contrôleurs de vos vues par exemple.\n\n```dart\nGet.put<SomeClass>(SomeClass());\nGet.put<LoginController>(LoginController(), permanent: true);\nGet.put<ListItemController>(ListItemController, tag: \"un String unique\");\n```\n\nCe sont toutes les options que vous pouvez définir lorsque vous utilisez put:\n```dart\nGet.put<S>(\n  // obligatoire: la classe que vous voulez que get enregistre, comme un 'controler' ou autre\n  // note: \"S\" signifie que ca peut etre une classe de n'importe quel type\n  S dependency\n\n  // optionnel: c'est pour quand vous voulez plusieurs classes qui sont du même type\n  // puisque vous obtenez normalement une classe en utilisant Get.find<Controller>(),\n  // vous devez utiliser ce tag pour indiquer de quelle instance vous avez besoin\n  // doit être un String unique\n  String tag,\n\n  // optionnel: par défaut, get supprimera les instances une fois qu'elles ne seront plus utilisées (exemple,\n  // le contrôleur d'une vue qui est fermée), mais vous pourriez avoir besoin que l'instance\n  // soit conservée dans toute l'application, comme une instance de sharedPreferences ou quelque chose du genre\n  // donc vous utilisez ceci\n  // équivaut à false par défaut\n  bool permanent = false,\n\n  // facultatif: permet après avoir utilisé une classe abstraite dans un test, de la remplacer par une autre et de suivre le test.\n  // équivaut à false par défaut\n  bool overrideAbstract = false,\n\n  // facultatif: vous permet de créer la dépendance en utilisant la fonction au lieu de la dépendance elle-même.\n  // ce n'est pas couramment utilisé\n  InstanceBuilderCallback<S> builder,\n)\n```\n\n### Get.lazyPut\nIl est possible de lazyLoad une dépendance afin qu'elle ne soit instanciée que lorsqu'elle est utilisée. Très utile pour les classes qui demandent beaucoup de ressources ou si vous souhaitez instancier plusieurs classes en un seul endroit (comme dans une classe Bindings) et que vous savez que vous n'utiliserez pas cette classe à ce moment-là.\n\n```dart\n/// ApiMock ne sera appelé que lorsque quelqu'un utilise Get.find <ApiMock> pour la première fois\nGet.lazyPut<ApiMock>(() => ApiMock());\n\nGet.lazyPut<FirebaseAuth>(\n  () {\n    // ... some logic if needed\n    return FirebaseAuth();\n  },\n  tag: Math.random().toString(),\n  fenix: true\n)\n\nGet.lazyPut<Controller>(() => Controller() )\n```\n\nCe sont toutes les options que vous pouvez définir lors de l'utilisation de lazyPut:\n```dart\nGet.lazyPut<S>(\n  // obligatoire: une méthode qui sera exécutée lorsque votre classe sera appelée pour la première fois\n  InstanceBuilderCallback builder,\n  \n  // facultatif: identique à Get.put(), il est utilisé lorsque vous voulez plusieurs instances différentes d'une même classe\n  // doit être unique\n  String tag,\n\n  // facultatif: cela est similaire à \"permanent\", la différence est que l'instance est supprimée lorsqu'elle\n  // n'est pas utilisée, mais lorsqu'elle est à nouveau nécessaire, Get recrée l'instance\n  // identique à \"SmartManagement.keepFactory\" dans l'API Bindings\n  // vaut false par défaut\n  bool fenix = false\n  \n)\n```\n\n### Get.putAsync\nSi vous souhaitez enregistrer une instance async, vous pouvez utiliser `Get.putAsync`:\n\n```dart\nGet.putAsync<SharedPreferences>(() async {\n  final prefs = await SharedPreferences.getInstance();\n  await prefs.setInt('counter', 12345);\n  return prefs;\n});\n\nGet.putAsync<YourAsyncClass>(() async => await YourAsyncClass())\n```\n\nCe sont toutes les options que vous pouvez définir lors de l'utilisation de putAsync:\n```dart\nGet.putAsync<S>(\n\n  // obligatoire: une méthode async qui sera exécutée pour instancier votre classe\n  AsyncInstanceBuilderCallback<S> builder,\n\n  // facultatif: identique à Get.put(), il est utilisé lorsque vous voulez plusieurs instances différentes d'une même classe\n  // doit être unique\n  String tag,\n\n  // facultatif: identique à Get.put(), utilisé lorsque vous devez maintenir cette instance active dans l'ensemble de l'application\n  // vaut false par défaut\n  bool permanent = false\n)\n```\n\n### Get.create\n\nCelui-ci est délicat. Une explication détaillée de ce que c'est et des différences d'avec les autres peut être trouvée dans la section [Différences entre les méthodes:](#differences-entre-les-methodes).\n\n```dart\nGet.Create<SomeClass>(() => SomeClass());\nGet.Create<LoginController>(() => LoginController());\n```\n\nCe sont toutes les options que vous pouvez définir lors de l'utilisation de create:\n\n```dart\nGet.create<S>(\n  // requis: une fonction qui renvoie une classe qui sera \"fabriquée\" chaque\n  // fois que `Get.find()` est appelé\n  // Exemple: Get.create<YourClass>(() => YourClass())\n  FcBuilderFunc<S> builder,\n\n  // facultatif: comme Get.put(), mais il est utilisé lorsque vous avez besoin de plusieurs instances\n  // d'une même classe\n  // Utile dans le cas où vous avez une liste oú chaque élément a besoin de son propre contrôleur\n  // doit être une String unique. Changez simplement de 'tag' en 'name'\n  String name,\n\n  // optionnel: tout comme dans `Get.put()`, c'est pour quand vous devez garder l'\n  // instance vivante dans toute l'application. La différence est que dans Get.create,\n  // permanent est 'true' par défaut\n  bool permanent = true\n```\n\n## Utilisation de méthodes/classes instanciées\n\nImaginez que vous ayez parcouru de nombreuses routes et que vous ayez besoin d'une donnée qui a été laissée dans votre contrôleur, vous auriez besoin d'un gestionnaire d'état combiné avec le 'Provider' ou Get_it, n'est-ce pas? Pas avec Get. Il vous suffit de demander à Get de \"find\" (trouver) votre contrôleur, vous n'avez pas besoin de dépendances supplémentaires:\n\n```dart\nfinal controller = Get.find<Controller>();\n// OR\nController controller = Get.find();\n\n// Oui, cela ressemble à Magic, Get trouvera votre contrôleur et vous le livrera.\n// Vous pouvez avoir 1 million de contrôleurs instanciés, Get vous trouvera toujours le bon contrôleur.\n```\n\nEt puis vous pourrez récupérer les données de votre contrôleur qui ont été obtenues là-bas:\n\n```dart\nText(controller.textFromApi);\n```\n\nLa valeur renvoyée étant une classe normale, vous pouvez faire tout ce que vous voulez:\n```dart\nint count = Get.find<SharedPreferences>().getInt('counter');\nprint(count); // donne: 12345\n```\n\nPour supprimer une instance de Get:\n\n```dart\nGet.delete<Controller>(); //généralement, vous n'avez pas besoin de le faire car GetX supprime déjà les contrôleurs inutilisés-\n```\n\n## Differences entre les methodes\n\nCommençons par le `fenix` de Get.lazyPut et le `permanent` des autres méthodes.\n\nLa différence fondamentale entre `permanent` et `fenix` réside dans la manière dont vous souhaitez stocker vos instances.\n\nRenforcement: par défaut, GetX supprime les instances lorsqu'elles ne sont pas utilisées.\nCela signifie que: Si l'écran 1 a le contrôleur 1 et l'écran 2 a le contrôleur 2 et que vous supprimez la première route du Stack, (comme si vous utilisez `Get.off()` ou `Get.offNamed()`) le contrôleur 1 a perdu son utilisation, il sera donc effacé.\n\nMais si vous optez pour l'utilisation de `permanent: true`, alors le contrôleur ne sera pas perdu dans cette transition - ce qui est très utile pour les services que vous souhaitez maintenir actif dans toute l'application.\n\n`fenix`, quant à lui, est destiné aux services que vous ne craignez pas de perdre entre les changements d'écran, mais lorsque vous avez besoin de ce service, vous vous attendez à ce qu'il soit vivant. Donc, fondamentalement, il supprimera le contrôleur / service / classe inutilisé, mais lorsque vous en aurez besoin, il \"recréera à partir de ses cendres\" une nouvelle instance.\n\nDifférences entre les méthodes:\n\n- Get.put et Get.putAsync suivent le même ordre de création, à la différence que la seconde utilise une méthode asynchrone: ces deux méthodes créent et initialisent l'instance. Celle-ci est insérée 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 a pour seul but de dire s'il faut utiliser la dépendance sur` dependency` ou s'il doit utiliser la dépendance sur `FcBuilderFunc`). Après cela, `Get.find()` est appelé pour initialiser immédiatement les instances qui sont en mémoire.\n\n- Get.create: Comme son nom l'indique, il \"créera\" votre dépendance! Similaire à `Get.put()`, il appelle également la méthode interne `insert` pour l'instanciation. Mais `permanent` devient vrai et` isSingleton` devient faux (puisque nous \"créons\" notre dépendance, il n'y a aucun moyen pour que ce soit une instance singleton, c'est pourquoi il est faux). Et comme il a `permanent: true`, nous avons par défaut l'avantage de ne pas le perdre entre les écrans! De plus, `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 convient de noter que` Get.create() `a été créé dans le but de créer des instances non partagées, mais qui ne sont pas supprimées, comme par exemple un bouton dans un listView, pour lequel vous voulez une instance unique pour cette liste - à cause de cela, Get.create doit être utilisé avec GetWidget.\n\n- Get.lazyPut: Comme son nom l'indique, il s'agit d'un processus 'paresseux'. L'instance est créée, mais elle n'est pas appelée pour être utilisée immédiatement, elle reste en attente d'être appelée. Contrairement aux autres méthodes, `insert` n'est pas appelé ici. Au lieu de cela, l'instance est insérée dans une autre partie de la mémoire, une partie chargée de dire si l'instance peut être recréée ou non, appelons-la \"factory\". Si nous voulons créer quelque chose pour être utilisé plus tard, il ne sera pas mélangé avec les choses actuellement utilisées. Et voici où la magie de `fenix` apparaît: si vous choisissez de laisser` fenix: false`, et que votre `smartManagement` n'est pas` keepFactory`, alors lors de l'utilisation de `Get.find`, l'instance changera la place dans la mémoire de la \"factory\" à la zone de mémoire d'instance commune. Juste après cela, par défaut, il est retiré de `la factory`. Maintenant, si vous optez pour `fenix: true`, l'instance continue d'exister dans cette partie dédiée, allant même vers la zone commune, pour être appelée à nouveau dans le futur.\n\n## Bindings\n\nL'une des grandes différences de ce package, peut-être, est la possibilité d'une intégration complète des routes, du gestionnaire d'état et du gestionnaire de dépendances.\nLorsqu'une route est supprimée de la pile, tous les contrôleurs, variables et instances d'objets qui lui sont associés sont supprimés de la mémoire. Si vous utilisez des streams ou timers, ils seront fermés automatiquement et vous n'aurez à vous soucier de rien de tout cela.\nDans la version 2.10, Get a complètement implémenté l'API Bindings.\nVous n'avez plus besoin d'utiliser la méthode init. Vous n'avez même pas besoin de `typer`(declaration de type) vos contrôleurs si vous ne le souhaitez pas. Vous pouvez démarrer vos contrôleurs et services à l'endroit approprié pour cela.\nLa classe Binding est une classe qui découplera l'injection de dépendances, en faisant du \"binding\" des routes entre le gestionnaire d'état et le gestionnaire de dépendances.\nCela permet à Get de savoir quel écran est affiché lorsqu'un contrôleur particulier est utilisé et de savoir où et comment s'en débarrasser.\nDe plus, la classe Binding vous permettra d'avoir le contrôle de la configuration de SmartManager. Vous pouvez configurer les dépendances à organiser lors de la suppression d'une route du Stack, ou lorsque le widget qui l'utilisait est disposé, ou ni l'un ni l'autre. Vous disposerez d'une gestion intelligente des dépendances qui fonctionnera pour vous, mais vous pourrez malgré tout la configurer comme vous le souhaitez.\n\n### Classe Bindings\n\n- Créer une classe et implémenter Bindings\n\n```dart\nclass HomeBinding implements Bindings {}\n```\n\nVotre IDE vous demandera automatiquement de remplacer la méthode \"dependencies\", et il vous suffit de cliquer sur la lampe, de remplacer la méthode et d'insérer toutes les classes que vous allez utiliser sur cette route:\n\n```dart\nclass HomeBinding implements Bindings {\n  @override\n  void dependencies() {\n    Get.lazyPut<HomeController>(() => HomeController());\n    Get.put<Service>(()=> Api());\n  }\n}\n\nclass DetailsBinding implements Bindings {\n  @override\n  void dependencies() {\n    Get.lazyPut<DetailsController>(() => DetailsController());\n  }\n}\n```\n\nIl vous suffit maintenant d'informer votre route, que vous utiliserez ce Binding pour établir la connexion entre le gestionnaire de routes, les dépendances et les états.\n\n- En utilisant les routes nommées:\n\n```dart\ngetPages: [\n  GetPage(\n    name: '/',\n    page: () => HomeView(),\n    binding: HomeBinding(),\n  ),\n  GetPage(\n    name: '/details',\n    page: () => DetailsView(),\n    binding: DetailsBinding(),\n  ),\n];\n```\n\n- En utilisant les routes normales:\n\n```dart\nGet.to(Home(), binding: HomeBinding());\nGet.to(DetailsView(), binding: DetailsBinding())\n```\n\nLà, vous n'avez plus à vous soucier de la gestion de la mémoire de votre application, Get le fera pour vous.\n\nLa classe Binding 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.\n\n```dart\nGetMaterialApp(\n  initialBinding: SampleBind(),\n  home: Home(),\n);\n```\n\n### BindingsBuilder\n\nLa manière par défaut de créer un binding est de créer une classe qui implémente Bindings.\n\nMais alternativement, vous pouvez utiliser le callback `BindingsBuilder` afin de pouvoir simplement utiliser une fonction pour instancier ce que vous désirez.\n\nExemple:\n\n```dart\ngetPages: [\n  GetPage(\n    name: '/',\n    page: () => HomeView(),\n    binding: BindingsBuilder(() {\n      Get.lazyPut<ControllerX>(() => ControllerX());\n      Get.put<Service>(()=> Api());\n    }),\n  ),\n  GetPage(\n    name: '/details',\n    page: () => DetailsView(),\n    binding: BindingsBuilder(() {\n      Get.lazyPut<DetailsController>(() => DetailsController());\n    }),\n  ),\n];\n```\n\nDe cette façon, vous pouvez éviter de créer une classe Binding pour chaque route, ce qui est encore plus simple.\n\nLes deux méthodes fonctionnent parfaitement bien et nous voulons que vous utilisiez ce qui correspond le mieux à vos goûts.\n\n### SmartManagement\n\nGetX par défaut supprime les 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 supprimé.\nC'est ce qu'on appelle le mode `full` de gestion des dépendances.\nMais si vous voulez changer la façon dont GetX contrôle la suppression des classes, vous avez la classe `SmartManagement` pour définir différents comportements.\n\n#### Comment changer\n\nSi vous souhaitez modifier cette configuration (dont vous n'avez généralement pas besoin), procédez comme suit:\n\n```dart\nvoid main () {\n  runApp(\n    GetMaterialApp(\n      smartManagement: SmartManagement.onlyBuilders //Ici\n      home: Home(),\n    )\n  )\n}\n```\n\n#### SmartManagement.full\n\nC'est celui par défaut. Supprime les classes qui ne sont pas utilisées et qui n'ont pas été définies pour être permanentes. Dans la majorité des cas, vous voudrez garder cette configuration intacte. Si vous débutez avec GetX, ne changez pas cela.\n\n#### SmartManagement.onlyBuilders\n\nAvec cette option, seuls les contrôleurs démarrés dans `init:` ou chargés dans un  Binding avec `Get.lazyPut()` seront supprimés.\n\nSi vous utilisez `Get.put()` ou `Get.putAsync()` ou toute autre approche, SmartManagement n'aura pas les autorisations pour exclure cette dépendance.\n\nAvec le comportement par défaut, même les widgets instanciés avec \"Get.put\" seront supprimés, contrairement à SmartManagement.onlyBuilders.\n\n#### SmartManagement.keepFactory\n\nTout comme SmartManagement.full, il supprimera ses dépendances lorsqu'elles ne seront plus utilisées. Cependant, il conservera leur factory, ce qui signifie qu'il recréera la dépendance si vous avez à nouveau besoin de cette instance.\n\n### Comment Bindings fonctionne sous le capot\n\nBindings crée des `'factories' transitoires`, qui sont créées au moment où vous cliquez pour aller à un autre écran, et seront détruites dès que l'animation de changement d'écran se produit.\nCela arrive si vite que l'analyseur ne pourra même pas l'enregistrer.\nLorsque vous accédez à nouveau à cet écran, une nouvelle fabrique temporaire sera appelée, c'est donc préférable à l'utilisation de SmartManagement.keepFactory, mais si vous ne voulez pas créer de Bindings, ou si vous voulez garder toutes vos dépendances sur le même Binding , cela vous aidera certainement.\nLes factories prennent peu de mémoire, elles ne contiennent pas d'instances, mais une fonction avec la \"forme\" de cette classe que vous voulez.\nCela a un très faible coût en mémoire, mais comme le but de cette bibliothèque est d'obtenir le maximum de performances possible en utilisant le minimum de ressources, Get supprime même les factories par défaut.\nUtilisez celui qui vous convient le mieux.\n\n## Notes\n\n- N'UTILISEZ PAS SmartManagement.keepFactory si vous utilisez plusieurs Bindings. Il a été conçu pour être utilisé sans Bindings ou avec une seule Binding liée dans le fichier initialBinding de GetMaterialApp.\n\n- L'utilisation de Bindings est complètement facultative, 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.\n  Cependant, si vous travaillez avec des services ou toute autre abstraction, je vous recommande d'utiliser Bindings pour une meilleure organisation."
  },
  {
    "path": "documentation/fr_FR/route_management.md",
    "content": "- [Gestion de route](#gestion-de-route)\n  - [Utilisation](#utilisation)\n  - [Navigation sans nom](#navigation-sans-nom)\n  - [Navigation par nom](#navigation-par-nom)\n    - [Envoyer des données aux routes nommées](#envoyer-des-donnes-aux-routes-nommes)\n    - [Liens URL dynamiques](#liens-url-dynamiques)\n    - [Middleware](#middleware)\n  - [Navigation sans context](#navigation-sans-context)\n    - [SnackBars](#snackbars)\n    - [Dialogs](#dialogs)\n    - [BottomSheets](#bottomsheets)\n  - [Nested Navigation](#nested-navigation)\n\n# Gestion de route\n\nC'est l'explication complète de tout ce qu'il y a à savoir sur Getx quand il s'agit de la gestion des routes.\n\n## Utilisation\n\nAjoutez ceci à votre fichier pubspec.yaml:\n\n```yaml\ndependencies:\n  get:\n```\n\nSi vous allez utiliser des routes/snackbars/dialogs/bottomsheets sans contexte, ou utiliser les API Get de haut niveau, vous devez simplement ajouter \"Get\" avant votre MaterialApp, en le transformant en GetMaterialApp et en profiter!\n\n```dart\nGetMaterialApp( // Avant: MaterialApp(\n  home: MyHome(),\n)\n```\n\n## Navigation sans nom\n\nPour accéder à un nouvel écran:\n\n```dart\nGet.to(NextScreen());\n```\n\nPour fermer les snackbars, dialogs, bottomsheets ou tout ce que vous fermez normalement avec Navigator.pop(context);\n\n```dart\nGet.back();\n```\n\nPour aller à l'écran suivant et aucune option pour revenir à l'écran précédent (pour une utilisation dans SplashScreens, écrans de connexion, etc.)\n\n```dart\nGet.off(NextScreen());\n```\n\nPour aller à l'écran suivant et annuler toutes les routes précédents (utile dans les paniers d'achat e-commerce, les sondages et les tests)\n\n```dart\nGet.offAll(NextScreen());\n```\n\nPour naviguer vers l'écran suivant et recevoir ou mettre à jour des données dès que vous en revenez:\n\n```dart\nvar data = await Get.to(Payment());\n```\n\nsur l'autre écran, envoyez les données pour l'écran précédent:\n\n```dart\nGet.back(result: 'success');\n```\n\nEt utilisez-les:\n\nex:\n\n```dart\nif(data == 'success') madeAnything();\n```\n\nVous ne voulez pas apprendre notre syntaxe?\nChangez simplement le Navigateur (majuscule) en navigateur (minuscule), et vous aurez toutes les fonctions de la navigation standard, sans avoir à utiliser 'context'.\nExemple:\n\n```dart\n\n// Navigateur Flutter par défaut\nNavigator.of(context).push(\n  context,\n  MaterialPageRoute(\n    builder: (BuildContext context) {\n      return HomePage();\n    },\n  ),\n);\n\n// Utilisez la syntaxe Flutter sans avoir besoin de 'context'\nnavigator.push(\n  MaterialPageRoute(\n    builder: (_) {\n      return HomePage();\n    },\n  ),\n);\n\n// Syntaxe Get (c'est beaucoup mieux, mais vous avez le droit d'être en désaccord)\nGet.to(HomePage());\n\n\n```\n\n## Navigation Par Nom\n\n- Si vous préférez naviguer par namedRoutes, Get prend également en charge cela.\n\nPour aller à nextScreen\n\n```dart\nGet.toNamed(\"/NextScreen\");\n```\n\nPour naviguer et supprimer l'écran précédent du stack.\n\n```dart\nGet.offNamed(\"/NextScreen\");\n```\n\nPour naviguer et supprimer tous les écrans précédents du stack.\n\n```dart\nGet.offAllNamed(\"/NextScreen\");\n```\n\nPour définir des routes, utilisez GetMaterialApp:\n\n```dart\nvoid main() {\n  runApp(\n    GetMaterialApp(\n      initialRoute: '/',\n      getPages: [\n        GetPage(name: '/', page: () => MyHomePage()),\n        GetPage(name: '/second', page: () => Second()),\n        GetPage(\n          name: '/third',\n          page: () => Third(),\n          transition: Transition.zoom  \n        ),\n      ],\n    )\n  );\n}\n```\n\nPour gérer la navigation vers des routes non définies (erreur 404), vous pouvez définir une page 'unknownRoute' dans GetMaterialApp.\n\n```dart\nvoid main() {\n  runApp(\n    GetMaterialApp(\n      unknownRoute: GetPage(name: '/notfound', page: () => UnknownRoutePage()),\n      initialRoute: '/',\n      getPages: [\n        GetPage(name: '/', page: () => MyHomePage()),\n        GetPage(name: '/second', page: () => Second()),\n      ],\n    )\n  );\n}\n```\n\n### Envoyer des données aux routes nommées\n\nEnvoyez simplement ce que vous voulez comme arguments. Get accepte n'importe quoi ici, qu'il s'agisse d'une String, d'une Map, d'une List ou même d'une instance de classe.\n\n```dart\nGet.toNamed(\"/NextScreen\", arguments: 'Get is the best');\n```\n\ndans votre classe ou contrôleur:\n\n```dart\nprint(Get.arguments);\n//montre: Get is the best\n```\n\n### Liens URL dynamiques\n\nGet propose des URL dynamiques avancées, tout comme sur le Web. Les développeurs Web ont probablement déjà voulu cette fonctionnalité sur Flutter, et ont très probablement vu un package promettre cette fonctionnalité et fournir une syntaxe totalement différente de celle d'une URL sur le Web, mais Get résout également cela.\n\n```dart\nGet.offAllNamed(\"/NextScreen?device=phone&id=354&name=Enzo\");\n```\n\nsur votre classe controller/bloc/stateful/stateless:\n\n```dart\nprint(Get.parameters['id']);\n// donne: 354\nprint(Get.parameters['name']);\n// donne: Enzo\n```\n\nVous pouvez également recevoir facilement des paramètres nommés avec Get:\n\n```dart\nvoid main() {\n  runApp(\n    GetMaterialApp(\n      initialRoute: '/',\n      getPages: [\n      GetPage(\n        name: '/',\n        page: () => MyHomePage(),\n      ),\n      GetPage(\n        name: '/profile/',\n        page: () => MyProfile(),\n      ),\n       //Vous pouvez définir une page différente pour les routes avec arguments, et une autre sans arguments, mais pour cela vous devez utiliser la barre oblique '/' sur la route qui ne recevra pas d'arguments comme ci-dessus.\n       GetPage(\n        name: '/profile/:user',\n        page: () => UserProfile(),\n      ),\n      GetPage(\n        name: '/third',\n        page: () => Third(),\n        transition: Transition.cupertino  \n      ),\n     ],\n    )\n  );\n}\n```\n\nEnvoyer des données sur le nom de la route\n\n```dart\nGet.toNamed(\"/profile/34954\");\n```\n\nSur le deuxième écran, recevez les données par paramètre\n\n```dart\nprint(Get.parameters['user']);\n// donne: 34954\n```\n\nou envoyer plusieurs paramètres comme celui-ci\n\n```dart\nGet.toNamed(\"/profile/34954?flag=true\");\n```\n\nSur le deuxième écran, prenez les données par paramètres comme d'habitude\n\n```dart\nprint(Get.parameters['user']);\nprint(Get.parameters['flag']);\n// donne: 34954 true\n```\n\nEt maintenant, tout ce que vous avez à faire est d'utiliser Get.toNamed() pour parcourir vos routes nommées, sans aucun contexte (vous pouvez appeler vos routes directement à partir de votre classe BLoC ou Controller), et lorsque votre application est compilée sur le Web, vos routes apparaîtront dans l'url <3\n\n### Middleware\n\nSi vous souhaitez écouter les événements Get pour déclencher des actions, vous pouvez utiliser routingCallback pour le faire:\n\n```dart\nGetMaterialApp(\n  routingCallback: (routing) {\n    if(routing.current == '/second'){\n      openAds();\n    }\n  }\n)\n```\n\nSi vous n'utilisez pas GetMaterialApp, vous pouvez utiliser l'API manuelle pour attacher l'observateur Middleware.\n\n```dart\nvoid main() {\n  runApp(\n    MaterialApp(\n      onGenerateRoute: Router.generateRoute,\n      initialRoute: \"/\",\n      navigatorKey: Get.key,\n      navigatorObservers: [\n        GetObserver(MiddleWare.observer), // ICI !!!\n      ],\n    ),\n  );\n}\n```\n\nCréez une classe MiddleWare\n\n```dart\nclass MiddleWare {\n  static observer(Routing routing) {\n    /// Vous pouvez écouter en plus des routes, des snackbars, des dialogs et des bottomsheets sur chaque écran.\n    /// Si vous devez saisir l'un de ces 3 événements directement ici,\n    /// vous devez spécifier que l'événement est != Ce que vous essayez de faire.\n    if (routing.current == '/second' && !routing.isSnackbar) {\n      Get.snackbar(\"Hi\", \"You are on second route\");\n    } else if (routing.current =='/third'){\n      print('dernière route');\n    }\n  }\n}\n```\n\nMaintenant, utilisez Get sur votre code:\n\n```dart\nclass First extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        leading: IconButton(\n          icon: Icon(Icons.add),\n          onPressed: () {\n            Get.snackbar(\"hi\", \"i am a modern snackbar\");\n          },\n        ),\n        title: Text('First Route'),\n      ),\n      body: Center(\n        child: ElevatedButton(\n          child: Text('Open route'),\n          onPressed: () {\n            Get.toNamed(\"/second\");\n          },\n        ),\n      ),\n    );\n  }\n}\n\nclass Second extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        leading: IconButton(\n          icon: Icon(Icons.add),\n          onPressed: () {\n            Get.snackbar(\"hi\", \"i am a modern snackbar\");\n          },\n        ),\n        title: Text('second Route'),\n      ),\n      body: Center(\n        child: ElevatedButton(\n          child: Text('Open route'),\n          onPressed: () {\n            Get.toNamed(\"/third\");\n          },\n        ),\n      ),\n    );\n  }\n}\n\nclass Third extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: Text(\"Third Route\"),\n      ),\n      body: Center(\n        child: ElevatedButton(\n          onPressed: () {\n            Get.back();\n          },\n          child: Text('Go back!'),\n        ),\n      ),\n    );\n  }\n}\n```\n\n## Navigation sans context\n\n### SnackBars\n\nPour avoir un simple SnackBar avec Flutter, vous devez obtenir le 'context' de Scaffold, ou vous devez utiliser un GlobalKey attaché à votre Scaffold\n\n```dart\nfinal snackBar = SnackBar(\n  content: Text('Hi!'),\n  action: SnackBarAction(\n    label: 'I am a old and ugly snackbar :(',\n    onPressed: (){}\n  ),\n);\n// Trouvez le scaffold dans l'arborescence des widgets et utilisez-le pour afficher un SnackBar.\nScaffold.of(context).showSnackBar(snackBar);\n```\n\nAvec Get:\n\n```dart\nGet.snackbar('Hi', 'i am a modern snackbar');\n```\n\nAvec Get, tout ce que vous avez à faire est d'appeler votre Get.snackbar à partir de n'importe où dans votre code ou de le personnaliser comme vous le souhaitez!\n\n```dart\nGet.snackbar(\n  \"Hey i'm a Get SnackBar!\", // title\n  \"C'est incroyable! J'utilise SnackBar sans context, sans code standard, sans Scaffold, c'est quelque chose de vraiment incroyable!\", // message\n  icon: Icon(Icons.alarm),\n  shouldIconPulse: true,\n  onTap:(){},\n  barBlur: 20,\n  isDismissible: true,\n  duration: Duration(seconds: 3),\n);\n\n\n  ////////// TOUTES LES FONCTIONNALITÉS //////////\n  //     Color colorText,\n  //     Duration duration,\n  //     SnackPosition snackPosition,\n  //     Widget titleText,\n  //     Widget messageText,\n  //     bool instantInit,\n  //     Widget icon,\n  //     bool shouldIconPulse,\n  //     double maxWidth,\n  //     EdgeInsets margin,\n  //     EdgeInsets padding,\n  //     double borderRadius,\n  //     Color borderColor,\n  //     double borderWidth,\n  //     Color backgroundColor,\n  //     Color leftBarIndicatorColor,\n  //     List<BoxShadow> boxShadows,\n  //     Gradient backgroundGradient,\n  //     TextButton mainButton,\n  //     OnTap onTap,\n  //     bool isDismissible,\n  //     bool showProgressIndicator,\n  //     AnimationController progressIndicatorController,\n  //     Color progressIndicatorBackgroundColor,\n  //     Animation<Color> progressIndicatorValueColor,\n  //     SnackStyle snackStyle,\n  //     Curve forwardAnimationCurve,\n  //     Curve reverseAnimationCurve,\n  //     Duration animationDuration,\n  //     double barBlur,\n  //     double overlayBlur,\n  //     Color overlayColor,\n  //     Form userInputForm\n  ///////////////////////////////////\n```\n\nSi vous préférez le snack-bar traditionnel, ou souhaitez le personnaliser à partir de zéro, y compris en ajoutant une seule ligne (Get.snackbar utilise un titre et un message obligatoires), vous pouvez utiliser\n`Get.rawSnackbar ();` qui fournit l'API brute sur laquelle Get.snackbar a été construit.\n\n### Dialogs\n\nPour ouvrir un 'dialog':\n\n```dart\nGet.dialog(VotreDialogWidget());\n```\n\nPour ouvrir le 'dialog' par défaut:\n\n```dart\nGet.defaultDialog(\n  onConfirm: () => print(\"Ok\"),\n  middleText: \"Dialog made in 3 lines of code\"\n);\n```\n\nVous pouvez également utiliser Get.generalDialog au lieu de showGeneralDialog.\n\nPour tous les autres widgets de la boîte de dialogue Flutter, y compris cupertinos, vous pouvez utiliser Get.overlayContext au lieu du context et l'ouvrir n'importe où dans votre code.\nPour les widgets qui n'utilisent pas Overlay, vous pouvez utiliser Get.context.\nCes deux contextes fonctionneront dans 99% des cas pour remplacer le context de votre interface utilisateur, sauf dans les cas où inheritedWidget est utilisé sans context de navigation.\n\n### BottomSheets\n\nGet.bottomSheet est comme showModalBottomSheet, mais n'a pas besoin de 'context'.\n\n```dart\nGet.bottomSheet(\n  Container(\n    child: Wrap(\n      children: <Widget>[\n        ListTile(\n          leading: Icon(Icons.music_note),\n          title: Text('Music'),\n          onTap: () {}\n        ),\n        ListTile(\n          leading: Icon(Icons.videocam),\n          title: Text('Video'),\n          onTap: () {},\n        ),\n      ],\n    ),\n  )\n);\n```\n\n## Nested Navigation\n\nGetx a rendu la navigation imbriquée de Flutter encore plus facile.\nVous n'avez pas besoin de 'context' et vous trouverez votre stack de navigation par ID.\n\n- NOTE: La création de stacks de navigation parallèles peut être dangereuse. L'idéal est de ne pas utiliser NestedNavigators, ou de l'utiliser avec parcimonie. Si votre projet l'exige, allez-y, mais gardez à l'esprit que conserver plusieurs stacks de navigation en mémoire n'est peut-être pas une bonne idée pour la consommation de RAM.\n\nVoyez comme c'est simple:\n\n```dart\nNavigator(\n  key: Get.nestedKey(1), // créez une clé par index\n  initialRoute: '/',\n  onGenerateRoute: (settings) {\n    if (settings.name == '/') {\n      return GetPageRoute(\n        page: () => Scaffold(\n          appBar: AppBar(\n            title: Text(\"Main\"),\n          ),\n          body: Center(\n            child: TextButton(\n              color: Colors.blue,\n              onPressed: () {\n                Get.toNamed('/second', id:1); // naviguer votre itinéraire imbriqué par index\n              },\n              child: Text(\"Go to second\"),\n            ),\n          ),\n        ),\n      );\n    } else if (settings.name == '/second') {\n      return GetPageRoute(\n        page: () => Center(\n          child: Scaffold(\n            appBar: AppBar(\n              title: Text(\"Main\"),\n            ),\n            body: Center(\n              child:  Text(\"second\")\n            ),\n          ),\n        ),\n      );\n    }\n  }\n),\n```\n"
  },
  {
    "path": "documentation/fr_FR/state_management.md",
    "content": "- [Gestion d'État](#gestion-d-etat)\n  - [Gestionnaire d'état réactif](#gestionnaire-d-etat-reactif)\n    - [Avantages](#avantages)\n    - [Performance maximale:](#performance-maximale)\n    - [Déclaration d'une variable réactive](#declaration-d-une-variable-reactive)\n        - [Avoir un état réactif, c'est facile.](#avoir-un-etat-reactif-c-est-facile)\n    - [Utilisation des valeurs dans la Vue](#utilisation-des-valeurs-dans-la-vue)\n    - [Conditions pour reconstruire](#conditions-pour-reconstruire)\n    - [Quand utiliser .obs](#quand-utiliser-obs)\n    - [Remarque sur List](#remarque-sur-list)\n    - [Pourquoi je dois utiliser .value](#pourquoi-je-dois-utiliser-value)\n    - [Obx()](#obx)\n    - [Workers](#workers)\n  - [Gestionnaire d'état simple](#gestionnaire-d-etat-simple)\n    - [Atouts](#atouts)\n    - [Utilisation](#utilisation)\n    - [Comment il gère les contrôleurs](#comment-il-gre-les-contrleurs)\n    - [Vous n'aurez plus besoin de StatefulWidgets](#vous-naurez-plus-besoin-de-statefulwidgets)\n    - [Pourquoi ça existe](#pourquoi-ca-existe)\n    - [Autres façons de l'utiliser](#autres-formes-d-utilisation)\n    - [IDs Uniques](#ids-uniques)\n  - [Mélanger les deux gestionnaires d'état](#mixing-the-two-state-managers)\n  - [GetBuilder vs GetX vs Obx vs MixinBuilder](#getbuilder-vs-getx-vs-obx-vs-mixinbuilder)\n\n# Gestion d Etat\n\nGetX n'utilise pas Streams ou ChangeNotifier comme les autres gestionnaires d'état. Pourquoi? En plus de créer des applications pour Android, iOS, Web, Linux, MacOS et Linux, GetX vous permet de créer 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, des solutions à 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 d'état.\n\n- _Complexité_: Certains gestionnaires d'État sont complexes et ont beaucoup de code standard. Avec GetX, vous n'avez pas à définir une classe pour chaque événement, le code est très propre et clair, et vous faites beaucoup plus en écrivant moins. Beaucoup de gens ont abandonné Flutter à cause de ce sujet, et ils ont enfin une solution stupidement simple pour gérer les états.\n- _Aucun générateur de code_: Vous passez la moitié de votre temps de développement à écrire la logique de votre application. Certains gestionnaires d'état s'appuient sur des générateurs de code pour avoir un code lisible minimal. Changer une variable et avoir à exécuter build_runner peut être improductif, et souvent le temps d'attente après un redémarrage sera long, et vous devrez boire beaucoup de café.\n                              Avec GetX, tout est réactif, et rien ne dépend des générateurs de code, augmentant votre productivité dans tous les aspects de votre développement.\n- _Cela ne dépend pas de 'context'_: Vous avez probablement déjà eu besoin d'envoyer le contexte de votre vue à un contrôleur, ce qui rend le couplage de la vue avec votre logique métier élevé. Vous avez probablement dû utiliser une dépendance dans un endroit qui n'a pas de contexte, et avez dû passer le contexte à travers différentes classes et fonctions. Cela n'existe tout simplement pas avec GetX. Vous avez accès à vos contrôleurs depuis vos contrôleurs sans aucun contexte. Vous n'avez pas besoin d'envoyer le contexte par paramètre pour rien.\n- _Contrôle granulaire_: la plupart des gestionnaires d'état sont basés sur ChangeNotifier. ChangeNotifier notifiera tous les widgets qui en dépendent lors de l'appel de notifyListeners. Si vous avez 40 widgets sur un écran, qui ont une variable de votre classe ChangeNotifier, lorsque vous en mettez un à jour, tous seront reconstruits.\n                          Avec GetX, même les widgets imbriqués sont respectés. Si Obx gère votre ListView et un autre gère une case à cocher dans ListView, lors de la modification de la valeur CheckBox, il ne sera mis à jour que, lors de la modification de la valeur List, seul le ListView sera mis à jour.\n- _Il ne reconstruit que si sa variable change VRAIMENT_: GetX a un contrôle de flux, cela 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 Text et ne fera pas de reconstructions inutiles.\n                                                          La plupart (sinon tous) les gestionnaires d'état actuels se reconstruiront à l'écran.\n\n## Gestionnaire d etat reactif\n\nLa programmation réactive peut aliéner de nombreuses personnes car on dit qu'elle est compliquée. GetX transforme la programmation réactive en quelque chose d'assez simple:\n\n- Vous n'aurez pas besoin de créer des StreamControllers.\n- Vous n'aurez pas besoin de créer un StreamBuilder pour chaque variable\n- Vous n'aurez pas besoin de créer une classe pour chaque état.\n- Vous n'aurez pas besoin de créer un 'get' pour une valeur initiale.\n\n\nLa programmation réactive avec Get est aussi simple que d'utiliser setState.\n\nImaginons que vous ayez une variable de 'name' et que vous souhaitiez que chaque fois que vous la modifiez, tous les widgets qui l'utilisent soient automatiquement modifiés.\n\nVoici votre variable:\n\n```dart\nvar name = 'Jonatas Borges';\n```\n\nPour la rendre observable, il vous suffit d'ajouter \".obs\" à la fin:\n\n```dart\nvar name = 'Jonatas Borges'.obs;\n```\n\nC'est *tout*. Si simple que ca.\n\nA partir de maintenant, nous pourrions désigner ces variables réactives - \". Obs\" (ervables) comme _Rx_.\n\nQu'est ce qui s'est passé derrière les rideaux? 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_ changements, ils devront également changer.\n\nC'est la **magie de GetX**, grâce aux performances de Dart.\n\nMais, comme nous le savons, un `Widget` ne peut être changé que s'il est à l'intérieur d'une fonction, car les classes statiques n'ont pas le pouvoir de\" changer automatiquement \".\n\nVous devrez créer un `StreamBuilder`, vous abonner à cette variable pour écouter les changements et créer une\" cascade \"de` StreamBuilder` imbriqués si vous voulez changer plusieurs variables dans la même portée, non?\n\nNon, vous n'avez pas besoin d'un `StreamBuilder`, mais vous avez raison pour les classes statiques.\n\nEh bien, dans la vue, nous avons généralement beaucoup de code standard lorsque nous voulons changer un widget spécifique, c'est la manière Flutter.\nAvec **GetX**, vous pouvez également oublier ce code passe-partout.\n\n`StreamBuilder( … )`? `initialValue: …`? `builder: …`? Non, il vous suffit de placer cette variable dans un widget `Obx()`.\n\n```dart\nObx (() => Text (controller.name));\n```\n\n_Que devez-vous mémoriser?_  Seulement `Obx(() =>`. \n\nVous passez simplement ce Widget via une fonction dans un `Obx()` (l' \"Observateur\" du _Rx_).\n\n`Obx` est assez intelligent et ne changera que si la valeur de` controller.name` change.\n\nSi `name` est` \"John\" `, et que vous le changez en` \"John\" `(` name.value = \"John\" `), comme c'est la même` valeur` qu'avant, rien ne changera à l'écran, et `Obx`, pour économiser les ressources, ignorera simplement la nouvelle valeur et ne reconstruira pas le widget. **N'est-ce pas incroyable?**\n\n> Alors, que faire si j'ai 5 variables _Rx_ (observables) dans un `Obx`?\n\nIl sera simplement mis à jour lorsque **l'un d'entre eux** change.\n\n> Et si j'ai 30 variables dans une classe, lorsque j'en mets une à jour, est-ce que cela va mettre à jour **toutes** les variables qui sont dans cette classe?\n\nNon, juste le **Widget spécifique** qui utilise cette variable _Rx_.\n\nAinsi, **GetX** ne met à jour l'écran que lorsque la variable _Rx_ change sa valeur.\n\n```\nfinal isOpen = false.obs;\n\n// Rien de ne change... valeur identique.\nvoid onButtonTap() => isOpen.value=false;\n```\n### Avantages\n\n**GetX()** vous aide lorsque vous avez besoin d'un contrôle **granulaire** sur ce qui est mis à jour.\n\n\nSi vous n'avez pas besoin d'ID uniques, car toutes vos variables seront modifiées lorsque vous effectuez une action, utilisez `GetBuilder`,\nparce que c'est un Simple State Updater (en blocs, comme `setState()`), fait en seulement quelques lignes de code.\nIl a été rendu simple, pour avoir le moins d'impact sur le processeur, et juste pour remplir un seul objectif (une reconstruction de _l'état_) et dépenser le minimum de ressources possible.\n\nSi vous avez besoin d'un State Manager **puissant** , vous ne pouvez pas vous tromper avec **GetX**.\n\nCela ne fonctionne pas avec les variables, mais __flows__, tout ce qu'il contient sont des `Streams` en réalité.\nVous pouvez utiliser _rxDart_ en conjonction avec lui, car tout est `Streams`.\nVous pouvez écouter les changements de chaque \"variable _Rx_\",\nparce que tout ce qui se trouve dedans est un `Streams`.\n\n\nC'est littéralement une approche _BLoC_, plus facile que _MobX_, et sans générateurs de code ni décorations.\nVous pouvez transformer **n'importe quoi** en un _\"Observable\"_ avec juste un `.obs`.\n\n###  Performance maximale:\n\nEn plus d'avoir un algorithme intelligent pour des reconstructions minimales, **GetX** utilise des comparateurs\npour s'assurer que l'État a changé. \n\nSi vous rencontrez des erreurs dans votre application et envoyez un changement d'état en double,\n**GetX** garantira qu'il ne plantera pas.\n\nAvec **GetX**, l'état ne change que si la `valeur` change.\nC'est la principale différence entre **GetX** et l'utilisation de _`computed` de MobX_.\nLors de la jonction de deux __observables__, si l'une change; le listener de cet _observable_ changera également.\n\nAvec **GetX**, si vous joignez deux variables, `GetX()` (similaire à `Observer()`), ne se reconstruira que si cela implique un réel changement d'état.\n\n### Declaration d une variable reactive\n\nVous avez 3 façons de transformer une variable en \"observable\".\n\n1 - La première est d'utiliser **`Rx{Type}`**.\n\n```dart\n// la valeur initiale est recommandée, mais pas obligatoire\nfinal name = RxString('');\nfinal isLogged = RxBool(false);\nfinal count = RxInt(0);\nfinal balance = RxDouble(0.0);\nfinal items = RxList<String>([]);\nfinal myMap = RxMap<String, int>({});\n```\n\n2 - La seconde consiste à utiliser **`Rx`** et à utiliser les types `Rx<Type>` Génériques Darts \n\n```dart\nfinal name = Rx<String>('');\nfinal isLogged = Rx<Bool>(false);\nfinal count = Rx<Int>(0);\nfinal balance = Rx<Double>(0.0);\nfinal number = Rx<Num>(0);\nfinal items = Rx<List<String>>([]);\nfinal myMap = Rx<Map<String, int>>({});\n\n// Classes personnalisées - il peut s'agir de n'importe quelle classe, littéralement\nfinal user = Rx<User>();\n```\n\n3 - La troisième approche, plus pratique, plus facile et préférée, ajoutez simplement **`.obs`** comme propriété de votre` valeur`:\n\n```dart\nfinal name = ''.obs;\nfinal isLogged = false.obs;\nfinal count = 0.obs;\nfinal balance = 0.0.obs;\nfinal number = 0.obs;\nfinal items = <String>[].obs;\nfinal myMap = <String, int>{}.obs;\n\n// Classes personnalisées - il peut s'agir de n'importe quelle classe, littéralement\nfinal user = User().obs;\n```\n\n##### Avoir un etat reactif, c est facile.\n\nComme nous le savons, _Dart_ se dirige maintenant vers _null safety_.\nPour être prêt, à partir de maintenant, vous devez toujours commencer vos variables _Rx_ avec une **valeur initiale**.\n\n> Transformer une variable en _observable_ + _valeurInitiale_ avec **GetX** est l'approche la plus simple et la plus pratique.\n\nVous allez littéralement ajouter un \"\".obs\"\" à la fin de votre variable, et **c'est tout**, vous l'avez rendue observable,\net sa `.value`, eh bien, sera la _valeurInitiale_.\n\n### Utilisation des valeurs dans la Vue\n\n```dart\n// dans le controlleur\nfinal count1 = 0.obs;\nfinal count2 = 0.obs;\nint get sum => count1.value + count2.value;\n```\n\n```dart\n// dans la vue\nGetX<Controller>(\n  builder: (controller) {\n    print(\"count 1 reconstruction\");\n    return Text('${controller.count1.value}');\n  },\n),\nGetX<Controller>(\n  builder: (controller) {\n    print(\"count 2 reconstruction\");\n    return Text('${controller.count2.value}');\n  },\n),\nGetX<Controller>(\n  builder: (controller) {\n    print(\"count 3 reconstruction\");\n    return Text('${controller.sum}');\n  },\n),\n```\n\nSi nous incrémentons `count1.value++`, cela affichera:\n- `count 1 reconstruction` \n- `count 3 reconstruction`\n\nparce que `count1` a une valeur de `1`, et `1 + 0 = 1`, changeant la valeur du getter `sum`.\n\nSi nous incrémentons `count2.value++`, cela affichera:\n- `count 2 reconstruction` \n- `count 3 reconstruction`\n\nparce que `count2.value` a changé et que le résultat de `sum` est maintenant `2`.\n\n- NOTE: Par défaut, le tout premier événement reconstruira le widget, même s'il s'agit de la même `valeur`.\n         Ce comportement existe en raison de variables booléennes.\n\nImaginez que vous fassiez ceci:\n\n```dart\nvar isLogged = false.obs;\n```\n\nEt puis, vous vérifiez si un utilisateur est \"connecté\" pour déclencher un événement dans `ever`.\n\n```dart\n@override\nonInit(){\n  ever(isLogged, fireRoute);\n  isLogged.value = await Preferences.hasToken();\n}\n\nfireRoute(logged) {\n  if (logged) {\n   Get.off(Home());\n  } else {\n   Get.off(Login());\n  }\n}\n```\n\nsi `hasToken` était `false`, il n'y aurait pas de changement à `isLogged`, donc` ever() `ne serait jamais appelé.\nPour éviter ce type de comportement, la première modification d'un _observable_ déclenchera toujours un événement,\nmême s'il contient la même `.value`.\n\nVous pouvez supprimer ce comportement si vous le souhaitez, en utilisant:\n`isLogged.firstRebuild = false;`\n\n### Conditions pour reconstruire\n\nEn outre, Get fournit un contrôle d'état raffiné. Vous pouvez conditionner un événement (comme l'ajout d'un objet à une liste), à ​​une certaine condition.\n\n```dart\n// Premier paramètre: condition, doit retourner vrai ou faux.\n// Deuxième paramètre: la nouvelle valeur à appliquer si la condition est vraie.\nlist.addIf(item < limit, item);\n```\n\nSans décorations, sans générateur de code, sans complications :smile:\n\nConnaissez-vous l'application 'counter' de Flutter? Votre classe Controller pourrait ressembler à ceci:\n\n```dart\nclass CountController extends GetxController {\n  final count = 0.obs;\n}\n```\n\nAvec un simple:\n\n```dart\ncontroller.count.value++\n```\n\nVous pouvez mettre à jour la variable de compteur dans votre interface utilisateur, quel que soit l'endroit où elle est stockée.\n\n### Quand utiliser .obs\n\nVous pouvez tout transformer sur obs. Voici deux façons de procéder:\n\n* Vous pouvez convertir vos valeurs de classe en obs\n```dart\nclass RxUser {\n  final name = \"Camila\".obs;\n  final age = 18.obs;\n}\n```\n\n* ou vous pouvez convertir la classe entière en un observable:\n```dart\nclass User {\n  User({String name, int age});\n  var name;\n  var age;\n}\n\n// en instanciant:\nfinal user = User(name: \"Camila\", age: 18).obs;\n```\n\n### Remarque sur List\n\nLes listes sont complètement observables, tout comme les objets qu'elles contiennent. De cette façon, si vous ajoutez une valeur à une liste, cela reconstruira automatiquement les widgets qui l'utilisent.\n\nVous n'avez pas non plus besoin d'utiliser \".value\" avec des listes, l'incroyable api de Dart nous a permis de supprimer cela.\nMalheureusement, les types primitifs comme String et int ne peuvent pas être étendus, ce qui rend l'utilisation de .value obligatoire, mais ce ne sera pas un problème si vous travaillez avec des getters et des setters pour ceux-ci.\n\n```dart\n// Dans le controlleur\nfinal String title = 'User Info:'.obs;\nfinal list = List<User>().obs;\n\n// Dans la vue\nText(controller.title.value), // La String doit avoir .value devant elle\nListView.builder (\n  itemCount: controller.list.length // pas besoin pour List\n)\n```\n\nLorsque vous rendez vos propres classes observables, il existe une manière différente de les mettre à jour:\n\n```dart\n// sur le fichier modèle\n// nous allons rendre la classe entière observable au lieu de chaque attribut\nclass User() {\n  User({this.name = '', this.age = 0});\n  String name;\n  int age;\n}\n\n\n// Dans le controlleur\nfinal user = User().obs;\n// lorsque vous devez mettre à jour la variable utilisateur:\nuser.update( (user) { // ce paramètre est la classe même que vous souhaitez mettre à jour\nuser.name = 'Jonny';\nuser.age = 18;\n});\n// une autre manière de mettre à jour la variable user:\nuser(User(name: 'João', age: 35));\n\n// Dans la vue:\nObx(()=> Text(\"Name ${user.value.name}: Age: ${user.value.age}\"))\n// vous pouvez également accéder aux valeurs du modèle sans le .value:\nuser().name; //notez que c'est la variable utilisateur, pas la classe (la variable a un u minuscule)\n```\n\nVous n'êtes pas obligé de travailler avec des setters si vous ne le souhaitez pas. vous pouvez utiliser les API `assign` et `assignAll`.\nL'API `assign` effacera votre liste et ajoutera un seul objet que vous souhaitez.\nL'API `assignAll` effacera la liste existante et ajoutera tous les objets itérables que vous y injecterez.\n\n### Pourquoi je dois utiliser .value\n\nNous pourrions supprimer l'obligation d'utiliser 'value' pour `String` et` int` avec une simple décoration et un générateur de code, mais le but de cette bibliothèque est précisément d'éviter les dépendances externes. Nous souhaitons proposer un environnement prêt à la programmation, impliquant l'essentiel (gestion des routes, des dépendances et des états), de manière simple, légère et performante, sans avoir besoin d'un package externe.\n\nVous pouvez littéralement ajouter 3 lettres à votre pubspec (get) et un signe deux-points et commencer la programmation. Toutes les solutions incluses par défaut, de la gestion des routes à la gestion des états, visent la facilité, la productivité et la performance.\n\nLe poids total de cette bibliothèque est inférieur à celui d'un seul gestionnaire d'état, bien qu'il s'agisse d'une solution complète, et c'est ce que vous devez comprendre.\n\nSi vous êtes dérangé par `.value`, 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 seule dépendance dans pubspec et commencer à programmer sans se soucier de l'incompatibilité de la version d'un package 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, que ce soit littéralement \"juste de la programmation\", get est tout simplement parfait.\n\nSi vous n'avez aucun problème avec le générateur de code MobX, ou si vous n'avez aucun problème avec le code standard BLoC, vous pouvez simplement utiliser Get pour les routes et oublier qu'il a un gestionnaire d'état. Get 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 Flutter Clean sur une machine raisonnablement bonne, si votre projet il a 5, 10, 15 contrôleurs, n'importe quel gestionnaire d'état vous suffira bien. Si vous avez un projet d'une taille absurde et que le générateur de code est un problème pour vous, cette solution vous a été attribuée.\n\nÉvidemment, si quelqu'un veut contribuer au projet et créer un générateur de code, ou quelque chose de similaire, je vais créer un lien dans ce readme comme alternative, mon besoin n'est pas le besoin de tous les développeurs, mais pour l'instant je dis q'il y a de bonnes solutions qui font déjà cela, comme MobX.\n\n### Obx()\n\nLes types dans Get à l'aide de Bindings ne sont pas nécessaires. Vous pouvez utiliser le widget Obx, au lieu de GetX, qui ne reçoit que la fonction anonyme qui crée un widget.\nÉvidemment, si vous n'utilisez pas de type, vous devrez avoir une instance de votre contrôleur pour utiliser les variables, ou utiliser `Get.find<Controller>()` .value ou Controller.to.value pour récupérer la valeur .\n\n### Workers\n\nLes 'workers' vous assisteront, déclenchant des callbacks spécifiques lorsqu'un événement se produit.\n\n```dart\n/// Appelée à chaque fois que `count1` change.\never(count1, (_) => print(\"$_ a été modifié\"));\n\n/// Appelée uniquement la première fois que la variable est modifiée\nonce(count1, (_) => print(\"$_ a été changé une fois\"));\n\n/// Anti DDos - Appelée chaque fois que l'utilisateur arrête de taper pendant 1 seconde, par exemple.\ndebounce(count1, (_) => print(\"debouce$_\"), time: Duration(seconds: 1));\n\n/// Ignore toutes les modifications pendant 1 seconde.\ninterval(count1, (_) => print(\"interval $_\"), time: Duration(seconds: 1));\n```\nTous les workers (sauf `debounce`) ont un paramètre nommé `condition`, qui peut etre un `bool` ou un callback qui retourne un `bool`.\nCette `condition` definit quand la fonction `callback` est executée.\n\nTous les workers renvoyent un objet `Worker`, qui peut être utilisé pour annuler ( via `dispose()` ) le `worker`.\n \n- **`ever`**\n est appelée chaque fois que la variable _Rx_ émet une nouvelle valeur.\n\n- **`everAll`**\n Un peu comme `ever`, mais il prend une` List` de valeurs _Rx_. Appelée chaque fois que sa variable est changée. C'est tout.\n\n- **`once`**\n'once' est appelée uniquement la première fois que la variable a été modifiée.\n\n- **`debounce`**\n'debounce' est très utile dans les fonctions de recherche, où vous souhaitez que l'API ne soit appelée que lorsque l'utilisateur a fini de taper. Si l'utilisateur tape \"Jonny\", vous aurez 5 recherches dans les API, par la lettre J, o, n, n et y. Avec Get, cela ne se produit pas, car vous aurez un Worker \"anti-rebond\" qui ne sera déclenché qu'à la fin de la saisie.\n\n- **`interval`**\n'interval' est différent de 'debounce'. Avec `debounce` si l'utilisateur fait 1000 changements à une variable en 1 seconde, il n'enverra que le dernier après le temporisateur stipulé (la valeur par défaut est 800 millisecondes). 'Interval' ignorera à la place toutes les actions de l'utilisateur pour la période stipulée. Si vous envoyez des événements pendant 1 minute, 1000 par seconde, debounce ne vous enverra que le dernier, lorsque l'utilisateur arrête de mitrailler les événements. interval délivrera des événements toutes les secondes, et s'il est réglé sur 3 secondes, il fournira 20 événements cette minute. Ceci est recommandé pour éviter les abus, dans des fonctions où l'utilisateur peut rapidement cliquer sur quelque chose et obtenir un avantage (imaginez que l'utilisateur puisse gagner des pièces en cliquant sur quelque chose, s'il cliquait 300 fois dans la même minute, il aurait 300 pièces, en utilisant l'intervalle, vous pouvez définir une période de 3 secondes, et même en cliquant 300 ou mille fois, le maximum qu'il obtiendrait en 1 minute serait de 20 pièces, en cliquant 300 ou 1 million de fois). Le 'debounce' convient aux anti-DDos, pour des fonctions comme la recherche où chaque changement de onChange entraînerait une requête à votre api. Debounce attendra que l'utilisateur arrête de taper le nom, pour faire la demande. S'il était utilisé dans le scénario de pièces mentionné ci-dessus, l'utilisateur ne gagnerait qu'une pièce, car il n'est exécuté que lorsque l'utilisateur \"fait une pause\" pendant le temps établi.\n\n- NOTE: Les 'workers' doivent toujours être utilisés lors du démarrage d'un contrôleur ou d'une classe, il doit donc toujours être dans onInit (recommandé), le constructeur de classe ou l'initState d'un StatefulWidget (cette pratique n'est pas recommandée dans la plupart des cas, mais cela ne devrait poser aucun problème).\n\n## Gestionnaire d etat simple\n\nGet a un gestionnaire d'état extrêmement léger et facile, qui n'utilise pas ChangeNotifier, répondra aux besoins en particulier des nouveaux utilisateurs de Flutter et ne posera pas de problèmes pour les applications volumineuses.\n\nGetBuilder vise précisément le contrôle de plusieurs états. Imaginez que vous avez ajouté 30 produits à un panier, que 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 avec un nombre plus petit. Ce type d'approche fait de GetBuilder un tueur, car il regroupe les états et les modifie tous à la fois sans aucune \"logique de calcul\" pour cela. GetBuilder a été créé avec ce type de situation à l'esprit, car pour un changement d'état éphémère, vous pouvez utiliser setState et vous n'aurez pas besoin d'un gestionnaire d'état pour cela.\n\nDe cette façon, si vous voulez un contrôleur individuel, vous pouvez lui attribuer des ID ou utiliser GetX. Cela dépend de vous, en vous rappelant que plus vous avez de widgets \"individuels\", plus les performances de GetX se démarqueront, tandis que les performances de GetBuilder devraient être supérieures, en cas de changement d'état multiple.\n\n### Atouts\n\n1. Met à jour uniquement les widgets requis.\n\n2. N'utilise pas changeNotifier, c'est le gestionnaire d'état qui utilise le moins de mémoire (proche de 0 Mo).\n\n3. Oubliez StatefulWidget! Avec Get, vous n'en aurez jamais besoin. Avec les autres gestionnaires d'états, vous devrez probablement utiliser un StatefulWidget pour obtenir l'instance de votre fournisseur, BLoC, MobX Controller, etc. Mais vous êtes-vous déjà arrêté pour penser que votre appBar, votre 'scaffold', et la plupart des les widgets de votre classe sont sans état (stateless)? Alors pourquoi sauvegarder l'état d'une classe entière, si vous pouvez sauvegarder l'état du widget qui est `avec état` (statefull)? Get résout cela aussi. Créez une classe sans état, rendez tout `sans état`. Si vous devez mettre à jour un seul composant, enveloppez-le avec GetBuilder et son état sera conservé.\n\n4. Organisez votre projet pour de vrai! Les contrôleurs ne doivent pas être dans votre interface utilisateur, placer votre TextEditController ou tout contrôleur que vous utilisez dans votre classe Controller.\n\n5. Avez-vous besoin de déclencher un événement pour mettre à jour un widget dès son rendu? GetBuilder a la propriété \"initState\", tout comme StatefulWidget, et vous pouvez appeler des événements depuis votre contrôleur, directement depuis celui-ci, aucun événement n'étant placé dans votre initState.\n\n6. Avez-vous besoin de déclencher une action comme la fermeture de stream, de timers, etc.? GetBuilder a également la propriété dispose(), où vous pouvez appeler des événements dès que ce widget est détruit.\n\n7. N'utilisez les streams que si nécessaire. Vous pouvez utiliser vos StreamControllers à l'intérieur de votre contrôleur normalement, et utiliser StreamBuilder également normalement, mais rappelez-vous qu'un stream consomme raisonnablement de la mémoire, la programmation réactive est belle, mais vous ne devriez pas en abuser. 30 streams ouverts simultanément peuvent être pires que changeNotifier (et changeNotifier est très mauvais).\n\n8. Mettez à jour les widgets sans dépenser de RAM pour cela. Get stocke uniquement l'ID de créateur GetBuilder et met à jour ce GetBuilder si nécessaire. La consommation de mémoire du stockage get ID en 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 économise BEAUCOUP de RAM pour les applications volumineuses. Fondamentalement, votre application sera entièrement sans état (stateless), et les quelques widgets qui seront stateful (dans GetBuilder) auront un seul état, et par conséquent, la mise à jour d'un seul les mettra tous à jour. L'état  est unique.\n\n9. Get est omniscient et, dans la plupart des cas, il sait exactement quand sortir de mémoire un contrôleur. Vous ne devez pas vous soucier du moment de vous débarrasser d'un contrôleur, Get connaît le meilleur moment pour le faire.\n\n### Utilisation\n\n```dart\n// Créez la classe controller qui 'extends' GetxController\nclass Controller extends GetxController {\n  int counter = 0;\n  void increment() {\n    counter++;\n    update(); // utilisez update() pour mettre à jour la variable de compteur sur l'interface utilisateur lorsque incrément() est appelé\n  }\n}\n// Sur votre classe Stateless / Stateful, utilisez GetBuilder pour mettre à jour le texte lorsque incrément() est appelé\nGetBuilder<Controller>(\n  init: Controller(), // INITIER CA UNIQUEMENT LA PREMIÈRE FOIS\n  builder: (_) => Text(\n    '${_.counter}',\n  ),\n)\n//Initialisez votre contrôleur uniquement la première fois. La deuxième fois que vous utilisez ReBuilder pour le même contrôleur, ne recommencez pas. Votre contrôleur sera automatiquement supprimé de la mémoire dès que le widget qui l'a marqué comme `init` sera déployé. Vous n'avez pas à vous en soucier, Get le fera automatiquement, assurez-vous simplement de ne pas démarrer deux fois le même contrôleur.\n```\n\n**Fait!**\n\n- Vous avez déjà appris à gérer les états avec Get.\n\n- Note: Vous pouvez souhaiter une organisation plus grande et ne pas utiliser la propriété init. Pour cela, vous pouvez créer une classe et étendre la classe Bindings, et y mentionner les contrôleurs qui seront créés dans cette route. Les contrôleurs ne seront pas créés à ce moment-là, au contraire, il ne s'agit que d'une déclaration, de sorte que la première fois que vous utilisez un contrôleur, Get saura où chercher. Get restera lazyLoad et continuera à supprimer les contrôleurs lorsqu'ils ne seront plus nécessaires. Voir l'exemple pub.dev pour voir comment cela fonctionne.\n\nSi vous parcourez de nombreuses routes et avez besoin de données qui se trouvaient dans votre contrôleur précédemment utilisé, il vous suffit de réutiliser GetBuilder (sans init):\n\n```dart\nclass OtherClass extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      body: Center(\n        child: GetBuilder<Controller>(\n          builder: (s) => Text('${s.counter}'),\n        ),\n      ),\n    );\n  }\n\n```\n\nSi vous devez utiliser votre contrôleur dans de nombreux autres endroits, et en dehors de GetBuilder, créez simplement un get dans votre contrôleur et ayez-le facilement. (ou utilisez `Get.find<Controller>()`)\n\n```dart\nclass Controller extends GetxController {\n\n  /// Vous n'en avez pas besoin. Je recommande de l'utiliser uniquement pour faciliter la syntaxe.\n  /// avec la méthode statique: Controller.to.counter();\n  /// sans méthode statique: Get.find<Controller>() .counter();\n  /// Il n'y a aucune différence de performances, ni aucun effet secondaire de l'utilisation de l'une ou l'autre syntaxe. Un seul n'a pas besoin du type, et l'autre l'EDI le complétera automatiquement.\n   static Controller get to => Get.find(); // Ajouter cette ligne\n\n  int counter = 0;\n  void increment() {\n    counter++;\n    update();\n  }\n}\n```\n\nEt puis vous pouvez accéder directement à votre contrôleur, de cette façon:\n\n```dart\nFloatingActionButton(\n  onPressed:() {\n    Controller.to.increment(),\n  } // This is incredibly simple!\n  child: Text(\"${Controller.to.counter}\"),\n),\n```\n\nLorsque vous appuyez sur FloatingActionButton, tous les widgets qui écoutent la variable `counter` seront mis à jour automatiquement.\n\n### Comment il gère les contrôleurs\n\nDisons que nous avons ceci:\n\n`Class a => Class B (has controller X) => Class C (has controller X)`\n\nDans la classe A, le contrôleur n'est pas encore en mémoire, car vous ne l'avez pas encore utilisé (Get est 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 retirera automatiquement le contrôleur X de la mémoire et libèrera des ressources, car la classe A n'utilise pas le contrôleur. Si vous naviguez à nouveau vers B, le contrôleur X entrera à nouveau en mémoire, si au lieu de passer à la classe C, vous revenez en classe A, Get retirera le contrôleur de la mémoire de la même manière. Si la classe C n'utilisait pas le contrôleur et que vous retiriez la classe B de la mémoire, aucune classe n'utiliserait le contrôleur X et de même, elle serait éliminée. La seule exception qui peut gâcher Get, est si vous supprimez B de l'itinéraire de manière inattendue et essayez d'utiliser le contrôleur dans C.Dans ce cas, l'ID de créateur du contrôleur qui était dans B a été supprimé et Get a été programmé pour supprimer de la mémoire tous les contrôleurs qui n'ont pas d'ID de créateur. Si vous avez l'intention de faire cela, ajoutez l'indicateur \"autoRemove: false\" au GetBuilder de la classe B et utilisez adoptID = true; dans GetBuilder de la classe C.\n\n### Vous n'aurez plus besoin de StatefulWidgets\n\nUtiliser StatefulWidgets signifie stocker inutilement l'état d'écrans entiers, même parce que si vous avez besoin de reconstruire au minimum un widget, vous l'intègrerez dans un Consumer / Observer / BlocProvider / GetBuilder / GetX / Obx, qui sera un autre StatefulWidget.\nLa classe StatefulWidget est une classe plus grande que StatelessWidget, qui allouera plus de RAM, et cela ne fera peut-être pas une différence significative entre une ou deux classes, mais cela le fera très certainement lorsque vous en aurez 100!\nÀ moins que vous n'ayez besoin d'utiliser un mixin, comme TickerProviderStateMixin, il sera totalement inutile d'utiliser un StatefulWidget avec Get.\n\nVous pouvez appeler toutes les méthodes d'un StatefulWidget directement à partir d'un GetBuilder.\nSi vous devez appeler la méthode initState() ou dispose() par exemple, vous pouvez les appeler directement:\n\n```dart\nGetBuilder<Controller>(\n  initState: (_) => Controller.to.fetchApi(),\n  dispose: (_) => Controller.to.closeStreams(),\n  builder: (s) => Text('${s.username}'),\n),\n```\n\nUne bien meilleure approche que celle-ci consiste à utiliser les méthodes onInit() et onClose() directement à partir de votre contrôleur.\n\n```dart\n@override\nvoid onInit() {\n  fetchApi();\n  super.onInit();\n}\n```\n\n- NOTE: 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 package orienté performance comme Get, cela frôle la mauvaise pratique, car 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 remplirez un contrôleur avant même qu'il ne soit utilisé, vous allouez de la mémoire sans qu'elle ne soit utilisée , cela nuit définitivement aux principes de cette bibliothèque). Les méthodes onInit(); et onClose(); ont été créés pour cela, ils seront appelés lors de la création du Controller, ou lors de sa première utilisation, selon que vous utilisez Get.lazyPut ou non. Si vous voulez, par exemple, faire un appel à votre API pour remplir des données, vous pouvez oublier la méthode à l'ancienne de initState / dispose, lancez simplement votre appel à l'API dans onInit, et si vous devez exécuter une commande comme la fermeture des flux, utilisez onClose() pour cela.\n\n### Pourquoi ca existe\n\nLe but de ce package 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 le moins de dépendances possible, avec un haut degré de découplage. Get engage toutes les API Flutter de haut et bas niveau en lui-même, pour vous assurer de travailler avec le moins de couplage possible. Nous centralisons tout dans un seul package, pour vous assurer que vous n'avez aucun type de couplage dans votre projet. De cette façon, vous pouvez mettre uniquement des widgets dans votre vue et laisser la partie de votre équipe qui travaille avec la `business logique` libre, pour travailler avec la business logique sans dépendre d'aucun élément de la vue. Cela fournit un environnement de travail beaucoup plus propre, de sorte qu'une partie de votre équipe ne travaille 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 business logique dans toute son ampleur, sans dépendre d'aucun élément de la Vue.\n\nDonc, pour simplifier cela:\nVous n'avez pas besoin d'appeler des méthodes dans initState et de les envoyer par paramètre à votre contrôleur, ni d'utiliser votre constructeur de contrôleur pour cela, vous avez la méthode onInit() qui est appelée au bon moment pour démarrer vos services.\nVous 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 supprimé de la mémoire. De cette façon, ne laissez les vues que pour les widgets, abstenez-vous d'y mettre tout type de business logique.\n\nN'appelez pas une méthode dispose() dans GetxController, cela ne fera rien, rappelez-vous que le contrôleur n'est pas un Widget, vous ne devez pas le `supprimer`, et il sera automatiquement et intelligemment supprimé de la mémoire par Get. Si vous avez utilisé un Stream et que vous souhaitez le fermer, insérez-le simplement dans la méthode close(). Exemple:\n\n```dart\nclass Controller extends GetxController {\n  StreamController<User> user = StreamController<User>();\n  StreamController<String> name = StreamController<String>();\n\n  /// pour fermer stream = méthode onClose(), pas dispose().\n  @override\n  void onClose() {\n    user.close();\n    name.close();\n    super.onClose();\n  }\n}\n```\n\nCycle de vie du controlleur:\n\n- onInit() quand il est créé.\n- onClose() quand il est fermé pour apporter des modifications en préparation de la méthode delete.\n- deleted: vous n'avez pas accès à cette API car elle supprime littéralement le contrôleur de la mémoire. Il est littéralement supprimé, sans laisser de trace.\n\n### Autres formes d utilisation\n\nVous pouvez utiliser l'instance Controller directement sur la valeur GetBuilder:\n\n```dart\nGetBuilder<Controller>(\n  init: Controller(),\n  builder: (value) => Text(\n    '${value.counter}', // ici\n  ),\n),\n```\n\nVous pouvez également avoir besoin d'une instance de votre contrôleur en dehors de votre GetBuilder, et vous pouvez utiliser ces approches pour y parvenir:\n\n```dart\nclass Controller extends GetxController {\n  static Controller get to => Get.find();\n[...]\n}\n// Dans la vue:\nGetBuilder<Controller>(  \n  init: Controller(), // utilisez-le seulement la première fois sur chaque contrôleur\n  builder: (_) => Text(\n    '${Controller.to.counter}', // ici\n  )\n),\n```\n\nou encore\n\n```dart\nclass Controller extends GetxController {\n // static Controller get to => Get.find(); // sans static get\n[...]\n}\n// Dans la classe stateful/stateless\nGetBuilder<Controller>(  \n  init: Controller(), // utilisez-le seulement la première fois sur chaque contrôleur\n  builder: (_) => Text(\n    '${Get.find<Controller>().counter}', // ici\n  ),\n),\n```\n\n- Vous pouvez utiliser des approches `non canoniques` pour ce faire. Si vous utilisez un autre gestionnaire de dépendances, comme get_it, modular, etc., et que vous souhaitez simplement fournir l'instance de contrôleur, vous pouvez le faire:\n\n```dart\nController controller = Controller();\n[...]\nGetBuilder<Controller>(\n  init: controller, // ici\n  builder: (_) => Text(\n    '${controller.counter}', // ici\n  ),\n),\n\n```\n\n### IDs Uniques\n\nSi vous souhaitez affiner le contrôle de mise à jour d'un widget avec GetBuilder, vous pouvez leur attribuer des ID uniques:\n\n```dart\nGetBuilder<Controller>(\n  id: 'text'\n  init: Controller(), // utilisez-le seulement la première fois sur chaque contrôleur\n  builder: (_) => Text(\n    '${Get.find<Controller>().counter}', // ici\n  ),\n),\n```\n\nEt mettez-le à jour de cette façon:\n\n```dart\nupdate(['text']);\n```\n\nVous pouvez également imposer des conditions pour la mise à jour:\n\n```dart\nupdate(['text'], counter < 10);\n```\n\nGetX le fait automatiquement et ne reconstruit que le widget qui utilise la variable exacte qui a été modifiée, si vous remplacez une variable par la même que la précédente et que cela n'implique pas un changement d'état, GetX ne reconstruira pas le widget pour économiser de la mémoire et Cycles CPU (3 est affiché à l'écran, et vous changez à nouveau la variable à 3. Dans la plupart des gestionnaires d'états, cela entraînera une nouvelle reconstruction, mais avec GetX, le widget ne sera reconstruit qu'à nouveau, si en fait son état a changé ).\n\n## Mélanger les deux gestionnaires d'état\n\nCertaines personnes ont ouvert une demande de fonctionnalité, car elles ne voulaient utiliser qu'un seul type de variable réactive, et les autres mécanismes, et devaient insérer un Obx dans un GetBuilder pour cela. En y réfléchissant, MixinBuilder a été créé. Il permet à la fois des changements réactifs en changeant les variables \".obs\" et des mises à jour mécaniques via update(). Cependant, des 4 widgets c'est celui qui consomme le plus de ressources, car en plus d'avoir un Abonnement pour recevoir les événements de changement de ses enfants, il souscrit à la méthode de mise à jour de son contrôleur.\n\nL'extension de GetxController est importante, car ils ont des cycles de vie et peuvent `démarrer` et `terminer` des é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'elles soient observables ou non.\n\n## GetBuilder vs GetX vs Obx vs MixinBuilder\n\nEn une décennie de travail avec la programmation, j'ai pu apprendre de précieuses leçons.\n\nMon premier contact avec la programmation réactive a été tellement \"wow, c'est incroyable\" et en fait la programmation réactive est incroyable.\nCependant, elle ne convient pas à toutes les situations. Souvent, il suffit de changer l'état de 2 ou 3 widgets en même temps, ou d'un changement d'état éphémère, auquel cas la programmation réactive n'est pas mauvaise, mais elle n'est pas appropriée.\n\nLa programmation réactive a une consommation de RAM plus élevée qui peut être compensée par le flux de travail individuel, ce qui garantira qu'un seul widget est reconstruit et si nécessaire, mais créer une liste avec 80 objets, chacun avec plusieurs flux n'est pas une bonne idée . Ouvrez le 'dart inspect' et vérifiez combien un StreamBuilder consomme, et vous comprendrez ce que j'essaie de vous dire.\n\nDans cet esprit, j'ai créé le gestionnaire d'état simple. C'est simple, et c'est exactement ce que vous devriez lui demander: mettre à jour l'état par blocs de manière simple et de la manière la plus économique.\n\nGetBuilder est très économique en RAM, et il n'y a guère d'approche plus économique que lui (du moins je ne peux pas en imaginer une, si elle existe, merci de nous le faire savoir).\n\nCependant, GetBuilder est toujours un gestionnaire d'état mécanique, vous devez appeler update() comme vous auriez besoin d'appeler les notifyListeners() de Provider.\n\nIl y a d'autres situations où la programmation réactive est vraiment intéressante, et ne pas travailler avec elle revient à réinventer la roue. Dans cet esprit, GetX a été créé pour fournir tout ce qui est le plus moderne et le plus avancé dans un gestionnaire d'état. Il met à jour uniquement ce qui est nécessaire et si nécessaire, si vous avez une erreur et envoyez 300 changements d'état simultanément, GetX filtrera et mettra à jour l'écran uniquement si l'état change réellement.\n\nGetX est toujours plus économique que tout autre gestionnaire d'état réactif, mais il consomme un peu plus de RAM que GetBuilder. En y réfléchissant et en visant à maximiser la consommation de ressources, Obx a été créé. Contrairement à GetX et GetBuilder, vous ne pourrez pas initialiser un contrôleur à l'intérieur d'un Obx, c'est juste un widget avec un StreamSubscription qui reçoit les événements de changement de vos widgets enfants, c'est tout. Il est plus économique que GetX, mais perd face à GetBuilder, ce qui était prévisible, 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."
  },
  {
    "path": "documentation/id_ID/dependency_management.md",
    "content": "- [Dependency Management](#dependency-management)\n  - [Menginstansiasi method](#menginstansiasi-method)\n    - [Get.put()](#getput)\n    - [Get.lazyPut](#getlazyput)\n    - [Get.putAsync](#getputasync)\n    - [Get.create](#getcreate)\n  - [Menggunakan method/kelas yang terinstansiasi](#menggunakan-methodkelas-yang-terinstansiasi)\n  - [Perbedaan antar method](#perbedaan-antar-method)\n  - [Bindings](#bindings)\n    - [Bindings class](#bindings-class)\n    - [BindingsBuilder](#bindingsbuilder)\n    - [SmartManagement](#smartmanagement)\n      - [Cara mengubahnya](#cara-mengubahnya)\n      - [SmartManagement.full](#smartmanagementfull)\n      - [SmartManagement.onlyBuilders](#smartmanagementonlybuilders)\n      - [SmartManagement.keepFactory](#smartmanagementkeepfactory)\n    - [Cara kerja bindings dibalik layar](#cara-kerja-bindings-dibalik-layar)\n  - [Catatan](#catatan)\n\n# Dependency Management\n\nGet memiliki dependency manager sederhana dan powerful yang memungkinkan anda mendapatkan kelas yang setara dengan Bloc atau Controller hanya dengan 1 baris kode, tanpa Provider context, tanpa inheritedWidget:\n\n```dart\nController controller = Get.put(Controller());\n```\n\nDaripada menginstansiasi kelas anda didalam kelas yang anda gunakan, cukup lakukan hal itu di dalam Get instance, ini akan membuatnya tersedia di semua tempat di Aplikasimu. Jadi anda bisa menggunakan controller (atau class Bloc) secara normal.\n\n- Catatan: Jika anda menggunakan State Manager milik Get, harap untuk lebih memperhatikan [Bindings](#bindings) api, yang mana akan membuat pengkoneksian View terhadap Controller jadi lebih mudah.\n- Note²: Dependency Management Get terpisah dari bagian lain dari package, jadi jika sebagai contoh aplikasi anda sudah menggunakan state manager (tidak peduli apapun itu), anda tidak perlu menulis ulang sama sekali, anda bisa menggunakan dependency injection tanpa masalah.\n\n## Menginstansiasi method\n\nBerikut adalah metode dan parameternya yang dapat dikonfigurasi:\n\n### Get.put()\n\nCara paling umum untuk memasukkan dependensi, untuk kontroler dari view anda contohnya.\n\n```dart\nGet.put<SomeClass>(SomeClass());\nGet.put<LoginController>(LoginController(), permanent: true);\nGet.put<ListItemController>(ListItemController, tag: \"some unique string\");\n```\n\nBerikut adalah semua opsi yang bisa anda atur ketika menggunakan put:\n\n```dart\nGet.put<S>(\n  // wajib: kelas yang ingin anda simpan, seperti controller, atau apapun\n  // catatan: \"S\" menandakan bahwa tipenya bisa jadi sebuah kelas dari tipe apapun.\n  S dependency\n\n  // opsional: ini digunakan ketika anda ingin memasukkan banyak kelas yang memiliki tipe yang sama.\n  // berhubung normalnya anda memanggil kelas menggunakan Get.find<Controller>(),\n  // anda perlu menggunakan tag untuk menandai instance mana yang anda butuhkan\n  // tag harus unik, dan bertipe String.\n  String tag,\n\n  // opsional: secara default, get akan men-dispose instance setelah tidak digunakan lagi (contoh,\n  // sebuah controller dari view yang ditutup), tapi mungkin anda membutuhkannya untuk digunakan\n  // ditempat lain di aplikasi anda, contohnya seperti sebuah instance dari SharedPreference, atau yang lain.\n  // Maka anda perlu ini\n  // nilai defaultnya adalah false\n  bool permanent = false,\n\n  // opsional: memungkinkan anda setelah menggunakan kelas abstrak didalam test, menggantinya dengan yang lain dan mengikuti testnya.\n  // nilai defaultnya adalah false\n  bool overrideAbstract = false,\n\n  // opsional: memungkinkan anda untuk memasukkan dependensi menggunakan fungsi daripada dependensi itu sendiri.\n  // ini jarang dipakai.\n  InstanceBuilderCallback<S> builder,\n)\n```\n\n### Get.lazyPut\n\nAnda bisa melakukan lazyload terhadap sebuah dependensi supaya dependensi tersebut terinstansiasi hanya ketika digunakan saja. Sangat berguna untuk kelas komputasional yang \"mahal\" atau jika anda ingin menginstansiasi beberapa kelas hanya dalam satu lokasi (seperti pada kelas Bindings) dan anda tahu anda tidak akan menggunakannya secara langsung.\n\n```dart\n/// ApiMock hanya akan dipanggil ketika seseorang menggunakan Get.find<ApiMock> pertama kali.\nGet.lazyPut<ApiMock>(() => ApiMock());\n\nGet.lazyPut<FirebaseAuth>(\n  () {\n    // ... beberapa logic jika diperlukan..\n    return FirebaseAuth();\n  },\n  tag: Math.random().toString(),\n  fenix: true\n)\n\nGet.lazyPut<Controller>( () => Controller() )\n```\n\nBerikut adalah semua opsi yang bisa anda atur ketika menggunakan lazyPut:\n\n```dart\nGet.lazyPut<S>(\n  // wajib: sebuah method yang akan di eksekusi ketika kelas anda dipanggil untuk pertama kali\n  InstanceBuilderCallback builder,\n  \n  // opsional: sama seperti Get.put(), ini digunakan ketika anda menginginkan banyak instance berbeda dengan kelas yang sama\n  // harus unik dan harus String.\n  String tag,\n\n  // opsional: Mirip seperti \"permanent\", bedanya adalah instance akan dihapus ketika tidak\n  // digunakan, tetapi ketika diperlukan lagi, Get akan membuat ulang instance yang sama,\n  // seperti \"SmartManagement.keepFactory\" pada bindings api.\n  bool fenix = false\n  \n)\n```\n\n### Get.putAsync\n\nJika anda ingin mendaftarkan instance yang asynchronous, anda bisa menggunakan `Get.putAsync()`:\n\n```dart\nGet.putAsync<SharedPreferences>(() async {\n  final prefs = await SharedPreferences.getInstance();\n  await prefs.setInt('counter', 12345);\n  return prefs;\n});\n\nGet.putAsync<YourAsyncClass>( () async => await YourAsyncClass() )\n```\n\nBerikut adalah semua opsi yang anda bisa atur ketika menggunakan putAsync:\n\n```dart\nGet.putAsync<S>(\n\n  // wajib: sebuah async method yang akan di eksekusi untuk menginstansiasi kelas anda\n  AsyncInstanceBuilderCallback<S> builder,\n\n  // opsional: sama seperti Get.put(), ini digunakan ketika anda menginginkan banyak instance berbeda dengan kelas yang sama\n  // harus unik dan harus String.\n  String tag,\n\n  // opsional: sama seperti Get.put(), digunakan ketika anda ingin mempertahankan\n  // instance tersebut (keep-alive) untuk digunakan diseluruh aplikasi anda.\n  // nilai defaultnya adalah false\n  bool permanent = false\n)\n```\n\n### Get.create\n\nYang satu ini agak rumit. Penjelasan lebih detail tentang ini dan perbedaannya dengan yang lain bisa ditemukan di sesi [Perbedaan antar method](#perbedaan-antar-method).\n\n```dart\nGet.create<SomeClass>(() => SomeClass());\nGet.create<LoginController>(() => LoginController());\n```\n\nBerikut adalah semua opsi yang bisa anda atur ketika menggunakan create:\n\n```dart\nGet.create<S>(\n  // diperlukan: sebuah fungsi yang mereturn sebuah kelas yang akan \"terfabrikasi\" setiap\n  // kali `Get.find()` dipanggil\n  // Contoh: Get.create<YourClass>(() => YourClass())\n  FcBuilderFunc<S> builder,\n\n  // opsional: sama seperti Get.put(), ini digunakan ketika anda menginginkan\n  // banyak instance berbeda dengan kelas yang sama.\n  // Berguna dalam kasus ketika anda memiliki sebuah list yang setiap isinya membutuhkan\n  // controllernya masing-masing.\n  // Harus unik dan harus String. Cukup ganti `tag` menjadi `name`.\n  String name,\n\n  // opsional: sama seperti Get.put(), digunakan ketika anda ingin mempertahankan\n  // instance tersebut (keep-alive) untuk digunakan diseluruh aplikasi anda.\n  // Untuk Get.create, `permanent` nilainya `true` secara default.\n  bool permanent = true\n```\n\n## Menggunakan method/kelas yang terinstansiasi\n\nBayangkan anda bernavigasi melewati route yang sangat banyak, dan anda membutuhkan data yang tertinggal didalam controller jauh di belakang route sebelumnya, anda akan butuh state manager dikombinasikan dengan Provider atau Get_it, benar kan? Tidak dengan Get. Anda hanya perlu meminta Get untuk \"menemukan\" controllernya, anda tidak perlu dependensi tambahan:\n\n```dart\nfinal controller = Get.find<Controller>();\n// ATAU\nController controller = Get.find();\n\n// Ya, terlihat seperti Sulap, Get akan menemukan controller anda, dan akan mengantarkannya ke lokasi anda.\n// Anda bisa memiliki 1 juta controller terinisialisasi, Get akan selalu memberimu controller yang tepat.\n```\n\nDan setelahnya anda bisa memperoleh data yang tertinggal sebelumnya:\n\n```dart\nText(controller.textFromApi);\n```\n\nBerhubung value yang direturn adalah sebuah kelas normal, anda bisa melakukan apapun yang anda mau:\n\n```dart\nint count = Get.find<SharedPreferences>().getInt('counter');\nprint(count); // keluaran: 12345\n```\n\nUntuk menghapus sebuah instance dari Get:\n\n```dart\nGet.delete<Controller>(); // biasanya anda tidak perlu melakukan ini karena GetX sudah melakukannya untuk anda\n```\n\n## Perbedaan antar method\n\nSebelum kita mulai, mari kita bahas tentang `fenix` dari Get.lazyPut dan `permanent` dari method lainnya.\n\nPerbedaan mendasar diantara `permanent` dan `fenix` adalah bagaimana anda ingin menyimpannya (kelas anda).\n\nMenguatkan: secara default, GetX menghapus instance ketika tidak digunakan.\n\nArtinya: Jika screen 1 memiliki controller 1, dan screen 2 memiliki controller 2, dan anda menghapus route pertama dari stack, (seperti pada halnya anda menggunakan `Get.off()` atau `Get.offNamed()`), controller 1 akan kehilangan status kegunaannya dan akan dihapus.\n\nTapi jika anda menggunakan `permanent:true`, maka controller tidak akan dihapus pada saat berpindah halaman - yang mana sangat berguna untuk service yang ingin anda pertahankan supaya tetap ada (keep-alive) diseluruh aplikasi anda.\n\n`fenix` di sisi lain adalah sebuah service yang anda tidak perlu khawatir kehilangan ketika berpindah antar halaman, tetapi ketika anda membutuhkan service tersebut, anda berekspektasi bahwa service tersebut masih ada. Walaupun sebenarnya, controller/service/class tetap ter-dispose, dan ketika anda membutuhkannya, dia akan membuat ulang (dari abu-nya) sebuah instance baru.\n\nLanjut dengan perbedaan antar method:\n\n- Get.put dan Get.putAsync mengikuti urutan pembuatan yang sama, bedanya, yang kedua menggunakan asynchronous method: kedua method tersebut membuat dan menginisialisasi sebuah instance. Dimasukkan secara langsung kedalam memori, menggunakan method internal `insert` dengan parameter `permanent:false` dan `isSingleton:true` (isSingleton parameter ini hanya hanya bertujuan untuk membedakan apakah harus menggunakannya pada `dependency` atau menggunakannya pada `FcBuilderFunc`). Setelah itu, `Get.find()` dipanggil dan segera menginisialisasi instance yang ada didalam memori.\n\n- Get.create: seperti namanya, dia akan \"membuat\" dependensi anda! Mirip seperti `Get.put()`, dia juga memanggil metode internal `insert` untuk menginstansiasi. Namun mengubah `permanent` menjadi true dan `isSingleton` menjadi false (karena kita \"membuat\" dependensi, tidak ada cara untuk menjadikannya sebagai singleton, inilah kenapa nilainya false). Dan karena dia memiliki `permanent:true`, kita secara default memiliki keuntungan untuk tidak kehilangannya pada saat berpindah halaman! Dan juga, `Get.find()` tidak dipanggil secara langsung, dia menunggu untuk digunakan disuatu halaman untuk dipanggil. Ini dibuat dengan cara tersebut supaya bisa menggunakan parameter `permanent`, sementara itu, perlu diketahui, `Get.create()` dibuat dengan tujuan untuk membuat instance yang tidak dapat di-share, tetapi juga tidak ter-dispose, seperti contohnya sebuah button didalam ListView, dan anda menginginkan sebuah instance unik untuk list tersebut - karena itu, Get.create harus digunakan bersamaan dengan GetWidget.\n\n- Get.lazyPut: seperti namanya, ini membuat \"lazy process\". Instance nya dibuat, namun tidak digunakan secara langsung, dia menunggu untuk dipanggil. Bertentangan dengan metode lain, `insert` tidak dipanggil disini. Sebaliknya, instance dimasukkan ke bagian lain didalam memori, bagian yang bertanggung jawab untuk memberi tahu apakah instance bisa dibuat ulang atau tidak, mari kita sebut itu sebagai \"factory\". Jika kita ingin membuat sesuatu untuk digunakan nanti, ini tidak akan tercampur dengan yang digunakan sekarang. Dan disini adalah dimana \"sihir\" `fenix` terjadi: jika anda memilih untuk membiarkan `fenix: false`, dan `smartManagement` bukan `keepFactory`, maka ketika menggunakan `Get.find`, instance akan mengubah posisinya didalam memori supaya tersedia di bagian terpisah ini, bahkan menuju ke area umum, untuk dipanggil lagi di masa yang akan datang.\n\n## Bindings\n\nSalah satu dari perbedaan besar dari package ini, mungkin, adalah suatu kemungkinan untuk mengintegrasikan route, state manager, dan dependency manager secara penuh.\n\nKetika route dihapus dari Stack, semua kontroler, variabel, dan instance yang berhubungan dengan itu akan dihapus dari memori. Jika anda menggunakan stream atau timer, mereka akan ditutup secara otomatis, dan anda tidak perlu khawatir tentang hal itu.\n\nDi versi 2.10, Get benar-benar mengimplementasi Bindings API. Sekarang anda tidak perlu menggunakan init method. Bahkan anda tidak perlu mengetik controller yang ingin anda tuju jika anda mau. Anda bisa memulai controller dan service di tempat yang tepat untuk itu.\n\nBinding class adalah sebuah kelas yang memisahkan dependency injection, sembari \"mengaitkan\" route ke state manager dan dependency manager.\n\nIni memungkinkan Get untuk mengetahui tampilan mana yang sedang ditampilkan ketika controller yang bersangkutan digunakan dan untuk mengetahui bagaimana cara men-dispose nya.\n\nSebagai tambahan, Binding class memungkinkan anda untuk memiliki kontrol terhadap konfigurasi SmartManager. Anda bisa mengkonfigurasi dependensi anda untuk diurutkan ketika penghapusan route dari stack, atau ketika widget yang digunakan diletakkan, atau tidak keduanya. Anda akan memiliki dependensi management pintar yang bekerja untuk anda, tapi meski begitu, anda bisa mengkonfigurasinya sesuka hati anda.\n\n### Bindings class\n\n- Buat sebuah kelas yang meng-implements Bindings\n\n```dart\nclass HomeBinding implements Bindings {}\n```\n\nIDE anda akan secara otomatis meminta anda untuk meng-override \"dependencies method\", dan anda hanya perlu klik ikon lampu, override method nya, dan masukkan semua kelas yang akan anda gunakan dalam route tersebut:\n\n```dart\nclass HomeBinding implements Bindings {\n  @override\n  void dependencies() {\n    Get.lazyPut<HomeController>(() => HomeController());\n    Get.put<Service>(()=> Api());\n  }\n}\n\nclass DetailsBinding implements Bindings {\n  @override\n  void dependencies() {\n    Get.lazyPut<DetailsController>(() => DetailsController());\n  }\n}\n```\n\nSekarang anda hanya perlu memberi tahu route anda, bahwa anda akan menggunakan binding tersebut untuk membuat koneksi diantara route manager, dependency manager dan state.\n\n- Menggunakan named route:\n\n```dart\ngetPages: [\n  GetPage(\n    name: '/',\n    page: () => HomeView(),\n    binding: HomeBinding(),\n  ),\n  GetPage(\n    name: '/details',\n    page: () => DetailsView(),\n    binding: DetailsBinding(),\n  ),\n];\n```\n\n- Menggunakan normal route:\n\n```dart\nGet.to(Home(), binding: HomeBinding());\nGet.to(DetailsView(), binding: DetailsBinding())\n```\n\nDisana, anda tidak perlu lagi khawatir tentang manajemen memori aplikasi anda, Get akan melakukannya untuk anda.\n\nBinding akan dipanggil ketika route dipanggil, anda juga bisa membuat sebuah \"initialBinding\" di GetMaterialApp dan memasukkan semua dependensi yang diperlukan.\n\n```dart\nGetMaterialApp(\n  initialBinding: SampleBind(),\n  home: Home(),\n);\n```\n\n### BindingsBuilder\n\nSecara default, untuk membuat sebuah binding adalah dengan membuat kelas baru yang meng-implements Bindings.\nSecara alternatif, anda bisa menggunakan `BindingsBuilder` untuk menginstansiasi apapun yang anda mau melalui sebuah fungsi callback.\n\nExample:\n\n```dart\ngetPages: [\n  GetPage(\n    name: '/',\n    page: () => HomeView(),\n    binding: BindingsBuilder(() {\n      Get.lazyPut<ControllerX>(() => ControllerX());\n      Get.put<Service>(()=> Api());\n    }),\n  ),\n  GetPage(\n    name: '/details',\n    page: () => DetailsView(),\n    binding: BindingsBuilder(() {\n      Get.lazyPut<DetailsController>(() => DetailsController());\n    }),\n  ),\n];\n```\n\nDengan cara ini, anda bisa menghindari membuat satu kelas Binding untuk setiap route yang anda buat, membuatnya jadi semakin simpel.\n\nKedua cara tersebut bekerja secara sempurna dan kami ingin anda menggunakan yang manapun yang anda rasa cocok untuk anda.\n\n### SmartManagement\n\nGetX secara default men-dispose controller yang tidak digunakan dari memori, bahkan jika kegagalan terjadi dan widget yang menggunakannya tidak ter-dispose dengan benar.\nIni adalah apa yang disebut dengan `full` mode dari sebuah dependency management.\nTetapi jika anda ingin mengubah cara kerja GetX dalam mengontrol \"disposal\" terhadap kelas, anda memiliki kelas `SmartManagement` yang anda bisa atur perilakunya.\n\n#### Cara mengubahnya\n\nJika anda ingin mengubah konfigurasi ini (yang biasanya tidak diperlukan), ini caranya:\n\n```dart\nvoid main () {\n  runApp(\n    GetMaterialApp(\n      smartManagement: SmartManagement.onlyBuilders // Disini\n      home: Home(),\n    )\n  )\n}\n```\n\n#### SmartManagement.full\n\nIni adalah pengaturan default. Dispose semua kelas yang tidak digunakan dan tidak ditandai sebagai permanent. Di kebanyakan kasus anda ingin konfigurasi ini tidak disentuh. Jika anda baru di GetX, jangan mengubahnya.\n\n#### SmartManagement.onlyBuilders\n\nDengan opsi ini, hanya controller yang dimulai didalam `init:` atau yang ter-load kedalam sebuah Binding dengan `Get.lazyPut()`, yang akan di dispose.\n\nJika anda menggunakan `Get.put()` atau `Get.putAsync()` atau cara lain, SmartManagement tidak akan memiliki izin untuk meng-exclude dependensi ini.\n\nDengan perilaku default, bahkan widget yang terinstansiasi dengan \"Get.put\" akan dihapus, tidak seperti SmartManagement.onlyBuilders.\n\n#### SmartManagement.keepFactory\n\nSama seperti SmartManagement.full, ini akan menghapus semua dependensi ketika tidak digunakan lagi. Meski begitu, ini akan menyimpan factory mereka, yang artinya dia akan membuat ulang dependensi jika anda membutuhkannya lagi.\n\n### Cara kerja bindings dibalik layar\n\nBindings membuat factory sementara, yang mana dibuat ketika anda meng-klik untuk pindah ke halaman lain, dan akan dihapus segera setelah animasi perpindahan halaman terjadi.\nIni terjadi begitu cepat bahkan analyzer sekalipun tidak bisa meregistrasikannya.\nKetika anda kembali ke halaman itu lagi, factory baru akan dipanggil, jadi ini lebih disarankan daripada menggunakan SmartManagement.keepFactory, tapi jika anda tidak ingin membuat Bindings, atau ingin menyimpan semua dependensi didalam Binding yang sama, itu akan sangat membantu.\nKonsumsi memori terhadap Factory sangatlah kecil, mereka tidak memegang instance, hanya sebuah fungsi dengan \"bentukan\" dari kelas yang anda inginkan.\nIni sangat menghemat penggunaan memori, tetapi karena tujuan dari lib ini adalah untuk mendapatkan performa maksimum dan menggunakan resource seminimum mungkin, Get menghapus bahkan si factory itu sendiri secara default.\nGunakan mana yang anda rasa mudah untuk anda.\n\n## Catatan\n\n- JANGAN GUNAKAN SmartManagement.keepFactory jika anda menggunakan lebih dari satu Bindings. Ini dedesain untuk digunakan tanpa Bindings, atau dengan satu Binding terhubung dengan initialBinding milik GetMaterialApp.\n\n- Menggunakan Binding sifatnya opsional, jika anda mau, anda bisa menggunakan `Get.put()` dan `Get.find()` untuk kelas yang menggunakan controller tanpa masalah.\n  Meski begitu, jika anda bekerja dengan Service atau segala jenis abstraksi lain, Saya merekomendasikan menggunakan Bindings supaya pengorganisiran menjadi lebih baik.\n"
  },
  {
    "path": "documentation/id_ID/route_management.md",
    "content": "- [Route Management](#route-management)\n  - [Cara pakai](#cara-pakai)\n  - [Navigasi tanpa named route](#navigasi-tanpa-named-route)\n  - [Navigasi menggunakan named route](#navigasi-menggunakan-named-route)\n    - [Mengirim data ke named route](#mengirim-data-ke-named-route)\n    - [Tautan URL dinamis](#tautan-url-dinamis)\n    - [Middleware](#middleware)\n  - [Navigasi tanpa konteks](#navigasi-tanpa-konteks)\n    - [SnackBar](#snackbar)\n    - [Dialog](#dialog)\n    - [BottomSheet](#bottomsheet)\n  - [Navigasi Bersarang](#navigasi-bersarang)\n\n# Route Management\n\nIni adalah penjelasan lengkap mengenai route management di GetX.\n\n## Cara pakai\n\nTambahkan ini kedalam pubspec.yaml anda:\n\n```yaml\ndependencies:\n  get:\n```\n\nJika anda akan menggunakan route/snackbar/dialog/bottomsheet tanpa konteks, atau menggunakan high-level API dari Get, cukup tambahkan \"Get\" sebelum MaterialApp, mengubahnya menjadi GetMaterialApp, dan selamat menikmati!\n\n```dart\nGetMaterialApp( // Sebelumnya: MaterialApp(\n  home: MyHome(),\n)\n```\n\n## Navigasi tanpa named route\n\nUntuk pindah ke halaman baru:\n\n```dart\nGet.to(NextScreen());\n```\n\nUntuk menutup snackbar, dialog, bottomsheet, atau apapun yang normalnya anda tutup menggunakan Navigator.pop(context);\n\n```dart\nGet.back();\n```\n\nUntuk pergi ke halaman baru dan mencegah user kembali ke halaman sebelumnya (biasanya digunakan untuk SplashScreen, LoginScreen, dsb).\n\n```dart\nGet.off(NextScreen());\n```\n\nUntuk pergi ke halaman baru dan batalkan navigasi sebelumnya (berguna untuk shopping cart, polls, dan test).\n\n```dart\nGet.offAll(NextScreen());\n```\n\nUntuk pergi ke halaman baru dan menerima atau memperbarui data segera setelah anda kembali dari halaman tersebut:\n\n```dart\nvar data = await Get.to(Payment());\n```\n\npada halaman lain, kirim data ke halaman sebelumnya:\n\n```dart\nGet.back(result: 'success');\n```\n\nLalu gunakan:\n\ncontoh:\n\n```dart\nif(data == 'success') madeAnything();\n```\n\nBukankah anda ingin mempelajari sintaks kami?\nCukup ubah Navigator (uppercase) ke navigator (lowercase), dan anda akan mendapatkan semua fungsi standar navigasi, tanpa harus menggunakan konteks.\nContoh:\n\n```dart\n\n// Navigator bawaan Flutter\nNavigator.of(context).push(\n  context,\n  MaterialPageRoute(\n    builder: (BuildContext context) {\n      return HomePage();\n    },\n  ),\n);\n\n// Get menggunakan sintaks Flutter tanpa membutuhkan konteks.\nnavigator.push(\n  MaterialPageRoute(\n    builder: (_) {\n      return HomePage();\n    },\n  ),\n);\n\n// Sintaks Get (Lebih baik, tapi anda juga berhak untuk tidak setuju)\nGet.to(HomePage());\n\n\n```\n\n## Navigasi menggunakan named route\n\n- Jika anda lebih suka bernavigasi menggunakan namedRoutes, Get juga bisa melakukannya.\n\nUntuk pindah ke halaman nextScreen\n\n```dart\nGet.toNamed(\"/NextScreen\");\n```\n\nUntuk pindah dan hapus halaman sebelumnya dari widget tree.\n\n```dart\nGet.offNamed(\"/NextScreen\");\n```\n\nUntuk pindah dan hapus semua halaman sebelumnya dari widget tree.\n\n```dart\nGet.offAllNamed(\"/NextScreen\");\n```\n\nUntuk mendifinisikan route, gunakan GetMaterialApp:\n\n```dart\nvoid main() {\n  runApp(\n    GetMaterialApp(\n      initialRoute: '/',\n      getPages: [\n        GetPage(name: '/', page: () => MyHomePage()),\n        GetPage(name: '/second', page: () => Second()),\n        GetPage(\n          name: '/third',\n          page: () => Third(),\n          transition: Transition.zoom  \n        ),\n      ],\n    )\n  );\n}\n```\n\nUntuk menangani navigasi ke route yang tidak terdefinisi (404), anda bisa mendefinisikan sebuah halaman unknownRoute didalam GetMaterialApp.\n\n```dart\nvoid main() {\n  runApp(\n    GetMaterialApp(\n      unknownRoute: GetPage(name: '/notfound', page: () => UnknownRoutePage()),\n      initialRoute: '/',\n      getPages: [\n        GetPage(name: '/', page: () => MyHomePage()),\n        GetPage(name: '/second', page: () => Second()),\n      ],\n    )\n  );\n}\n```\n\n### Mengirim data ke named route\n\nCukup kirim apa yang anda mau sebagai arguments. Get menerima apapun disitu, baik dalam bentuk String, Map, List atau bahkan instance dari sebuah Kelas.\n\n```dart\nGet.toNamed(\"/NextScreen\", arguments: 'Get is the best');\n```\n\ndi dalam kelas atau controller anda:\n\n```dart\nprint(Get.arguments);\n// keluaran: Get is the best\n```\n\n### Tautan URL dinamis\n\nGet menawarkan tautan URL dinamis lebih lanjut sama seperti di Web. Para Web developer mungkin sudah menginginkan fitur ini di Flutter, dan mungkin juga sering melihat sebuah package menjanjikan fitur ini dan mengantarkan sintaks yang benar benar berbeda dari sebuah URL yang kita miliki di web, Get juga menyelesaikan masalah ini.\n\n```dart\nGet.offAllNamed(\"/NextScreen?device=phone&id=354&name=Enzo\");\n```\n\ndidalam controller/bloc/stateful/stateless class anda:\n\n```dart\nprint(Get.parameters['id']);\n// keluaran: 354\nprint(Get.parameters['name']);\n// keluaran: Enzo\n```\n\nAnda juga bisa menerima NamedParameters dengan Get dengan mudah:\n\n```dart\nvoid main() {\n  runApp(\n    GetMaterialApp(\n      initialRoute: '/',\n      getPages: [\n      GetPage(\n        name: '/',\n        page: () => MyHomePage(),\n      ),\n      GetPage(\n        name: '/profile/',\n        page: () => MyProfile(),\n      ),\n       // Anda bisa mendefinisikan halaman berbeda untuk routes dengan arguments,\n       // dan yang lainnya tanpa arguments, namun untuk itu anda perlu slash '/'\n       // pada route yang tidak menerima arguments seperti diatas.\n       GetPage(\n        name: '/profile/:user',\n        page: () => UserProfile(),\n      ),\n      GetPage(\n        name: '/third',\n        page: () => Third(),\n        transition: Transition.cupertino  \n      ),\n     ],\n    )\n  );\n}\n```\n\nKirim data ke named route\n\n```dart\nGet.toNamed(\"/profile/34954\");\n```\n\nPada halaman kedua, ambil data menggunakan parameter\n\n```dart\nprint(Get.parameters['user']);\n// keluaran: 34954\n```\n\natau kirim beberapa parameter seperti ini\n\n```dart\nGet.toNamed(\"/profile/34954?flag=true\");\n```\n\nPada layar kedua, ambil data berdasarkan parameter seperti biasanya\n\n```dart\nprint(Get.parameters['user']);\nprint(Get.parameters['flag']);\n// keluaran: 34954 true\n```\n\n\nDan sekarang, yang anda perlu lakukan adalah menggunakan Get.toNamed() untuk bernavigasi ke named route anda, tanpa konteks (anda bisa memanggil route secara langsung dari kelas BLoC atau Controller), dan ketika aplikasi anda di-compile di web, route anda akan muncul di url <3\n\n### Middleware\n\nJika anda ingin me-listen sebuah Get event untuk melakukan sebuah action, anda bisa menggunakan routingCallback didalamnya.\n\n```dart\nGetMaterialApp(\n  routingCallback: (routing) {\n    if(routing.current == '/second'){\n      openAds();\n    }\n  }\n)\n```\n\nJika anda tidak menggunakan GetMaterialApp, anda bisa menggunakan API untuk mengaitkan Middleware observer secara manual.\n\n```dart\nvoid main() {\n  runApp(\n    MaterialApp(\n      onGenerateRoute: Router.generateRoute,\n      initialRoute: \"/\",\n      navigatorKey: Get.key,\n      navigatorObservers: [\n        GetObserver(MiddleWare.observer), // Disini\n      ],\n    ),\n  );\n}\n```\n\nMembuat sebuah kelas Middleware\n\n```dart\nclass MiddleWare {\n  static observer(Routing routing) {\n    /// Anda bisa me-listen sebuah route, snackbar, dialog, dan bottomsheet disetiap halaman.\n    /// Jika anda harus memasukkan salah satu dari 3 event tersebut secara langsung disini,\n    /// anda perlu menyebutkan bahwa event tersebut != (tidak sama dengan) apa yang mau anda lakukan.\n    if (routing.current == '/second' && !routing.isSnackbar) {\n      Get.snackbar(\"Halo\", \"Anda sedang berada di route kedua\");\n    } else if (routing.current =='/third'){\n      print('route terakhir dipanggil');\n    }\n  }\n}\n```\n\nSekarang, gunakan Get dalam kode anda:\n\n```dart\nclass First extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        leading: IconButton(\n          icon: Icon(Icons.add),\n          onPressed: () {\n            Get.snackbar(\"halo\", \"saya adalah snackbar modern\");\n          },\n        ),\n        title: Text('Halaman Pertama'),\n      ),\n      body: Center(\n        child: ElevatedButton(\n          child: Text('Pindah halaman'),\n          onPressed: () {\n            Get.toNamed(\"/second\");\n          },\n        ),\n      ),\n    );\n  }\n}\n\nclass Second extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        leading: IconButton(\n          icon: Icon(Icons.add),\n          onPressed: () {\n            Get.snackbar(\"halo\", \"saya adalah snackbar modern\");\n          },\n        ),\n        title: Text('Halaman kedua'),\n      ),\n      body: Center(\n        child: ElevatedButton(\n          child: Text('Pindah halaman'),\n          onPressed: () {\n            Get.toNamed(\"/third\");\n          },\n        ),\n      ),\n    );\n  }\n}\n\nclass Third extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: Text(\"Halaman ketiga\"),\n      ),\n      body: Center(\n        child: ElevatedButton(\n          onPressed: () {\n            Get.back();\n          },\n          child: Text('Kembali!'),\n        ),\n      ),\n    );\n  }\n}\n```\n\n## Navigasi tanpa konteks\n\n### SnackBar\n\nUntuk mendapatkan SnackBar sederhana dengan Flutter, anda harus mendapatkan konteks dari sebuah Scaffold, atau anda harus menggunakan GlobalKey yang dikaitkan pada Scaffold anda\n\n```dart\nfinal snackBar = SnackBar(\n  content: Text('Halo!'),\n  action: SnackBarAction(\n    label: 'Saya adalah snackbar tua yang jelek :(',\n    onPressed: () {}\n  ),\n);\n// Temukan Scaffold didalam widget tree dan gunakan itu\n// untuk menampilkan snackbar\nScaffold.of(context).showSnackBar(snackBar);\n```\n\nDengan Get:\n\n```dart\nGet.snackbar('Halo', 'Saya adalah snackbar modern');\n```\n\nDengan Get, yang anda butuhkan hanya memanggil Get.snackbar darimanapun di kode anda atau menyesuaikannya sesuka hati anda!\n\n```dart\nGet.snackbar(\n  \"Halo, saya snackbar milik Get!\", // judul\n  \"Sulit dipercaya! Saya menggunakan SnackBar tanpa konteks, tanpa boilerplate, tanpa Scaffold, ini benar benar keren!\", // pesan\n  icon: Icon(Icons.alarm),\n  shouldIconPulse: true,\n  onTap: () {},\n  barBlur: 20,\n  isDismissible: true,\n  duration: Duration(seconds: 3),\n);\n\n\n  ////////// SEMUA FITUR //////////\n  //     Color colorText,\n  //     Duration duration,\n  //     SnackPosition snackPosition,\n  //     Widget titleText,\n  //     Widget messageText,\n  //     bool instantInit,\n  //     Widget icon,\n  //     bool shouldIconPulse,\n  //     double maxWidth,\n  //     EdgeInsets margin,\n  //     EdgeInsets padding,\n  //     double borderRadius,\n  //     Color borderColor,\n  //     double borderWidth,\n  //     Color backgroundColor,\n  //     Color leftBarIndicatorColor,\n  //     List<BoxShadow> boxShadows,\n  //     Gradient backgroundGradient,\n  //     TextButton mainButton,\n  //     OnTap onTap,\n  //     bool isDismissible,\n  //     bool showProgressIndicator,\n  //     AnimationController progressIndicatorController,\n  //     Color progressIndicatorBackgroundColor,\n  //     Animation<Color> progressIndicatorValueColor,\n  //     SnackStyle snackStyle,\n  //     Curve forwardAnimationCurve,\n  //     Curve reverseAnimationCurve,\n  //     Duration animationDuration,\n  //     double barBlur,\n  //     double overlayBlur,\n  //     Color overlayColor,\n  //     Form userInputForm\n  ///////////////////////////////////\n```\n\nJika anda lebih menyukai snackbar tradisional, atau ingin menyesuaikannya sendiri dari awal, termasuk menambahkan hanya satu baris (Get.snackbar memanfaatkan title dan message yang diperlukan), anda bisa gunakan\n`Get.rawSnackbar();` yang akan menyediakan RAW API untuk Get.snackbar yang dibuat.\n\n### Dialog\n\nUntuk membuka dialog:\n\n```dart\nGet.dialog(YourDialogWidget());\n```\n\nUntuk membuka default dialog:\n\n```dart\nGet.defaultDialog(\n  onConfirm: () => print(\"Ok\"),\n  middleText: \"Dialog made in 3 lines of code\"\n);\n```\n\nAnda juga bisa menggunakan Get.generalDialog daripada showGeneralDialog.\n\nUntuk semua widget dialog di Flutter, termasuk cupertino, anda bisa menggunakan Get.overlayContext daripada context, dan membukanya darimanapun di kode anda.\nUntuk widget yang tidak menggunakan Overlay, anda bisa menggunakan Get.context.\nKedua konteks akan bekerja dalam 99% kasus untuk me-replace konteks dari UI anda, kecuali untuk kasus dimana inheritedWidget digunakan tanpa konteks navigasi.\n\n### BottomSheet\n\nGet.bottomSheet sama seperti showModalBottomSheet, tapi tidak membutuhkan konteks.\n\n```dart\nGet.bottomSheet(\n  Container(\n    child: Wrap(\n      children: <Widget>[\n        ListTile(\n          leading: Icon(Icons.music_note),\n          title: Text('Music'),\n          onTap: () {}\n        ),\n        ListTile(\n          leading: Icon(Icons.videocam),\n          title: Text('Video'),\n          onTap: () {},\n        ),\n      ],\n    ),\n  )\n);\n```\n\n## Navigasi Bersarang\n\nGet membuat navigasi bersarang milik Flutter menjadi lebih mudah.\nAnda tidak perlu konteks, dan anda akan menemukan stack navigasi melalui Id.\n\n- CATATAN: Membuat stack navigasi parallel bisa jadi berbahaya. Sebaiknya hindari penggunaan Navigasi Bersarang, atau gunakan dengan bijak. Jika proyek anda membutuhkannya, silahkan, tapi mohon di ingat bahwa menyimpan lebih dari satu navigation stack didalam memori mungkin bukan ide yang bagus untuk konsumsi RAM.\n\nLihat betapa sederhananya ini:\n\n```dart\nNavigator(\n  key: Get.nestedKey(1), // buat sebuah key menggunakan index\n  initialRoute: '/',\n  onGenerateRoute: (settings) {\n    if (settings.name == '/') {\n      return GetPageRoute(\n        page: () => Scaffold(\n          appBar: AppBar(\n            title: Text(\"Main\"),\n          ),\n          body: Center(\n            child: TextButton(\n              color: Colors.blue,\n              onPressed: () {\n                Get.toNamed('/second', id:1); // pindah ke halaman bersarang anda menggunakan index\n              },\n              child: Text(\"Go to second\"),\n            ),\n          ),\n        ),\n      );\n    } else if (settings.name == '/second') {\n      return GetPageRoute(\n        page: () => Center(\n          child: Scaffold(\n            appBar: AppBar(\n              title: Text(\"Main\"),\n            ),\n            body: Center(\n              child:  Text(\"second\")\n            ),\n          ),\n        ),\n      );\n    }\n  }\n),\n```\n"
  },
  {
    "path": "documentation/id_ID/state_management.md",
    "content": "- [State Management](#state-management)\n  - [Reactive State Manager](#reactive-state-manager)\n    - [Keuntungan](#keuntungan)\n    - [Performa Maksimum](#performa-maksimum)\n    - [Mendeklarasikan reactive variable](#mendeklarasikan-reactive-variable)\n      - [Memiliki sebuah reactive state itu, mudah](#memiliki-sebuah-reactive-state-itu-mudah)\n    - [Menggunakan value didalam view](#menggunakan-value-didalam-view)\n    - [Kondisi untuk rebuild](#kondisi-untuk-rebuild)\n    - [Dimana .obs bisa digunakan](#dimana-obs-bisa-digunakan)\n    - [Catatan mengenai List](#catatan-mengenai-list)\n    - [Mengapa harus menggunakan .value](#mengapa-harus-menggunakan-value)\n    - [Obx()](#obx)\n    - [Worker](#worker)\n  - [Simple State Manager](#simple-state-manager)\n    - [Keuntungan](#keuntungan-1)\n    - [Penggunaan](#penggunaan)\n    - [Bagaimana Get meng-handle controller](#bagaimana-get-meng-handle-controller)\n    - [Anda tidak membutuhkan StatefulWidget lagi](#anda-tidak-membutuhkan-statefulwidget-lagi)\n    - [Mengapa GetX ada](#mengapa-getx-ada)\n    - [Cara lain dalam menggunakannya](#cara-lain-dalam-menggunakannya)\n    - [Unique ID](#unique-id)\n  - [Mencampur 2 state manager](#mencampur-2-state-manager)\n  - [GetBuilder vs GetX vs Obx vs MixinBuilder](#getbuilder-vs-getx-vs-obx-vs-mixinbuilder)\n\n# State Management\n\nGetX tidak menggunakan Stream atau ChangeNotifier seperti state manager lainnya. Mengapa? Selain membangun aplikasi untuk Android, iOS, Web, Linux, MacOS, dan Linux, dengan GEtX anda bisa membangun aplikasi server dengan sintaks yang sama seperti Flutter/GetX. Untuk meningkatkan waktu response dan mengurangi konsumsi RAM, kami menciptakan GetValue dan GetStream, yang memiliki solusi latensi rendah yang dapat memberikan performa yang banyak dengan biaya operasi yang rendah. Kami menggunakan ini sebagai dasar untuk membangun semua resource kami, termasuk state management.\n\n- _Kompleksitas_: Beberapa state manager yang ada bisa dibilang kompleks dan memiliki banyak boilerplate. Dengan GetX anda tidak perlu mendefinisikan sebuah kelas untuk setiap event, kode yang dibuat pun bersih dan jelas, dan anda bisa melakukan banyak hal dengan menulis lebih sedikit kode. Banyak orang menyerah menggunakan Flutter karena hal ini, dan pada akhirnya mereka mendapatkan solusi yang sangat sederhana untuk me-manage state.\n\n- _Tidak ada code generator_: Anda menghabiskan separuh waktu development anda menuliskan logic dari aplikasi yang anda buat. Beberapa state manager bergantung pada code generator yang menghasilkan kode dengan keterbacaan yang rendah. Mengubah sebuah variabel dan perlu menjalankan run build_runner bisa jadi tidak produktif, dan terkadang waktu menunggu setelah sebuah flutter clean akan lama, dan anda harus meminum banyak kopi untuk itu.\n\nDengan GetX semuanya reactive, dan tidak bergantung pada code generator, meningkatkan produktifitas di segala aspek development anda.\n\n- _Tidak bergantung pada konteks_: Anda mungkin pernah diharuskan untuk mengirim konteks dari view ke sebuah controller, membuat keterkaitan yang tinggi terhadap View yang anda buat dengan Business Logic. Anda mungkin pernah diharuskan untuk menggunakan dependensi untuk suatu tempat yang tidak memiliki konteks, dan harus mengirim koteks tersebut melalui berbagai macam kelas dan fungsi. Hal ini tidak ada di GetX. Anda memiliki akses terhadap controller anda dari controller yang anda buat tanpa konteks apapun. Anda tidak perlu mengirim konteks melalui parameter untuk hal yang secara harfiah tidak diperlukan.\n\n- _Kontrol granular_: Kebanyakan state manager didasari oleh ChangeNotifier. ChangeNotifier akan memberi tahu semua widget yang bergantung padanya ketika notifyListener dipanggil. Jika anda memiliki 40 widget didalam satu halaman, yang mana memiliki variabel dari kelas ChangeNotifier anda, ketika anda memperbarui satu dari mereka, semuanya akan me-rebuild.\nDengan GetX, bahkan nested widget pun dihargai. Jika anda memiliki Obx membungkus ListView anda, dan yang lain membungkus sebuah checkbox didalam ListView tersebut, ketika nilai dari CheckBox berubah, hanya CheckBox tersebut yang akan diperbarui, ketika nilai dari List yang berubah, hanya ListView yang akan diperbarui.\n\n- _Hanya merekonstruksi jika variabelnya BENAR-BENAR berubah_: GetX memiliki kontrol flow, yang artinya jika anda menampilkan Text dengan 'Paola', jika anda mengubah variabel observabel menjadi 'Paola' lagi, widget tidak akan direkonstruksi. Ini karena GetX tahu bahwa 'Paola' sudah ditampilkan di Text, dan tidak akan melakukan rekonstruksi yang tidak diperlukan.\nKebanyakan state manager (jika tidak semuanya) saat ini akan merebuild tampilan.\n\n## Reactive State Manager\n\nReactive programming bisa meng-alienasi banya orang karena katanya, sulit dimengerti. GetX mengubah reactive programming menjadi sesuatu yang cukup sederhana:\n\n- Anda tidak perlu membuat StreamController.\n- Anda tidak perlu membuat StreamBuilder untuk setiap variabel.\n- Anda tidak perlu membuat kelas untuk setiap state.\n- Anda tidak perlu membuat get untuk sebuah value awal (initial value).\n- Anda tidak perlu menggunakan generator kode.\n\nReactive programming dengan Get semudah menggunakan setState.\n\nBayangkan anda memiliki variabel nama, dan setiap kali anda mengubahnya, semua widget yang menggunakannya akan berubah secara otomatis.\n\nIni variabel count anda:\n\n```dart\nvar name = 'Jonatas Borges';\n```\n\nUntuk membuatnya \"observable\", anda hanya perlu menambahkan \".obs\" di belakangnya:\n\n```dart\nvar name = 'Jonatas Borges'.obs;\n```\n\nSelesai! _Sesederhana_ itu.\n\nMulai saat ini, kami akan mereferensikan variabel reactive-\".obs\"(ervables) sebagai _Rx_.\n\nApa yang kami lakukan dibalik layar? Kami membuat sebuah `Stream` dari `String`, mengajukan value awal `\"Jonatas Borges\"`, kami memberi tahu semua widget yang menggunakan `\"Jonatas Borges\"` bahwa mereka sekarang \"milik\" variabel tersebut, dan ketika nilai _Rx_ berubah, mereka harus mengubahnya juga.\n\nIni adalah **keajaiban dari GetX**, terima kasih untuk kemampuan Dart.\n\nTapi, seperti yang kita ketahui, sebuah `Widget` hanya bisa dirubah jika lokasinya berada didalam sebuah fungsi, karena kelas static tidak memiliki kemampuan untuk \"otomatis berubah\"\n\nAnda akan harus untuk membuat `StreamBuilder`, berlangganan ke variabel tersebut untuk \"mendengar\" perubahan, dan membuat sebuah \"cascade\" dari nested `StreamBuilder` jika anda ingin mengubah beberapa variabel didalam scope, benar kan?\n\nTidak, anda tidak perlu `StreamBuilder`, tapi anda benar tentang kelas static.\n\nYah, didalam view, kita biasanya memiliki banyak boilerplate ketika kita ingin mengubah sebuah Widget secara spesifik, itu adalah cara Flutter.\nDengan **GetX** anda juga bisa melupakan tentang boilerplate code ini.\n\n`StreamBuilder( … )`? `initialValue: …`? `builder: …`? Tidak, anda hanya perlu meletakkan variabel kedalam Widget `Obx()`.\n\n```dart\nObx (() => Text (controller.name));\n```\n\n_Apa yang perlu anda ingat?_  Hanya `Obx(() =>`.\n\nAnda hanya mengirim Widget itu melalui sebuah arrow-function kedalam sebuah `Obx()` (sebuah \"Pengamat\" daripada _Rx_).\n\n`Obx` cukup pintar, dan akan selalu berubah jika value dari `controller.name` berubah.\n\nJika `name` nilainya `\"John\"`, dan anda mengubahnya ke `\"John\"` (`name.value = \"John\"`), karena `value` nya sama seperti sebelumnya, tidak akan ada perubahan apapun di layar, dan `Obex`, untuk menghemat resource, akan secara sederhana mengabaikan value baru yang diberikan dan tidak akan merebuild Widget. **Keren kan?**\n\n> Lalu, bagaimana jika Saya memiliki 5 variabel _Rx_ (observable) didalam `Obx`?\n\nDia hanya akan memperbarui ketika **semuanya** berubah.\n\n> Dan jika Saya memiliki 30 variabel didalam sebuah kelas, ketika Saya memperbarui salah satu dari mereka, apakah akan memperbarui **semua** variabel didalam kelas tersebut?\n\nTidak, hanya **Widget tertentu* yang menggunakan variabel _Rx_ tersebut.\n\nJadi, **GetX** hanya memperbarui tampilan, ketika nilai dari variabel _Rx_ berubah.\n\n```dart\nfinal isOpen = false.obs;\n\n// TIDAK AKAN terjadi apa apa... nilainya sama.\nvoid onButtonTap() => isOpen.value=false;\n```\n\n### Keuntungan\n\n**GetX()** membantu anda ketika anda membutuhkan kontrol **granular** atas apa yang sedang diperbarui.\n\nJika anda tidak membutuhkan `unique ID`, karena semua variabel anda akan di modifikasi ketika anda melakukan sebuah aksi, maka gunakanlah `GetBuilder`,\nkarena dia adalah Simple State Updater (didalam block, seperti `setState()`), dibuat hanya dengan beberapa baris kode.\nIni dibuat sederhana, untuk mendapatkan pengaruh CPU yang sedikit, dan hanya untuk memenuhi satu kebutuhan (sebuah _State_ rebuild) dan menggunakan resource se-minimal mungkin.\n\nJika anda perlu sebuah State Manager yang **powerful**, anda tidak akan salah dengan **GetX**.\n\nIni tidak bekerja dengan variabel, melainkan __aliran (flows)__, semuanya adalah `Streams` dibalik layar.\nAnda bisa menggunakan _rxDart_ bersamaan dengannya, karena semuanya adalah `Streams`,\nanda bisa me-listen sebuah `event` dari setiap \"variabel _Rx_\",\nkarena semua didalamnya adalah `Streams`.\n\nIni secara harfiah adalah cara yang digunakan _BLoC_, lebih mudah dari _MobX_, dan tanpa code generator atau decoration.\nAnda bisa mengubah **apapun** menjadi sebuah _\"Observable\"_ hanya dengan `.obs`.\n\n### Performa Maksimum\n\nSelain memiliki sebuah algoritma pintar untuk minimal rebuild, **GetX** menggunakan pembanding\nuntuk memastikan State nya berubah.\n\nJika anda mengalami error di aplikasi anda, dan mengirim sebuah duplikat terhadap perubahan State,\n**GetX** akan memastikan aplikasi anda tidak crash.\n\nDengan **GetX**, State hanya berubah ketika `value` nya berubah.\nItu adalah perbedaan utama diantara **GetX**, dan dengan menggunakan _`computed` dari MobX_.\nKetika menggabungkan kedua __observable__, dan salah satunya berubah; listener dari _observable_ itu akan berubah juga.\n\nDengan **GetX**, jika anda menggabungkan dua variabel, `GetX()` (mirip seperti `Observer()`) hanya akan merebuild jika State nya benar-benar berubah.\n\n### Mendeklarasikan reactive variable\n\nAnda memiliki 3 cara untuk mengubah variabel menjadi sebuah \"observable\".\n\n1 - Yang pertama adalah dengan menggunakan **`Rx{Type}`**.\n\n```dart\n// value awal direkomendasikan, tetapi tidak wajib\nfinal name = RxString('');\nfinal isLogged = RxBool(false);\nfinal count = RxInt(0);\nfinal balance = RxDouble(0.0);\nfinal items = RxList<String>([]);\nfinal myMap = RxMap<String, int>({});\n```\n\n2 - Yang kedua adalah dengan menggunakan **`Rx`** dan Darts Generics, `Rx<Type>`\n\n```dart\nfinal name = Rx<String>('');\nfinal isLogged = Rx<Bool>(false);\nfinal count = Rx<Int>(0);\nfinal balance = Rx<Double>(0.0);\nfinal number = Rx<Num>(0)\nfinal items = Rx<List<String>>([]);\nfinal myMap = Rx<Map<String, int>>({});\n\n// Kelas Kustom - ini bisa jadi kelas apapun, secara harfiah\nfinal user = Rx<User>();\n```\n\n3 - Yang ketiga, cara yang lebih praktis, mudah dan lebih disukai, cukup tambahkan **`.obs`** sebagai properti dari `value` anda:\n\n```dart\nfinal name = ''.obs;\nfinal isLogged = false.obs;\nfinal count = 0.obs;\nfinal balance = 0.0.obs;\nfinal number = 0.obs;\nfinal items = <String>[].obs;\nfinal myMap = <String, int>{}.obs;\n\n// Kelas Kustom - ini bisa jadi kelas apapun, secara harfiah\nfinal user = User().obs;\n```\n\n#### Memiliki sebuah reactive state itu, mudah\n\nSeperti yang kita ketahui, _Dart_ saat ini sedang mempersiapkan ke _null safety_.\nSebagai persiapan, mulai dari sekarang, anda harus selalu memulai variabel _Rx_ anda dengan sebuah **initial value** (nilai awal).\n\n> Mengubah sebuah variabel menjadi sebuah _observable_ + _initial value_ dengan **GetX** adalah cara yang paling sederhana, dan sangat praktis.\n\nAnda hanya cukup menambahkan sebuah \"`.obs`\" di akhir variabel anda, dan **selesai**, anda telah membuatnya observable,\ndan untuk `.value` nya, yah, _initial value_ yang anda berikan.\n\n### Menggunakan value didalam view\n\n```dart\n// file controller\nfinal count1 = 0.obs;\nfinal count2 = 0.obs;\nint get sum => count1.value + count2.value;\n```\n\n```dart\n// file view\nGetX<Controller>(\n  builder: (controller) {\n    print(\"count 1 rebuild\");\n    return Text('${controller.count1.value}');\n  },\n),\nGetX<Controller>(\n  builder: (controller) {\n    print(\"count 2 rebuild\");\n    return Text('${controller.count2.value}');\n  },\n),\nGetX<Controller>(\n  builder: (controller) {\n    print(\"count 3 rebuild\");\n    return Text('${controller.sum}');\n  },\n),\n```\n\nJika kita meng-increment `count1.value++`, ini akan mencetak:\n\n- `count 1 rebuild`\n- `count 3 rebuild`\n\nkarena `count1` memiliki nilai `1`, dan `1 + 0 = 1`, mengubah nilai dari getter `sum`.\n\nJika kita mengubah `count2.value++`, ini akan mencetak:\n\n- `count 2 rebuild`\n- `count 3 rebuild`\n\nkarena `count2.value` berubah, dan hasil dari `sum` sekarang adalah `2`.\n\n- CATATAN: Secara default, event yang paling pertama akan merebuild widget, meskipun `value` nya sama.\n  perilaku ini hadir karena variabel Boolean.\n\nBayangkan anda melakukan ini:\n\n```dart\nvar isLogged = false.obs;\n```\n\nDan kemudian, anda melakukan pengecekan apakah user \"sudah login\" untuk men-trigger sebuah event didalam `ever`.\n\n```dart\n@override\nonInit(){\n  ever(isLogged, fireRoute);\n  isLogged.value = await Preferences.hasToken();\n}\n\nfireRoute(logged) {\n  if (logged) {\n   Get.off(Home());\n  } else {\n   Get.off(Login());\n  }\n}\n```\n\njika `hasToken` nilainya `false`, tidak akan terjadi apa apa kepada `isLogged`, jadi `ever()` tidak akan dipanggil.\nUntuk menghindari jenis perilaku ini, perubahan awal terhadap sebuah _observable_ harus selalu men-trigger sebuah event,\nbahkan ketika mereka memiliki `.value` yang sama.\n\nAnda bisa menghapus perilaku ini jika anda mau, menggunakan:\n`isLogged.firstRebuild = false;`\n\n### Kondisi untuk rebuild\n\nSelain itu, Get menyediakan state kontrol yang telah dipoles. Anda bisa mengkondisikan sebuah event (seperti menambahkan sebuah object kedalam list), dalam suatu kondisi.\n\n```dart\n// Parameter pertama: kondisi, harus me-return true atau false\n// Parameter kedua: nilai baru yang akan dimasukkan jika kondisinya true\nlist.addIf(item < limit, item);\n```\n\nTanpa decoration, tanpa code generator, tanpa komplikasi :smile:\n\nAnda tahu counter app milik Flutter? Controller anda mungkin terlihat seperti ini:\n\n```dart\nclass CountController extends GetxController {\n  final count = 0.obs;\n}\n```\n\nHanya dengan:\n\n```dart\ncontroller.count.value++\n```\n\nAnda bisa memperbarui variabel counter di UI anda, tidak perduli dimanapun itu diletakkan.\n\n### Dimana .obs bisa digunakan\n\nAnda bisa mengubah apapun dengan obs. Berikut adalah dua cara untuk melakukannya:\n\n* Anda bisa mengkonversi value kelas anda menjadi obs\n\n```dart\nclass RxUser {\n  final name = \"Camila\".obs;\n  final age = 18.obs;\n}\n```\n\n* atau anda bisa mengkonversi seluruh kelasnya menjadi observable\n\n```dart\nclass User {\n  User({String name, int age});\n  var name;\n  var age;\n}\n\n// saat menginstansiasi:\nfinal user = User(name: \"Camila\", age: 18).obs;\n```\n\n### Catatan mengenai List\n\nList, dia observable secara menyeluruh, termasuk objek didalamnya.\nDengan itu, jika anda menambahkan value kedalam list, dia akan secara otomatis merebuild widget yang menggunakannya.\n\nAnda juga tidak perlu menggunakan \".value\" ketika mengakses list, API dart yang luar biasa mengizinkan kita untuk menghapusnya.\nSayangnya, tipe data primitif seperti String dan int tidak bisa di extend, membuat penggunaan .value menjadi suatu hal yang wajib, tapi itu bukan masalah jika anda bekerja menggunakan getter dan setter untuk mereka.\n\n```dart\n// Didalam Controller\nfinal String title = 'User Info:'.obs\nfinal list = List<User>().obs;\n\n// Didalam View\nText(controller.title.value), // String harus memiliki .value didepannya\nListView.builder (\n  itemCount: controller.list.length // list tidak perlu itu\n)\n```\n\nKetika anda membuat kelas anda sendiri observable, ada berbagai cara untuk memperbaruinya:\n\n```dart\n// didalam file model\n// kita akan membuat seluruh kelas menjadi observable daripada\n// mengimplementasikannya pada masing-masing atribut.\nclass User() {\n  User({this.name = '', this.age = 0});\n  String name;\n  int age;\n}\n\n\n// didalam file controller\nfinal user = User().obs;\n// ketika anda perlu mengupdate variabel user:\nuser.update( (user) { // parameter ini adalah kelas itu sendiri yang akan anda update\n  user.name = 'Jonny';\n  user.age = 18;\n});\n// cara alternatif untuk melakukannya:\nuser(User(name: 'João', age: 35));\n\n// didalam view:\nObx(()=> Text(\"Name ${user.value.name}: Age: ${user.value.age}\"))\n// anda juga bisa mengakses nilai model tanpa .value:\nuser().name; // perhatikan bahwa yang digunakan adalah variabel user, bukan kelasnya (variabel memiliki \"u\" kecil)\n```\n\nAnda tidak perlu bekerja dengan sets jika anda tidak mau. Anda bisa menggunakan API \"assign\" dan \"assignAll\".\nAPI \"assign\" akan membersihkan list anda, dan memasukkan satu objek sebagai permulaan.\nAPI \"assignAll\" akan membersihkan list yang sudah ada dan menambahkan objek iterable yang anda inject kedalamnya.\n\n### Mengapa harus menggunakan .value\n\nKami bisa saja menghapus kebijakan untuk menggunakan 'value' pada `String` dan `int` dengan decoration sederhana dan code generator, tapi tujuan dari library ini adalah untuk menghindari dependensi eksternal. Kami ingin menawarkan sebuah environment yang siap untuk programming, melibatkan hal-hal penting (route, dependency, dan state management), dengan cara yang sederhana, ringan, dan cepat, tanpa membutuhkan package dari luar.\n\nAnda bisa secara harfial menambahkan 3 huruf ke pubspec anda dan sebuah titik dua dan mulai membuat sebuah program. Semua solusi sudah termasuk secara default, mulai dari route management, hingga state management, menargetkan kemudahan, produktifitas dan performa.\n\nBerat total dari library ini kurang dari satu state manager, meskipun ini adalah solusi komplit, dan inilah yang harus anda pahami.\n\nJika anda terganggu dengan `.value`, dan menyukai code generator, MobX adalah alternatif yang baik, dan anda bisa menggunakannya bersamaan dengan Get. Untuk kalian yang ingin menambahkan satu dependensi di pubspec dan mulai membuat sebuah program tanpa mengkhawatirkan versi dari sebuah package tidak kompatibel dengan yang lain, atau sebuah error dari perbaruan state datang dari state manager atau dependensi, atau semacamnya, dan tidak mau khawatir tentang ketersediaan controller, ataupun secara harfiah \"hanya ingin membuat program\", get sudah sangat sempurna.\n\nJika anda merasa tidak masalah dengan code generator MobX, atau tidak masalah dengan boilerplate dari BLoC, anda bisa menggunakan Get untuk route, dan lupakan bahwa dia memiliki state manager. Get SEM dan RSM lahir karena kebutuhan, perusahaan saya memiliki proyek dengan lebih dari 90 controller, dan code generator sederhananya memakan waktu 30 menit untuk menyelesaikan tugasnya setelah Flutter Clean di komputer yang secara masuk akal bagus, jika proyek anda memiliki 5, 10, hingga 15 controller, state manager apapun akan mensuplai anda dengan baik. Jika anda memiliki proyek yang secara absurd berskala besar, dan code generator adalah masalah untuk anda, maka anggap ini sebagai hadiah.\n\nJelas, jika seseorang ingin berkontribusi terhadap proyek dan membuat sebuah code generator, atau sejenisnya, Saya akan tautkan kedalam readme ini sebagai alternatif, kebutuhan saya bukan kebutuhan untuk semua developer, namun untuk saat ini Saya mengatakan, sudah ada solusi yang baik diluar sana yang sudah melakukan hal itu, seperti MobX.\n\n### Obx()\n\nMemberi tipe di Get saat menggunakan Binding tidak diperlukan. Anda bisa menggunakan widget Obx daripada GetX yang mana hanya menerima fungsi anonim yang membuat sebuah widget.\nJelas, jika anda tidak menggunakan sebuah tipe, anda harus memiliki sebuah instance dari controller anda untuk menggunakan variabel didalamnya, atau gunakan `Get.find<Controller>()` .value atau Controller.to.value untuk mengambil value.\n\n### Worker\n\nWorker akan membantu anda, men-trigger callback spesifik ketika sebuah event terjadi.\n\n```dart\n/// Terpangil setiap kali `count1` berubah.\never(count1, (_) => print(\"$_ telah dirubah\"));\n\n/// Terpanggil hanya pada saat pertama kali variabel $_ dirubah.\nonce(count1, (_) => print(\"$_ telah dirubah sekali\"));\n\n/// Anti DDos - Terpangil setiap kali the user berhenti mengetik setelah 1 detik, contoh:\ndebounce(count1, (_) => print(\"debouce$_\"), time: Duration(seconds: 1));\n\n/// Abaikan semua perubahan selama 1 detik.\ninterval(count1, (_) => print(\"interval $_\"), time: Duration(seconds: 1));\n```\n\nSemua worker (kecuali `debounce`) memiliki sebuah `condition` named parameter, yang bisa jadi sebuah `bool` atau sebuah callback yang mereturn `bool`\n`condition` ini terdefinisikan ketika fungsi `callback` di eksekusi.\n\nSemua worker mereturn sebuah instance `Worker`, yang bisa anda gunakan untuk membatalkan worker tersebut (melalui `dispose()`).\n\n- **`ever`**\\\nterpanggil setiap kali variabel _Rx_ meng-emit value baru.\n\n- **`everAll`**\\\nMirip seperti `ever`, tapi menerima `List` sebagai nilai _Rx_, terpanggil setiap kali variabel berubah.\n\n- **`once`**\\\nTerpanggil hanya sekali pada saat pertama kali variabel berubah.\n\n- **`debounce`**\\\n'debounce' sangat berguna pada fungsi pencarian, dimana anda hanya ingin API dipanggil ketika user selesai mengetik. Jika user mengetik \"Jonny\", anda akan pendapatkan 5 pencarian di API, dengan huruf J, o, n, n, dan y. Dengan Get, ini tidak terjadi lagi, karena anda memiliki sebuah \"debounce\" worker, yang akan men-trigger pada akhir pengetikan.\n\n- **`interval`**\\\nberbeda dengan debounce. untuk debounce, jika user melakukan 1000 perubahan terhadap sebuah variabel dalam 1 detik, dia akan mengirim hanya yang terakhir setelah waktu yang ditetapkan (defaultnya adalah 800 milisekon).\n\\\n\\\nInterval bekerja sebaliknya, dia akan mengabaikan semua interaksi user dalam rentang waktu yang ditentukan. Jika anda mengirim event dalam 1 menit, 1000 per detik, debounce akan mengirimkan anda yang terakhir, ketika user berhenti melakukan spam terhadap event. Interval akan mengantar event setiap detik, dan jika diatur menjadi 3 detik, dia akan mengirimkan 20 event setiap menit.\n\\\n\\\nIni direkomendasikan untuk menghindari penyalahgunaan, dalam fungsi dimana user bisa secara cepat melakukan klik pada sesuatu untuk mendapatkan sebuah keuntungan (bayangkan jika user bisa mendapat koin dengan meng-klik pada sesuatu, jika dia mengklik 300 kali dalam 1 menit, dia akan mendapatkan 300 koin, menggunakan interval, anda bisa mengatur jangka waktu selama 3 detik, dan meskipun user meng-klik sebanyak 300 kali atau ribuan kali, maksimum koin yang bisa dia dapatkan dalam 1 menit akan selalu 20 koin, bahkan ketika dia meng-klik 1 juta kali sekalipun)\n\\\n\\\nDebounce cocok sebagai anti-DDos, untuk fungsi seperti search dimana setiap perubahan terhadap onChange akan mengirim sebuah query ke API anda. Debounce akan menunggu user berhenti mengetik nama, untuk membuat sebuah request. Jika ini digunakan pada skenario koin diatas, user hanya akan mendapatkan 1 koin, karena hanya akan di eksekusi ketika user memberi jeda terhadap waktu yang ditentukan.\n\n- CATATAN: Worker harus selalu digunakan ketika memulai sebuah Controller atau Class, jadi dia harus selalu diletakkan didalam onInit (direkomendasikan), Class constructor, atau initState dari StatefulWidget (praktik ini tidak direkomendasikan dalam kebanyakan kasus, dan tidak akan ada side effect).\n\n## Simple State Manager\n\nGet memiliki state manager yang sangat ringan dan mudah, dan tidak menggunakan ChangeNotifier, yang akan memenuhi kebutuhan khususnya untuk mereka yang baru di Flutter, dan tidak akan membuat masalah untuk aplikasi besar.\n\nGetBuilder membidik dengan tepat pada state control multipel. Bayangkan anda menambahkan 30 produk kedalam sebuah keranjang belanja, anda meng-klik \"delete\" pada salah satu produk tersebut, di waktu yang sama, list, harga, dan badge diperbarui ke angka yang lebih kecil. Pendekatan ini membuat GetBuilder mematikan, karena mengelompokkan state dan mengubah semuanya secara bersamaan dalam satu waktu tanpa \"computational logic\" untuk itu. Getbuilder dibuat dengan mempertimbangkan situasi seperti ini, untuk perubahan state \"ephemeral\", anda bisa menggunakan setState dan anda tidak membutuhkan sebuah state manager untuk itu.\n\nDengan begitu, jika anda menginginkan controller yang bekerja secara individu, anda bisa mengajukan ID untuknya, atau gunakan GetX. Semuanya terserah anda, mengingat bahwa semakin banyak \"individual\" widget yang anda miliki, performa dari GetX akan semakin terlihat, sementara performa dari GetBuilder harusnya lebih superior, ketika terjadi perubahan state secara multipel.\n\n### Keuntungan\n\n1. Hanya memperbarui widget yang diperlukan\n\n2. Tidak menggunakan changeNotifier, ini adalah state manager yang menggunakan memori lebih kecil (mendekati 0mb).\n\n3. Lupakan StatefulWidget! Dengan Get, anda tidak akan pernah membutuhkannya. Dengan state manager lain, anda mungkin harus menggunakan StatefulWidget untuk mendapatkan sebuah instance milik anda dari Provider, BLoC, MobX Controller, dsb. Tapi pernahkah anda berhenti untuk berfikir bahwa appBar, scaffold, dan kebanyakan widget anda itu stateless? Lalu mengapa menyimpan state dari seluruh kelas, jika anda hanya bisa menyimpan state dari Widget yang stateful? Get menyelesaikan masalah itu, juga. Buat kelas Stateless, buat semuanya stateless. Jika anda butuh update pada satu komponen, bungkus komponen itu dengan GetBuilder, dan state-nya akan di-maintain.\n\n4. Organisir proyek anda secara nyata! Controller tidak seharusnya ada di UI, letakkan TextEditingController anda, atau controller apapun didalam kelas Controller anda.\n\n5. Apakah anda perlu men-trigger sebuah event untuk widget segera setelah dirender? GetBuilder memiliki properti \"initState\", sama seperti StatefulWidget, dan anda akan bisa memanggil event dari controller anda, langsung dari sana, tidak ada lagi event diletakkan didalam initState anda.\n\n6. Apakah anda perlu men-trigger sebuah action seperti menutup stream, timer, dan semacamnya? GetBuilder juga memiliki properti dispose, dimana anda bisa memanggil event segera setelah widget dihancurkan.\n\n7. Gunakan stream hanya jika dibutuhkan. Anda bisa menggunakan StreamController didalam controller anda secara normal, dan menggunakan StreamBuilder juga secara normal, namun perlu di ingat, sebuah stream cukup memakan memori, reactive programming itu indah, namun anda tidak boleh menyalahgunakannya. 30 stream terbuka secara simultan bisa lebih buruk daripada changeNotifier (dan changeNotifier itu sangat buruk).\n\n8. Perbarui widget tanpa menghabiskan RAM untuk itu. Get menyimpan hanya creator ID milik GetBuilder, dan memperbarui GetBuilder tersebut ketika diperlukan. Konsumsi memori dari get ID storage sangat rendah bahkan untuk ribuan GetBuilder sekalipun. Ketika anda membuat GetBuilder baru, anda sebenarnya berbagi state dari GetBuilder yang memiliki creator ID. State baru tidak dibuat untuk setiap GetBuilder, yang mana menghemat SANGAT BANYAK RAM untuk aplikasi berskala besar. Pada dasarnya, aplikasi anda akan Stateless secara menyeluruh, dan semakin sedikit Widget yang akan Stateful (didalam GetBuilder) akan memiliki satu state, dan oleh karena itu, mengupdate salah satu dari mereka akan mengupdate semuanya. State nya hanya satu.\n\n9. Get maha tahu, dan dalam kebanyakan kasus, dia mengetahui dengan tepat kapan harus menghapus sebuah controller dari memori. Anda tidak perlu khawatir tentang kapan harus men-dispose sebuah controller, Get tahu waktu terbaik untuk melakukannya.\n\n### Penggunaan\n\n```dart\n// Buat kelas controller dan extends GetxController\nclass Controller extends GetxController {\n  int counter = 0;\n  void increment() {\n    counter++;\n    update(); // gunakan update() untuk mengupdate variabel counter di UI ketika increment dipanggil\n  }\n}\n// Pada Stateless/Stateful widget anda, gunakan GetBuilder untuk mengupdate Text ketika increment dipanggil\nGetBuilder<Controller>(\n  init: Controller(), // INISIALISASIKAN CONTROLLER HANYA UNTUK PERTAMA KALI\n  builder: (_) => Text(\n    '${_.counter}',\n  ),\n)\n// Inisialisasi controller anda hanya untuk pertama kali. Kedua kalinya anda menggunakan ReBuilder untuk controller yang sama, dan jangan gunakan itu lagi. Controller anda akan secara otomatis dihapus dari memori segera setelah widget yang ditandai sebagai 'init' di-deploy. Anda tidak perlu khawatir tentang itu, Get akan melakukannya secara otomatis, cukup pastikan anda tidak memulai controller yang sama dua kali.\n```\n\n**Selesai!**\n\n- Anda sudah mempelajari bagaimana caranya memanage state menggunakan Get.\n\n- Catatan: Anda mungkin menginginkan organisasi yang lebih besar, dan tidak menggunakan properti init. Untuk itu, anda bisa membuat kelas dan meng-extends kelas Bindings, dan didalamnya, sebutkan controller yang akan dibuat untuk route tersebut. Controller tidak akan dibuat pada waktu itu, sebaliknya, ini hanyalah sebuah statement, jadi pada saat pertama kali anda menggunakan sebuah Controller, Get akan tahu dimana harus mencarinya. Get akan melakukan lazyload, dan akan melanjutkan untuk men-dispose controller yang tidak lagi digunakan. Lihat contoh di pub.dev untuk melihat bagaimana cara kerjanya.\n\nJika anda bernavigasi ke banyak route dan membutuhkan data dari controller yang sebelumnya anda gunakan, anda hanya perlu menggunakan GetBuilder lagi (tanpa init):\n\n```dart\nclass OtherClass extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      body: Center(\n        child: GetBuilder<Controller>(\n          builder: (s) => Text('${s.counter}'),\n        ),\n      ),\n    );\n  }\n\n```\n\nJika anda perlu menggunakan controller anda di banyak tempat, dan diluar dari GetBuilder, cukup buat getter didalam controller anda dan anda akan mendapatkannya dengan mudah (atau gunakan `Get.find<Controller>()`)\n\n```dart\nclass Controller extends GetxController {\n\n  /// Anda tidak membutuhkan itu. Saya menyarankan menggunakannya hanya untuk kemudahan sintaks.\n  /// dengan static method: Controller.to.increment();\n  /// tanpa static method: Get.find<Controller>().increment();\n  /// Tidak ada perbedaan dari segi performa, atau efek samping apapun dalam menggunakan kedua sintaks diatas. Yang berbeda hanyalah yang satu tidak memerlukan type, dan yang satu lagi akan di autocomplete oleh IDE.\n  static Controller get to => Get.find(); // Tambahkan baris ini\n\n  int counter = 0;\n  void increment() {\n    counter++;\n    update();\n  }\n}\n```\n\nDan anda bisa mengakses controller secara langsung, dengan cara itu:\n\n```dart\nFloatingActionButton(\n  onPressed: () {\n    Controller.to.increment(),\n  } // Ini luar biasa simpel!\n  child: Text(\"${Controller.to.counter}\"),\n),\n```\n\nKetika anda menekan FloatingActionButton, semua widget yang me-listen variabel 'counter' akan diupdate secara otomatis.\n\n### Bagaimana Get meng-handle controller\n\nAnggaplah kita memiliki ini:\n\n`Class A => Class B (memiliki controller X) => Class C (memiliki controller X)`\n\nDi kelas A, controller belum ada di memori, karena anda belum menggunakannya (Get itu lazyload). Di kelas B anda menggunakan controller tersebut, dan controller itu masuk kedalam memori. Di kelas C, anda menggunakan controller yang sama seperti di kelas B, Get akan berbagi state dari controller B dengan controller C, dan controller yang sama akan tetap ada di memori.\n\nJika anda menutup screen C dan screen B, Get akan secara otomatis menghapus controller X dari memori dan membebaskan resource, karena kelas A tidak menggunakan controller. Jika anda bernavigasi ke kelas B lagi, controller X akan masuk ke memori lagi, jika daripada menuju ke kelas C, anda kembali ke kelas A lagi, Get akan menghapus controller dari memori dengan cara yang sama. Jika kelas C tidak menggunakan controller, dan anda mengeluarkan kelas B dari memori, tidak ada kelas yang menggunakan controller X dan demikian pula kelas itu akan dibuang.\n\nSatu-satunya exception yang bisa mengacau dengan Get, adalah jika anda menghapus B dari route secara tidak sengaja, dan mencoba menggunakan controller di C. Dalam kasus ini, creator ID dari controller yang ada di B terhapus, dan Get diprogram untuk menghapusnya dari memori untuk setiap controller yang tidak memiliki creator ID. Jika anda berniat melakukan ini, tambahkan flag \"autoRemove: false\" ke GetBuilder di kelas B dan gunakan \"adoptID = true;\" di GetBuilder pada kelas C.\n\n### Anda tidak membutuhkan StatefulWidget lagi\n\nMenggunakan StatefulWidget berarti menyimpan sebuah state dari seluruh layar secara tidak perlu, meski karena anda perlu untuk merebuild sebuah widget secara minimal, anda akan menyematkannya kedalam Consumer/Observer/BlocProvider/GetBuilder/GetX/Obx, yang mana akan menjadi StatfulWidget yang lain.\n\nStatefulWidget adalah sebuah kelas yang lebih besar daripada StatelessWidget, yang mana akan mengalokasi lebih banyak RAM, dan ini mungkin tidak akan membuat perbedaan secara signifikan antara satu atau dua kelas, tapi itu pasti akan terjadi ketika anda memiliki 100 dari mereka!\nKecuali anda perlu menggunakan mixin, seperti TickerProviderStateMixin, akan sangat tidak dibutuhkan menggunakan StatefulWidget dengan Get.\n\nAnda bisa memanggil semua method dari StatefulWidget secara langsung melalui GetBuilder.\nJika anda perlu memanggil initState() atau dispose() method contohnya, anda bisa memanggilnya secara langsung;\n\n```dart\nGetBuilder<Controller>(\n  initState: (_) => Controller.to.fetchApi(),\n  dispose: (_) => Controller.to.closeStreams(),\n  builder: (s) => Text('${s.username}'),\n),\n```\n\nCara yang lebih baik daripada ini adalah dengan menggunakan onInit() dan onClose() method secara langsung dari controller anda.\n\n```dart\n@override\nvoid onInit() {\n  fetchApi();\n  super.onInit();\n}\n```\n\n- CATATAN: Jika anda ingin memulai sebuah method pada saat controller dipanggil pertama kali, anda TIDAK PERLU menggunakan constructor, faktanya, menggunakan package yang berorientasi pada performa seperti Get, ini berbatas pada bad practice, karena menyimpang dari logic dimana setiap controller dibuat atau dialokasikan (jika anda membuat sebuah instance dari controller, constructornya akan dipanggil dengan segera, anda akan menumpuk controller bahkan sebelum digunakan, anda mengalokasikan memori tanpa digunakan, hal ini benar-benar menyakiti prinsip dasar library ini). method onInit(); dan onClose(); dibuat untuk hal ini, mereka akan dipanggil ketika Controller dibuat, atau digunakan untuk pertama kali, bergantung pada kondisi apakah anda menggunakan Get.lazyPut atau tidak. Jika anda mau, sebagai contoh, membuat sebuah panggilan ke API anda untuk mempopulasikan data, anda bisa lupakan tentang metode lawas initState/dispose, cukup mulai memanggilnya didalam onInit, dan jika anda perlu meng-eksekusi perintah seperti menutup stream, gunakan onClose() untuk hal itu.\n\n### Mengapa GetX ada\n\nTujuan dari package ini adalah secara tepat memberikan anda sebuah solusi komplit untuk navigasi route, dependency dan state management, menggunakan sedikit mungkin dependensi, dengan tingkat decoupling yang tinggi. Get melibatkan semua Flutter API baik dari level tertinggi dan terendah dalam dirinya sendiri, untuk memastikan bahwa anda bekerja dengan sedikit mungkin keterkaitan (coupling). Kami memusatkan semuanya kedalam satu package, untuk memastikan bahwa anda tidak memiliki keterkaitan (coupling) di proyek anda. Dengan begitu, anda bisa menaruh hanya widget di view anda, dan membiarkan bagian tim anda yang bekerja dengan business logic secara bebas, bekerja dengan business logic tanpa bergantung pada elemen apapun yang ada didalam View. Ini menyediakan lingkungan kerja yang lebih bersih, jadi bagian yang lain dari tim anda bisa bekerja hanya dengan widget, tanpa khawatir tentang mengirim data dari controller anda.\n\nJadi untuk menyederhanakannya:\nAnda tidak perlu memanggil method di initState dan mengirim mereka menggunakan parameter ke controller anda, atau menggunakan constructor didalam controller anda untuk itu, anda memiliki method onInit() yang akan dipanggil di waktu yang tepat untuk memulai service anda.\nAnda tidak perlu memanggil perangkatnya, anda memiliki method onClose() yang akan dipanggil di momen yang tepat ketika controller tidak lagi dibutuhkan dan akan dihapus dari memori. Dengan begitu, biarkan views hanya untuk widget, menghindari berbagai macam business logic darinya.\n\nJangan memanggil dispose method didalam GetxController, itu tidak akan melakukan apa-apa, ingat bahwa controller bukanlah sebuah Widget, anda tidak seharusnya men-\"dispose\" sebuah controller, dan dia akan secara otomatis dan secara pandai dihapus dari memori oleh Get. Jika anda menggunakan stream didalamnya dan ingin menutupnya, cukup masukkan itu kedalam close method. Contoh:\n\n```dart\nclass Controller extends GetxController {\n  StreamController<User> user = StreamController<User>();\n  StreamController<String> name = StreamController<String>();\n\n  /// menutup stream = onClose method, bukan dispose.\n  @override\n  void onClose() {\n    user.close();\n    name.close();\n    super.onClose();\n  }\n}\n```\n\nController life cycle (atau: siklus kehidupan controller):\n\n- onInit() dimana ketika Controller dibuat.\n- onClose() dimana ketika Controller ditutup untuk membuat segala jenis perubahan dalam rangka persiapan untuk metode penghapusan\n- deleted: anda tidak lagi memiliki akses ke API ini karena secara harfiah menghapusnya dari memori, dan secara harfiah pula itu dihapus, tanpa meninggalkan jejak.\n\n### Cara lain dalam menggunakannya\n\nAnda bisa menggunakan Controller secara langsung didalam GetBuilder value:\n\n```dart\nGetBuilder<Controller>(\n  init: Controller(),\n  builder: (value) => Text(\n    '${value.counter}', // Disini\n  ),\n),\n```\n\nAnda juga mungkin membutuhkan sebuah instance dari controller anda diluar GetBuilder, dan anda bisa menggunakan pendekatan ini:\n\n```dart\nclass Controller extends GetxController {\n  static Controller get to => Get.find();\n[...]\n}\n// didalam View:\nGetBuilder<Controller>(  \n  init: Controller(), // Gunakan ini hanya untuk pertama kali pada setiap controller\n  builder: (_) => Text(\n    '${Controller.to.counter}', // Disini\n  )\n),\n```\n\natau\n\n```dart\nclass Controller extends GetxController {\n // static Controller get to => Get.find(); // tanpa static getter\n[...]\n}\n// didalam stateful/stateless class\nGetBuilder<Controller>(  \n  init: Controller(), // Gunakan ini hanya untuk pertama kali pada setiap controller\n  builder: (_) => Text(\n    '${Get.find<Controller>().counter}', // Disini\n  ),\n),\n```\n\n- Anda bisa menggunakan cara \"non-canonical\" untuk hal ini. Jika anda menggunakan dependensi manager lain, seperti get_it, modular, etc., dan hanya ingin mengirimkan instance controller, anda bisa melakukan ini:\n\n```dart\nController controller = Controller();\n[...]\nGetBuilder<Controller>(\n  init: controller, // Disini\n  builder: (_) => Text(\n    '${controller.counter}', // Disini\n  ),\n),\n\n```\n\n### Unique ID\n\nJika anda ingin me-refine update control sebuah widget dengan GetBuilder, anda bisa mengajukan unique ID untuk mereka:\n\n```dart\nGetBuilder<Controller>(\n  id: 'text' // Disini\n  init: Controller(),\n  builder: (_) => Text(\n    '${Get.find<Controller>().counter}',\n  ),\n),\n```\n\nDan mengupdatenya dalam bentuk ini:\n\n```dart\nupdate(['text']);\n```\n\nAnda juga bisa menerapkan kondisi untuk updatenya:\n\n```dart\nupdate(['text'], counter < 10);\n```\n\nGetX melakukan ini secara otomatis dan hanya merekonstruksi widget yang menggunakan variabel persis yang dirubah, jika anda mengubah sebuah variabel dengan hal yang sama seperti sebelumnya, dan tidak mengimplifikasikan sebuah perubahan sate , GetX tidak akan merebuild widget untuk menghemat memori dan siklus CPU.\n\n## Mencampur 2 state manager\n\nBeberapa orang membuka sebuah permintaan fitur, karena mereka hanya ingin menggunakan satu jenis variabel reaktif, dan mekanisme lain, dan diharuskan untuk memasukkan Obx kedalam GetBuilder untuk hal ini. Memikirkan hal ini, MixinBuilder dibuat. Ini mengizinkan kedua perubahan reaktif dengan mengubah variabel \".obs\", dan mekanikal update via update(). Meski begitu, dari 4 widget dia adalah satu-satunya yang mengonsumsi resource paling banyak, karena selain memiliki langganan untuk menerima event perubahan dari children nya, dia juga berlangganan kepada metode update di controllernya.\n\nMeng-extend GetxController sangatlah penting, karena mereka memiliki siklus dan bisa \"memulai\" dan \"mengakhiri\" event di method onInit() dan onClose() mereka. Anda bisa menggunakan kelas apapun untuk ini, tapi Saya sangat merekomendasikan anda untuk menggunakan kelas GetxController untuk menempatkan variabel anda, baik apakah mereka observable atau tidak.\n\n## GetBuilder vs GetX vs Obx vs MixinBuilder\n\nDalam satu dekade bekerja dengan programming Saya mendapat beberapa pelajaran berharga.\n\nKontak pertama saya dengan reactive programming adalah seperti \"waw, ini luar biasa\" dan faktanya, reactive programming itu luar biasa.\nMeski begitu, ini tidak cocok untuk segala situasi. Terkadang semua yang anda butuhkan adalah mengubah state dari 2 atau 3 widget dalam waktu yang sama, atau sebuah perubahan state sementara, yang mana reactive programming tidaklah buruk, tapi tidak cocok.\n\nReactive programming memiliki konsumsi lebih tinggi dalam penggunaan RAM yang bisa dikompensasi oleh alur kerja individu, dimana akan memastikan bahwa hanya satu widget direbuild dan jika dibutuhkan, namun membuat sebuah list dari 80 objek, masing masing dengan beberapa stream bukanlah ide yang bagus. Buka dart inspect dan cek berapa banyak yang dikonsumsi oleh StreamBuilder, dan anda akan memahami apa yang saya coba katakan kepada anda.\n\nDengan memikirkan hal itu, Saya membuat sebuah state manager yang simpel. Ini simpel, dan itulah yang harus anda tuntut darinya: mengupdate state dalam sebuah block dengan cara yang sederhana, dan dengan cara yang paling ekonomis.\n\nGetBuilder sangat ekonomis di RAM, dan hampir tidak ada pendekatan yang lebih ekonomis darinya (setidaknya saya tidak bisa membayangkannya, jika itu ada, mohon beri tahu kami).\n\nMeski begitu, GetBuilder tetaplah sebuah state manager mekanik, anda perlu memanggil update() seperti anda perlu memanggil notifyListeners() milik Provider.\n\nAda beberapa situasi lain dimana reactive programming benar benar menarik, dan tidak bekerja dengan itu sama saja seperti \"reinventing the wheel\". Dengan memikirkan hal itu, GetX dibuat untuk menyediakan semuanya yang paling modern dan advanced dalam sebuah state manager. Dia mengupdate hanya apa yang diperlukan dan ketika diperlukan, jika anda memiliki error dan mengirim 300 perubahan state secara beruntun, GetX akan memfilter dan mengupdate layar hanya jika state nya benar-benar berubah.\n\nGetX masih lebih ekonomis dari reactive state manager yang lain, namun dia juga menkonsumsi sedikit lebih banyak RAM daripada GetBuilder. Memikirkan tentang hal itu dan menargetkan untuk memaksimalkan konsumsi resource yang dibuat oleh Obx. Tidak seperti GetX dan GetBuilder, anda tidak akan bisa menginisialisasi sebuah controller didalam Obx, itu hanyalah sebuah widget dengan StreamSubscription yang menerima event perubahan dari children anda, itu saja. Ini lebih ekonomis dari GetX, namun kalah dari GetBuilder, yang memang diharapkan, karena dia reactive dan GetBuilder memiliki pendekatan yang paling sederhana yang ada, untuk menyimpan hashCode milik sebuah widget dan StateSetter nya. Dengan Obx anda tidak perlu menulis tipe controller, dan anda bisa mendengar perubahan dari banyak controller yang berbeda, namun itu harus di inisialisasi sebelumnya, baik menggunakan contoh pendekatan di awal readme ini, atau menggunakan Binding class.\n"
  },
  {
    "path": "documentation/ja_JP/dependency_management.md",
    "content": "# 依存オブジェクト管理\n- [依存オブジェクト管理](#依存オブジェクト管理)\n  - [インスタンス化に使用するメソッド](#インスタンス化に使用するメソッド)\n    - [Get.put()](#getput)\n    - [Get.lazyPut()](#getlazyput)\n    - [Get.putAsync()](#getputasync)\n    - [Get.create()](#getcreate)\n  - [インスタンス化したクラスを使う](#インスタンス化したクラスを使う)\n  - [依存オブジェクトの置換](#依存オブジェクトの置換)\n  - [各メソッドの違い](#各メソッドの違い)\n  - [Bindings（Routeと依存オブジェクトの結束）](#Bindings（Routeと依存オブジェクトの結束）)\n    - [Bindingsクラス](#bindingsクラス)\n    - [BindingsBuilder](#bindingsbuilder)\n    - [SmartManagement](#smartmanagement)\n      - [設定の変更方法](#設定の変更方法)\n      - [SmartManagement.full](#smartmanagementfull)\n      - [SmartManagement.onlyBuilder](#smartmanagementonlybuilder)\n      - [SmartManagement.keepFactory](#smartmanagementkeepfactory)\n    - [Bindingsの仕組み](#Bindingsの仕組み)\n  - [補足](#補足)\n\nGetにはシンプルで強力な依存オブジェクト管理機能があります。たった1行のコードで、Provider contextやinheritedWidgetを使うことなく、BlocもしくはControllerのインスタンスを取得することができます。\n\n```dart\nController controller = Get.put(Controller()); // Controller controller = Controller() の代わりに\n```\n\nUIクラスの中でControllerクラスをインスタンス化する代わりに、Getインスタンスの中でインスタンス化することで、アプリ全体でControllerを利用できるようになります。\n\n- 注: Getの状態管理機能を使用する場合は、[Bindings](#bindings)の使用も検討してください。Bindingsを使うことでビューにControllerを結合させることができます。\n- 注²: Getの依存オブジェクト管理機能は、パッケージの他の部分から独立しています。そのため、たとえばあなたのアプリが既に他の状態管理ライブラリを使用している場合（どんなものでも）、何の問題もなく2つを組み合わせることができます。\n\n## インスタンス化に使用するメソッド\nControllerを初期化するのに使用するメソッドとその設定パラメーターについてご説明します。\n\n### Get.put()\n\n依存オブジェクトを注入するための最も基本のメソッド。たとえば、ビューで使用するControllerに使います。\n\n```dart\nGet.put<SomeClass>(SomeClass());\nGet.put<LoginController>(LoginController(), permanent: true);\nGet.put<ListItemController>(ListItemController, tag: \"some unique string\");\n```\n\n以下が put() を使用する際に設定できるパラメーターです。\n```dart\nGet.put<S>(\n  // 必須。インスタンスを保存しておきたいControllerなどを設定\n  // 注: \"S\" 型はジェネリクスで、どんな型でもOK\n  S dependency\n\n  // オプション。これは同じ型のControllerインスタンスが複数存在する場合に、\n  // タグIDにより識別したい場合に使用します。\n  // Get.find<Controller>(tag: ) でこのputで設定したインスタンスを探します。\n  // tag はユニークなStringである必要があります。\n  String tag,\n\n  // オプション。デフォルトでは使用されなくなったインスタンスは破棄されますが、\n  // （たとえばビューが閉じられた場合など） SharedPreferencesのインスタンスなど、\n  // アプリ全体を通して生かしておきたい場合があるかと思います。\n  // その場合はこれをtrueにしてください。デフォルトはfalseです。\n  bool permanent = false,\n\n  // オプション。テストで抽象クラスを使用した後、別クラスに置換してテストを追うことができます。\n  // デフォルトはfalseです。\n  bool overrideAbstract = false,\n\n  // オプション: 依存オブジェクトを関数を使って作ることができます。\n  // 使用頻度は低いと思います。\n  InstanceBuilderCallback<S> builder,\n)\n```\n\n### Get.lazyPut()\n依存オブジェクトをすぐにロードする代わりに、lazy（遅延、消極的）ロードすることができます。実際に使用されるときに初めてインスタンス化されます。計算量の多いクラスや、Bindingsを使って複数のControllerをまとめてインスタンス化したいが、その時点ではすぐにそれらを使用しないことがわかっている場合などに非常に便利です。\n\n```dart\n/// この場合のApiMockは Get.find<ApiMock> を使用した時点でインスタンス化されます。\nGet.lazyPut<ApiMock>(() => ApiMock());\n\nGet.lazyPut<FirebaseAuth>(\n  () {\n    // 必要ならここに何かのロジック\n    return FirebaseAuth();\n  },\n  tag: Math.random().toString(),\n  fenix: true\n)\n\nGet.lazyPut<Controller>( () => Controller() )\n```\n\nこれが .lazyPut で設定できるパラメーターです。\n```dart\nGet.lazyPut<S>(\n  // 必須。クラスSが初めてfindの対象になったときに実行されるメソッド\n  InstanceBuilderCallback builder,\n\n  // オプション。Get.put()のtagと同様に同じクラスの異なるインスタンスが必要なときに使用\n  // ユニークな値を指定\n  String tag,\n\n  // オプション。\"permanent\" に似ていますが、使用されていないときはインスタンスが\n  // 破棄され、再び使用するときにGetがインスタンスを再び作成する点が異なります。\n  // Bindings APIの \"SmartManagement.keepFactory \" と同じです。\n  // デフォルトはfalse\n  bool fenix = false\n\n)\n```\n\n### Get.putAsync()\nSharedPreferencesなど、非同期のインスタンスを登録したいときに使います。\n\n```dart\nGet.putAsync<SharedPreferences>(() async {\n  final prefs = await SharedPreferences.getInstance();\n  await prefs.setInt('counter', 12345);\n  return prefs;\n});\n\nGet.putAsync<YourAsyncClass>( () async => await YourAsyncClass() )\n```\n\nこれが .putAsync で設定できるパラメーターです。\n```dart\nGet.putAsync<S>(\n\n  // 必須。クラスをインスタンス化するための非同期メソッドを指定\n  AsyncInstanceBuilderCallback<S> builder,\n\n  // オプション。Get.put() と同じです。同じクラスの異なるインスタンスを作りたいときに使用\n  // ユニークな値を指定\n  String tag,\n\n  // オプション。Get.put() と同じです。アプリ全体を通して生かしておきたい場合に使用\n  // デフォルトはfalse\n  bool permanent = false\n)\n```\n\n### Get.create()\n\nこれは使いどころに迷うかもしれません。他のものとの違いなど詳細な説明は「[各メソッドの違い](#各メソッドの違い)」のセクションをご一読ください。\n\n```dart\nGet.Create<SomeClass>(() => SomeClass());\nGet.Create<LoginController>(() => LoginController());\n```\n\nこれが .create で設定できるパラメーターです。\n\n```dart\nGet.create<S>(\n  // 必須。Get.find() が呼ばれるたびにインスタンスがこの関数で新たに組み立てられる。\n  // 例: Get.create<YourClass>(() => YourClass())\n  FcBuilderFunc<S> builder,\n\n  // オプション。Get.put() のtagと同様で、同じクラスによる\n  // 複数インスタンスを扱うときに使用します。\n  // リストのアイテムにそれぞれコントローラが必要な場合に便利です。\n  // 文字列はユニークである必要があります。\n  String name,\n\n  // オプション。Get.put() と同様アプリ全体でインスタンスを維持するときに使用。\n  // 唯一の違いは Get.create() のpermanentはデフォルトでtrueということだけです。\n  bool permanent = true\n```\n\n## インスタンス化したクラスを使う\n\nいくつかのRouteを渡り歩いた後、以前のControllerに残してきたデータが必要になったとしたら、Provider や Get_it と組み合わせる必要がありますよね？Getの場合は違います。GetにControllerの「検索」を依頼するだけで追加の依存オブジェクトの注入は必要ありません。\n\n```dart\nfinal controller = Get.find<Controller>();\n// もしくは\nController controller = Get.find();\n\n// マジックみたいですよね。でも実際にGetはControllerのインスタンスを探して届けてくれます。\n// 100万ものControllerをインスタンス化していても、Getは常に正しいControllerを探してくれます。\n```\n\nそしてそのControllerが以前取得したデータをあなたは復元することができます。\n\n```dart\nText(controller.textFromApi);\n```\n\n戻り値は通常のクラスなので、そのクラスで可能なことは何でもできます。\n```dart\nint count = Get.find<SharedPreferences>().getInt('counter');\nprint(count); // 出力: 12345\n```\n\nインスタンスを明示的に削除したい場合はこのようにしてください。\n\n```dart\nGet.delete<Controller>(); // 通常であれば、GetXは未使用Controllerを自動削除するので、この作業は必要ありません。\n```\n\n## 依存オブジェクトの置換\n\n注入されている依存オブジェクトは `replace` または `lazyReplace` メソッドを使って、子クラスなど関連クラスのインスタンスに置き換えることができます。これは元の抽象クラスを型指定することで取得することができます。\n\n```dart\nabstract class BaseClass {}\nclass ParentClass extends BaseClass {}\n\nclass ChildClass extends ParentClass {\n  bool isChild = true;\n}\n\n\nGet.put<BaseClass>(ParentClass());\n\nGet.replace<BaseClass>(ChildClass());\n\nfinal instance = Get.find<BaseClass>();\nprint(instance is ChildClass); //true\n\n\nclass OtherClass extends BaseClass {}\nGet.lazyReplace<BaseClass>(() => OtherClass());\n\nfinal instance = Get.find<BaseClass>();\nprint(instance is ChildClass); // false\nprint(instance is OtherClass); //true\n```\n\n## Differences between methods\n\nまずは Get.lazyPut の `fenix` プロパティと、他メソッドの `permanent` プロパティの違いについてご説明します。\n\n`permanent` と `fenix` の根本的な違いは、インスタンスをどのように保持したいかという点に尽きます。\n\nしつこいようですが、GetXでは使われていないインスタンスは削除されるのがデフォルトの動作です。\nこれはもし画面AがController A、画面BがController Bを持っている場合において、画面Bに遷移するときに画面Aをスタックから削除した場合（`Get.off()` や `Get.offNamed()` を使うなどして）、Controller Aは消えてなくなるということです。\n\nしかし Get.put() する際に `permanent:true` としていれば、Controller Aはこの画面削除により失われることはありません。これはアプリケーション全体を通してControllerを残しておきたい場合に大変便利です。\n\n一方の `fenix` は、画面削除に伴っていったんはControllerが消去されますが、再び使いたいと思ったときに復活させることができます。つまり基本的には未使用の Controller / サービス / その他クラス は消去されますが、必要なときは新しいインスタンスを「燃えカス」から作り直すことができるのです。\n\n各メソッドを使用する際のプロセスの違いをご説明します。\n\n- Get.put と Get.putAsync はインスタンスを作成して初期化するプロセスは同じですが、後者は非同期メソッドを使用するという違いがあります。この2つのメソッドは内部に保有するメソッド `insert` に `permanent: false` と `isSingleton: true` という引数を渡して、メモリに直接インスタンスを挿入します (この isSingleton が行っていることは、依存オブジェクトを `dependency` と `builder` プロパティのどちらから拝借するかを判断することだけです)。その後に `Get.find()` が呼ばれると、メモリ上にあるインスタンスを即座に初期化するというプロセスをたどります。\n\n- Get.create はその名の通り、依存オブジェクトを「クリエイト」します。Get.put() と同様に内部メソッドである `insert` を呼び出してインスタンス化します。違いは `permanent: true` で `isSingleton: false` である点です (依存オブジェクトを「クリエイト」しているため、シングルトンにはなりません。それが false になっている理由です)。また `permanent: true` となっているので、デフォルトでは画面の破棄などでインスタンスを失わないというメリットがあります。また `Get.find()` はすぐに呼ばれず、画面内で実際に使用されてから呼ばれます。これは `permanent` の特性を活かすための設計ですが、それゆえ `Get.create()` は共有しないけど破棄もされないインスタンスを作成する目的で作られたと言えます。たとえば、ListViewの中のボタンアイテムに使うControllerインスタンスのように、そのリスト内でしか使わないけどリストアイテムごとに固有のインスタンスが必要なケースなどが考えられます。そのため、Get.create は GetWidget との併用がマストです。\n\n- Get.lazyPut は初期化をlazy（遅延、消極的）に行います。実行されるとインスタンスは作成されますが、すぐに使用できるように初期化はされず、待機状態になります。また他のメソッドと異なり `insert` メソッドは呼び出されません。その代わり、インスタンスはメモリの別の部分に挿入されます。この部分を「ファクトリー」と呼ぶことにしましょう。「ファクトリー」は、そのインスタンスが再生成できるかどうかを決める役割を持っています。これは後で使う予定のものを、現在進行形で使われているものと混ざらないようにするための工夫です。ここで `fenix` によるマジックが登場します。デフォルトの `fenix: false` のままにしており、かつ `SmartManagement` が `keepFactory` ではない場合において `Get.find` を使用すると、インスタンスは「ファクトリー」から共有メモリ領域に移動します。その直後にインスタンスは「ファクトリー」から削除されます。しかし `fenix: true` としていた場合、インスタンスは「ファクトリー」に残るため、共有メモリ領域から削除されても再び呼び出すことができるのです。\n\n## Bindings（Routeと依存オブジェクトの結束）\n\nこのパッケージの一番の差別化要素は、Route管理 / 状態管理 / 依存オブジェクト管理 を統合したことにあると思っています。\nスタックからRouteが削除されれば、関係するController、変数、オブジェクトのインスタンスがすべてメモリから削除されます。たとえばStreamやTimerを使用している場合も同様ですので、開発者は何も心配する必要はありません。\nGetはバージョン2.10からBindings APIをフル実装しました。\nBindingsを使用すれば init でControllerを起動する必要はありません。またControllerの型を指定する必要もありません。Controllerやサービスは各々適切な場所で起動することができるようになりました。\nBindingsは依存オブジェクトの注入をビューから切り離すことができるクラスです。それに加え、状態と依存オブジェクトの管理機能をRouteに「結束（bind）」してくれます。\nこれによりGetは、あるControllerが使用されたときにどの画面UIが表示されているかを知ることができます。つまり、そのControllerをどのタイミングでどう処分するかを判断することができるということです。\nさらにBindingsでは SmartManager の制御により、依存オブジェクトをどのタイミング（スタックからRouteを削除したときか、それに依存するWidgetを表示したときか、いずれでもないか）で整理するかを設定することができます。インテリジェントな依存オブジェクトの自動管理機能を持ちつつ、自分の好きなように設定できるのです。\n\n### Bindingsクラス\n\n- Bindings機能を実装したクラスを作成することができます。\n\n```dart\nclass HomeBinding implements Bindings {}\n```\n\n\"dependencies\" メソッドをオーバーライドするようIDEに自動で指摘されます。表示をクリックしてメソッドを override し、そのRoute内で使用するすべてのクラスを挿入してください。\n\n```dart\nclass HomeBinding implements Bindings {\n  @override\n  void dependencies() {\n    Get.lazyPut<HomeController>(() => HomeController());\n    Get.put<Service>(()=> Api());\n  }\n}\n\nclass DetailsBinding implements Bindings {\n  @override\n  void dependencies() {\n    Get.lazyPut<DetailsController>(() => DetailsController());\n  }\n}\n```\n\nBindingsを設定したら、このクラスが Route管理 / 依存オブジェクト管理 / 状態管理 を互いに接続する目的で使用されるものだということをRouteに知らせてあげます。\n\n- 名前付きRouteを使う場合\n\n```dart\ngetPages: [\n  GetPage(\n    name: '/',\n    page: () => HomeView(),\n    binding: HomeBinding(),\n  ),\n  GetPage(\n    name: '/details',\n    page: () => DetailsView(),\n    binding: DetailsBinding(),\n  ),\n];\n```\n\n- 通常のRouteを使う場合\n\n```dart\nGet.to(Home(), binding: HomeBinding());\nGet.to(DetailsView(), binding: DetailsBinding())\n```\n\nこれでアプリケーションのメモリ管理を気にする必要がなくなります。Getがすべてやってくれます。\n\nBindingsクラスはRouteの呼び出しと同時に呼び出されます。また、すべてに共通の依存オブジェクトを挿入するためには GetMaterialApp の initialBinding プロパティを使用してください。\n\n```dart\nGetMaterialApp(\n  initialBinding: SampleBind(),\n  home: Home(),\n);\n```\n\n### BindingsBuilder\n\nBindingsを作成する一般的な方法は Bindings を実装したクラスを作成することですが、`BindingsBuilder` コールバックを使う方法もあります。\n\nExample:\n\n```dart\ngetPages: [\n  GetPage(\n    name: '/',\n    page: () => HomeView(),\n    binding: BindingsBuilder(() {\n      Get.lazyPut<ControllerX>(() => ControllerX());\n      Get.put<Service>(()=> Api());\n    }),\n  ),\n  GetPage(\n    name: '/details',\n    page: () => DetailsView(),\n    binding: BindingsBuilder(() {\n      Get.lazyPut<DetailsController>(() => DetailsController());\n    }),\n  ),\n];\n```\n\nこの方法ならRouteごとにBindingsクラスを作る必要はありません。\n\nどちらの方法でも効果は変わりませんのでお好みの方法を使ってください。\n\n### SmartManagement\n\nエラーが発生してControllerを使用するWidgetが正しく破棄されなかった場合でも、Controllerが未使用になればGetXはデフォルトの動作通りそれをメモリから削除します。\nこれがいわゆる依存オブジェクト管理機能の `full` モードと呼ばれるものです。\nしかしもしGetXによるオブジェクト破棄の方法をコントロールしたい場合は、`SmartManagement`クラスを使って設定してください。\n\n#### 設定の変更方法\n\nこの設定は通常変更する必要はありませんが、変更されたい場合はこのようにしてください。\n\n```dart\nvoid main () {\n  runApp(\n    GetMaterialApp(\n      smartManagement: SmartManagement.onlyBuilder // ここで設定\n      home: Home(),\n    )\n  )\n}\n```\n\n#### SmartManagement.full\n\nこれがデフォルトのモードです。使用されていない、かつ `permanent: true` が設定されていないオブジェクトを自動で破棄してくれます。特殊な事情がない限り、この設定は触らない方がいいでしょう。GetXを使って間がない場合は特に。\n\n#### SmartManagement.onlyBuilder\n`init:` もしくはBindings内で `Get.lazyPut()` により設定したビルダー製のオブジェクトだけを破棄するモードです。\n\nもしそれが `Get.put()` や `Get.putAsync()` などのアプローチで生成したオブジェクトだとしたら、SmartManagement は勝手にメモリから除外することはできません。\n\nそれに対してデフォルトのモードでは `Get.put()` で生成したオブジェクトも破棄します。\n\n#### SmartManagement.keepFactory\n\nSmartManagement.full と同じように、オブジェクトが使用されていない状態になれば破棄します。ただし、前述の「ファクトリー」に存在するものだけは残します。つまりそのインスタンスが再び必要になった際は依存オブジェクトを再度生成するということです。\n\n### Bindingsの仕組み\nBindingsは「一過性のファクトリー」のようなものを作成します。これはそのRouteに画面遷移した瞬間に作成され、そこから画面移動するアニメーションが発生した瞬間に破棄されます。\nこの動作は非常に高速で行われるので、アナライザーでは捕捉できないほどです。\n再び元の画面に戻ると新しい「一過性のファクトリー」が呼び出されます。そのためこれは SmartManagement.keepFactory を使用するよりも多くの場合好ましいですが、Bindingsを作成したくない場合やすべての依存オブジェクトを同じBindingsに持っておきたい場合は SmartManagement.keepFactory を使うといいでしょう。\nファクトリーのメモリ使用量は少なく、インスタンスを保持することはありません。その代わりにそのクラスのインスタンスを形作る関数を保持します。\nメモリコストは非常に低いのですが、最小リソースで最大パフォーマンスを得ることが目的のGetではデフォルトでファクトリーを削除します。\nどちらか都合に合う方ををお使いいただければと思います。\n\n## 補足\n\n- 複数のBindingsを使う場合は SmartManagement.keepFactory は**使わない**でください。これは Bindings を使わないケースや、GetMaterialAppのinitialBindingに設定された単独のBindingと一緒に使うケースを想定されて作られました。\n\n- Bindingsを使うことは必須ではありません。`Get.put()` と `Get.find()` だけでも全く問題ありません。\nただし、サービスやその他抽象度の高いクラスをアプリに取り入れる場合はコード整理のために使うことをおすすめします。\n"
  },
  {
    "path": "documentation/ja_JP/route_management.md",
    "content": "- [Route管理](#Route管理)\n  - [使い方](#使い方)\n  - [通常Routeによるナビゲーション](#通常Routeによるナビゲーション)\n  - [名前付きRouteによるナビゲーション](#名前付きRouteによるナビゲーション)\n    - [名前付きRouteにデータを送る](#名前付きRouteにデータを送る)\n    - [動的URLの生成](#動的URLの生成)\n    - [ミドルウェアの使用](#ミドルウェアの使用)\n  - [contextを使わないナビゲーション](#contextを使わないナビゲーション)\n    - [SnackBar](#snackbar)\n    - [Dialog](#dialog)\n    - [BottomSheet](#bottomsheet)\n  - [ネスト構造のナビゲーション](#ネスト構造のナビゲーション)\n\n# Route管理\n\nこのドキュメントではGetXにおけるRoute管理のすべてをご説明します。\n\n## How to use\n\n次の3文字を pubspec.yaml ファイルに追加してください。\n\n```yaml\ndependencies:\n  get:\n```\n\nRoute / SnackBar / Dialog / BottomSheet をcontextなしで、あるいは高レベルのGet APIを使用するには MaterialApp の前に「Get」を追加してください。それだけで GetMaterialApp の機能が使用できます。\n\n```dart\nGetMaterialApp( // 変更前: MaterialApp(\n  home: MyHome(),\n)\n```\n\n## 名前付きRouteによる画面遷移\n\n次の画面に遷移するには Get.to を使ってください。\n\n```dart\nGet.to(NextScreen());\n```\n\nSnackBar / Dialog / BottomSheet など Navigator.pop(context) で閉じるものと同じものを閉じるには Get.back を使います。\n\n```dart\nGet.back();\n```\n\n次の画面に遷移しつつ、前の画面に戻れないようにするには Get.off を使います（スプラッシュスクリーンやログイン画面などで使用)。\n\n```dart\nGet.off(NextScreen());\n```\n\n次の画面に遷移して、それ以前のRouteはすべて破棄するには Get.offAll を使います（ショッピングカート、投票、テストなどで使用)\n\n```dart\nGet.offAll(NextScreen());\n```\n\n次の画面に遷移して、戻ったらデータを受け取る方法はこちら。\n\n```dart\nvar data = await Get.to(Payment());\n```\n\n次の画面では、このようにデータを前の画面に送る必要があります。\n\n```dart\nGet.back(result: 'success');\n```\n\nそして使いましょう。\n\nex:\n\n```dart\nif(data == 'success') madeAnything();\n```\n\nどのようなシンタックスがあるかもっと知りたいですか？\nいつもの Navigator ではなく navigator と入れてみてください。通常のNavigatorで使えるプロパティがcontextなしで使えるようになっているかと思います。\n\n```dart\n\n// 通常のFlutterによるNavigator\nNavigator.of(context).push(\n  context,\n  MaterialPageRoute(\n    builder: (BuildContext context) {\n      return HomePage();\n    },\n  ),\n);\n\n// GetではFlutterのシンタックスをcontextなしで使えます\nnavigator.push(\n  MaterialPageRoute(\n    builder: (_) {\n      return HomePage();\n    },\n  ),\n);\n\n// Getのシンタックス（上記よりかなり短いですね）\nGet.to(HomePage());\n\n\n```\n\n## 名前付きRouteによる画面遷移\n\n- Getは名前付きRouteによる遷移もサポートしています。\n\n次の画面への遷移はこう。\n\n```dart\nGet.toNamed(\"/NextScreen\");\n```\n\nGet.off の名前付きRoute版。\n\n```dart\nGet.offNamed(\"/NextScreen\");\n```\n\nGet.offAll の名前付きRoute版。\n\n```dart\nGet.offAllNamed(\"/NextScreen\");\n```\n\nRouteを定義するにはGetMaterialAppを使ってください。\n\n```dart\nvoid main() {\n  runApp(\n    GetMaterialApp(\n      initialRoute: '/',\n      getPages: [\n        GetPage(name: '/', page: () => MyHomePage()),\n        GetPage(name: '/second', page: () => Second()),\n        GetPage(\n          name: '/third',\n          page: () => Third(),\n          transition: Transition.zoom\n        ),\n      ],\n    )\n  );\n}\n```\n\n未定義Route（404エラー）に遷移させるには、GetMaterialAppで unknownRoute を設定してください。\n\n```dart\nvoid main() {\n  runApp(\n    GetMaterialApp(\n      unknownRoute: GetPage(name: '/notfound', page: () => UnknownRoutePage()),\n      initialRoute: '/',\n      getPages: [\n        GetPage(name: '/', page: () => MyHomePage()),\n        GetPage(name: '/second', page: () => Second()),\n      ],\n    )\n  );\n}\n```\n\n### 名前付きRouteにデータを送る\n\n次の画面に渡すデータは arguments で引数を設定します。Getでは引数にどんなものでも指定できます。StringでもMapでもListでも、クラスのインスタンスでも大丈夫です。\n\n```dart\nGet.toNamed(\"/NextScreen\", arguments: 'Get is the best');\n```\n\nビュー側のクラスやControllerで値を使うにはこうしてください。\n\n```dart\nprint(Get.arguments);\n// Get is the best が表示される\n```\n\n### 動的URLの生成\n\nGetはウェブのような高度な動的URLを提供します。ウェブ開発者はFlutterにこの機能が提供されることを待ち望んでいたことでしょう。この機能の提供を謳うパッケージは存在しますが、ウェブ上のURLとは全く異なるシンタックスが表示されているのを見たことがあるかもしれません。Getはこの点も解決します。\n\n```dart\nGet.offAllNamed(\"/NextScreen?device=phone&id=354&name=Enzo\");\n```\n\nビュー側のクラスやControllerで値を使う方法。\n\n```dart\nprint(Get.parameters['id']);\n// 出力: 354\nprint(Get.parameters['name']);\n// 出力: Enzo\n```\n\nこの名前付きパラメーターはこのように簡単に受け取ることもできます。\n\n```dart\nvoid main() {\n  runApp(\n    GetMaterialApp(\n      initialRoute: '/',\n      getPages: [\n      GetPage(\n        name: '/',\n        page: () => MyHomePage(),\n      ),\n      GetPage(\n        name: '/profile/',\n        page: () => MyProfile(),\n      ),\n       // 引数userを使う場合と使わない場合で別ページを定義することが可能です。\n       // ただ、そのためにはスラッシュ '/' をベースのRoute名の後に入れる必要があります。\n       GetPage(\n        name: '/profile/:user',\n        page: () => UserProfile(),\n      ),\n      GetPage(\n        name: '/third',\n        page: () => Third(),\n        transition: Transition.cupertino\n      ),\n     ],\n    )\n  );\n}\n```\n\nRoute名を使ってデータを送る方法。\n\n```dart\nGet.toNamed(\"/profile/34954\");\n```\n\n次の画面でデータを受け取る方法。\n\n```dart\nprint(Get.parameters['user']);\n// out: 34954\n```\n\n複数のパラメーターを送信するにはこちら。\n\n```dart\nGet.toNamed(\"/profile/34954?flag=true&country=italy\");\n```\nもしくは\n```dart\nvar parameters = <String, String>{\"flag\": \"true\",\"country\": \"italy\",};\nGet.toNamed(\"/profile/34954\", parameters: parameters);\n```\n\n次の画面でデータを受け取る方法。\n\n```dart\nprint(Get.parameters['user']);\nprint(Get.parameters['flag']);\nprint(Get.parameters['country']);\n// 出力: 34954 true italy\n```\n\n\n\nあとは Get.toNamed() を使い、名前付きRouteを指定するだけです（contextを使わないので BLoC や Controller から直接Routeを呼び出すことができます）。ウェブアプリとしてコンパイルされると、Routeが正しくURLに表示されます。\n\n### ミドルウェアの使用\n\n何かのアクションのトリガーとなるイベントを取得したい場合は、routingCallbackを使用してください。\n\n```dart\nGetMaterialApp(\n  routingCallback: (routing) {\n    if(routing.current == '/second'){\n      openAds();\n    }\n  }\n)\n```\n\nGetMaterialAppを使用しない場合は、手動のAPIを使ってミドルウェアオブザーバーを設定してください。\n\n```dart\nvoid main() {\n  runApp(\n    MaterialApp(\n      onGenerateRoute: Router.generateRoute,\n      initialRoute: \"/\",\n      navigatorKey: Get.key,\n      navigatorObservers: [\n        GetObserver(MiddleWare.observer), // ここ\n      ],\n    ),\n  );\n}\n```\n\nミドルウェアクラスを作成する\n\n```dart\nclass MiddleWare {\n  static observer(Routing routing) {\n    /// Routeの他に SnackBar / Dialog / BottomSheet のイベントも監視することができます。\n    /// また、ここで直接この3つのいずれかを表示したい場合は、\n    /// イベント自身が「それではない」ことを事前にチェックする必要があります。\n    if (routing.current == '/second' && !routing.isSnackbar) {\n      Get.snackbar(\"Hi\", \"You are on second route\");\n    } else if (routing.current =='/third'){\n      print('last route called');\n    }\n  }\n}\n```\n\nそれではGetをコードで使ってみましょう。\n\n```dart\nclass First extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        leading: IconButton(\n          icon: Icon(Icons.add),\n          onPressed: () {\n            Get.snackbar(\"hi\", \"i am a modern snackbar\");\n          },\n        ),\n        title: Text('First Route'),\n      ),\n      body: Center(\n        child: ElevatedButton(\n          child: Text('Open route'),\n          onPressed: () {\n            Get.toNamed(\"/second\");\n          },\n        ),\n      ),\n    );\n  }\n}\n\nclass Second extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        leading: IconButton(\n          icon: Icon(Icons.add),\n          onPressed: () {\n            Get.snackbar(\"hi\", \"i am a modern snackbar\");\n          },\n        ),\n        title: Text('second Route'),\n      ),\n      body: Center(\n        child: ElevatedButton(\n          child: Text('Open route'),\n          onPressed: () {\n            Get.toNamed(\"/third\");\n          },\n        ),\n      ),\n    );\n  }\n}\n\nclass Third extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: Text(\"Third Route\"),\n      ),\n      body: Center(\n        child: ElevatedButton(\n          onPressed: () {\n            Get.back();\n          },\n          child: Text('Go back!'),\n        ),\n      ),\n    );\n  }\n}\n```\n\n## contextを使わないナビゲーション\n\n### SnackBar\n\nFlutterでシンプルなSnackBarを表示したいとき、Scaffoldのcontextか、GlobalKeyを取得する必要があります。\n\n```dart\nfinal snackBar = SnackBar(\n  content: Text('Hi!'),\n  action: SnackBarAction(\n    label: 'I am a old and ugly snackbar :(',\n    onPressed: (){}\n  ),\n);\n// WidgetツリーでScaffoldを探し、それをSnackBar表示に使用します。\nScaffold.of(context).showSnackBar(snackBar);\n```\n\nGetならこうなります。\n\n```dart\nGet.snackbar('Hi', 'i am a modern snackbar');\n```\n\nコードのどこにいようと、Get.snackbar を呼ぶだけでいいのです。カスタマイズも自由自在です。\n\n```dart\nGet.snackbar(\n  \"Hey i'm a Get SnackBar!\", // タイトル\n  \"It's unbelievable! I'm using SnackBar without context, without boilerplate, without Scaffold, it is something truly amazing!\", // 本文\n  icon: Icon(Icons.alarm),\n  shouldIconPulse: true,\n  onTap:(){},\n  barBlur: 20,\n  isDismissible: true,\n  duration: Duration(seconds: 3),\n);\n\n\n  ////////// すべてのプロパティ //////////\n  //     Color colorText,\n  //     Duration duration,\n  //     SnackPosition snackPosition,\n  //     Widget titleText,\n  //     Widget messageText,\n  //     bool instantInit,\n  //     Widget icon,\n  //     bool shouldIconPulse,\n  //     double maxWidth,\n  //     EdgeInsets margin,\n  //     EdgeInsets padding,\n  //     double borderRadius,\n  //     Color borderColor,\n  //     double borderWidth,\n  //     Color backgroundColor,\n  //     Color leftBarIndicatorColor,\n  //     List<BoxShadow> boxShadows,\n  //     Gradient backgroundGradient,\n  //     TextButton mainButton,\n  //     OnTap onTap,\n  //     bool isDismissible,\n  //     bool showProgressIndicator,\n  //     AnimationController progressIndicatorController,\n  //     Color progressIndicatorBackgroundColor,\n  //     Animation<Color> progressIndicatorValueColor,\n  //     SnackStyle snackStyle,\n  //     Curve forwardAnimationCurve,\n  //     Curve reverseAnimationCurve,\n  //     Duration animationDuration,\n  //     double barBlur,\n  //     double overlayBlur,\n  //     Color overlayColor,\n  //     Form userInputForm\n  ///////////////////////////////////\n```\n\n従来の SnackBar がお好みの場合や、ゼロからカスタマイズしたい場合 (たとえば Get.snackbar ではタイトルと本文が必須項目となっています)は `Get.rawSnackbar();` を使ってください。SnackBarの元々のAPIを取得できます。\n\n### Dialog\n\nダイアログを表示する方法。\n\n```dart\nGet.dialog(YourDialogWidget());\n```\n\nデフォルトのダイアログを表示する方法。\n\n```dart\nGet.defaultDialog(\n  onConfirm: () => print(\"Ok\"),\n  middleText: \"Dialog made in 3 lines of code\"\n);\n```\n\nまた showGeneralDialog の代わりに Get.generalDialog が使えます。\n\nOverlayを使用するCupertino含むその他のFlutterのダイアログについては、contextの代わりに Get.overlayContext を使うことでコードのどこでもダイアログを表示することができます。\nOverlayを使わないWidgetについては、Get.context が使えます。\nこれら2つのcontextはほとんどのケースでUIのcontextを代替することができるでしょう。ただし、ナビゲーションのcontextを使用せずInheritedWidgetが使われているケースは例外です。\n\n### BottomSheet\n\nGet.bottomSheet は showModalBottomSheet に似ていますが、contextが不要です。\n\n```dart\nGet.bottomSheet(\n  Container(\n    child: Wrap(\n      children: <Widget>[\n        ListTile(\n          leading: Icon(Icons.music_note),\n          title: Text('Music'),\n          onTap: () {}\n        ),\n        ListTile(\n          leading: Icon(Icons.videocam),\n          title: Text('Video'),\n          onTap: () {},\n        ),\n      ],\n    ),\n  )\n);\n```\n\n## ネスト構造のナビゲーション\n\nGetはFlutterのネスト構造のナビゲーションの扱いも簡単にしてくれます。\ncontextを必要とせず、IDによりナビゲーションのスタックを見つけることができます。\n\n- 注: 並列のナビゲーションスタックを作成することは危険です。ネスト構造のNavigatorを使用しないか、使用を控えめにするのが理想です。必要なら使っていただいても問題ありませんが、複数のナビゲーションのスタックを保持することはRAM消費の面で好ましくないということは覚えておいてください。\n\nこんなに簡単にできます。\n\n```dart\nNavigator(\n  key: Get.nestedKey(1), // インデックス指定でkey作成\n  initialRoute: '/',\n  onGenerateRoute: (settings) {\n    if (settings.name == '/') {\n      return GetPageRoute(\n        page: () => Scaffold(\n          appBar: AppBar(\n            title: Text(\"Main\"),\n          ),\n          body: Center(\n            child: TextButton(\n              color: Colors.blue,\n              onPressed: () {\n                Get.toNamed('/second', id:1); // インデックス指定でネスト型Routeに遷移\n              },\n              child: Text(\"Go to second\"),\n            ),\n          ),\n        ),\n      );\n    } else if (settings.name == '/second') {\n      return GetPageRoute(\n        page: () => Center(\n          child: Scaffold(\n            appBar: AppBar(\n              title: Text(\"Main\"),\n            ),\n            body: Center(\n              child:  Text(\"second\")\n            ),\n          ),\n        ),\n      );\n    }\n  }\n),\n```\n"
  },
  {
    "path": "documentation/ja_JP/state_management.md",
    "content": "* [状態管理](#状態管理)\n  + [リアクティブな状態管理](#リアクティブな状態管理)\n    - [利点](#利点)\n    - [パフォーマンスの最大化](#パフォーマンスの最大化)\n    - [リアクティブな変数の宣言](#リアクティブな変数の宣言)\n        - [初期値の設定](#初期値の設定)\n    - [Observableの値をビュー内で使う](#Observableの値をビュー内で使う)\n    - [更新条件を設定](#更新条件を設定)\n    - [.obsの使いどころ](#.obsの使いどころ)\n    - [List(Rx)に関する補足](#List(Rx)に関する補足)\n    - [なぜ「.value」を使う必要があるのか](#なぜ「.value」を使う必要があるのか)\n    - [Obx()](#obx)\n    - [Worker](#worker)\n  + [非リアクティブな状態管理](#非リアクティブな状態管理)\n    - [利点](#利点)\n    - [使用例](#使用例)\n    - [Controllerインスタンスの扱い](#Controllerインスタンスの扱い)\n    - [StatefulWidgetsはもういらない](#StatefulWidgetsはもういらない)\n    - [Getの目的](#Getの目的)\n    - [Controllerの様々な使用方法](#Controllerの様々な使用方法)\n    - [ユニークIDの設定](#ユニークIDの設定)\n  + [状態管理ソリューションを混在させる](#状態管理ソリューションを混在させる)\n  + [StateMixin](#StateMixin)\n  + [GetBuilder VS GetX VS Obx VS MixinBuilder](#GetBuilder-VS-GetX-VS-Obx-VS-MixinBuilder)\n\n# 状態管理\n\nGetXは他の状態管理ライブラリのように Stream や ChangeNotifier を使用する必要がありません。なぜか？私たちは応答時間とRAM消費量を改善するために GetValueとGetStream という低遅延のソリューションを開発しましたが、状態管理機能を含むGetXのリソースはすべてこれをベースに作られているためです。このソリューションはより低い運用コストと高いパフォーマンスを実現します。GetXを使えばAndroid、iOS、Web、Linux、macOS用のアプリケーションを作成するだけでなく、Flutter/GetXと同じシンタックスでサーバーアプリケーションを作ることができます。\n\n* _バカみたいにシンプル_: 他の状態管理アプローチの中には、複雑で多くのボイラープレートコードを書かなければいけないものもあります。この問題により少なくない人たちがFlutterを見限りましたが、今ようやく、バカみたいにシンプルなソリューションを手に入れることができました。GetXを使えば、非常にすっきりとした、記述量の少ないコードでより多くのことができるようになります。イベントごとにクラスを定義する必要もありません。\n* _コード生成にサヨナラ_: 開発時間の半分はアプリケーションロジックの作成に費やします。それにも関わらず、状態管理ライブラリの中には、ミニマルなコードを作るためにコード生成ツールに依存しているものがあります。変数を変更して build_runner を実行するのは非生産的ですし、flutter clean 後の待ち時間もコーヒーをたくさん飲まなければならないほど長くなることもあります。\n\nGetXはすべてがリアクティブであり、コード生成ツールに依存しないため、開発のあらゆる面において生産性が向上します。\n\n* _context依存にサヨナラ_: ビューとビジネスロジックを連携させるため、ビューのcontextをControllerに送る必要に迫られた。contextがないところで依存オブジェクトの注入をする必要があり、contextを方々のクラスや関数からなんとか渡した。これらの経験、誰もが通ってきた道かと思います。しかし、GetXではこのような経験をすることはありません。contextなしで、Controllerの中から別のControllerにアクセスすることができます。パラメーターを通じて無駄にcontextを送る必要はもうありません。\n* _細かいコントロール_: 多くの状態管理ソリューションは、ChangeNotifierをベースにしています。ChangeNotifierは、notifyListenerが呼ばれたときに、依存するすべてのWidgetに通知します。画面に40個のWidgetがあるとしましょう。それらがすべてChangeNotifierの変数に依存している場合、変数を1つでも更新すれば、すべてのWidgetが更新されます。\n\nGetXを使えばネストされたWidgetさえも的確にビルドを処理することができます。ListViewを担当するObxと、ListViewの中のチェックボックスを担当するObxがあれば、チェックボックスの値を変更した場合はチェックボックスWidgetだけが更新され、Listの値を変更した場合はListViewだけが更新されます。\n\n* _変数が本当に変わったときだけ更新する_: GetXはデータの流れをコントロールします。つまり、Textに紐づいたObservable(監視可能)変数の値 'Paola' を、同じ 'Paola' に変更してもWidgetは更新されません。これは、GetXがTextに'Paola'がすでに表示されていることをわかっているためです。\n\n多くの状態管理ソリューションは、この場合更新を行います。\n\n## リアクティブな状態管理\n\nリアクティブプログラミングは複雑であると言われがちなためか、多くの人に敬遠されています。しかし、GetXはリアクティブプログラミングを非常にシンプルなものにしてくれます。\n\n* StreamControllerを作る必要はありません。\n* 変数ごとにStreamBuilderをセットする必要はありません。\n* 状態ごとにクラスを作る必要はありません。\n* 初期値のためにgetを準備する必要はありません。\n\nGetによるリアクティブプログラミングは、setState並に簡単です。\n\nたとえば name という変数があり、それを変更するたびに変数に依存するすべてのWidgetを自動更新したいとします。\n\nこれがその name 変数です。\n\n``` dart\nvar name = 'Jonatas Borges';\n```\n\nこれをObservable(監視可能)にするには、値の末尾に \".obs\" を付け足すだけです。\n\n``` dart\nvar name = 'Jonatas Borges'.obs;\n```\n\nこれで終わりです。*こんなに* 簡単なんですよ。\n\n(以後、このリアクティブな \".obs\" 変数、Observable(監視可能)を _Rx_ と呼ぶことがあります。)\n\n内部ではこのような処理を行っています: `String`の`Stream`を作成し、初期値`\"Jonatas Borges\"`を割り当て、`\"Jonatas Borges\"`に依存するすべてのWidgetに、あなたは今この変数の影響下にあるから、_Rx_の値が変更されたときには、あなたも同様に変更する必要がある旨を通知。\n\nこれがDartの機能のおかげで実現できた **GetX マジック** です。\n\nしかし皆さんご存知の通り、`Widget` は関数の中にいなければ自らを更新できません。静的クラスには「自動更新」の機能がないからです。\n\nそれなら、同じスコープ内で複数の変数に依存してWidgetをビルドする場合は、複数の `StreamBuilder` をネストして変数の変化を監視する必要がありますね。\n\nいいえ、**GetX** なら `StreamBuilder` すら不要です。\n\nまたWidgetを更新する際のボイラープレートコードについても、**GetX**では忘れてください。\n\n`StreamBuilder( ... )` ? `initialValue: ...` ? `builder: ...` ? これらはすべて不要で、対象のWidgetを `Obx()` の中に入れるだけです。\n\n``` dart\nObx (() => Text (controller.name));\n```\n\n_覚えること？_  それは `Obx(() =>` だけです。\n\nそのWidgetをアロー関数を通じて `Obx()`（_Rx_のObserver(監視者)）に渡すだけです。\n\n`Obx` は非常に賢く、`controller.name` の値が本当に変わったときにのみ、Widgetの更新をかけます。\n\n`name` が `\"John\"` だとして、それを `\"John\"` ( `name.value = \"John\"` ) に変更しても、以前と同じ `value` のため画面上では何も変化しません。`Obx` はリソースを節約するために値を無視し、Widgetを更新しません。**すごいでしょ？**\n\n> では、もしも `Obx` の中に_Rx_（Observable）変数が5つあったらどうでしょう？\n\n5つの**いずれかに**値の変化があればWidgetは更新されます。\n\n> また、1つのControllerクラスに30もの変数がある場合、1つの変数を更新したら変数に関わるWidgetが**すべて**更新されてしまうのでしょうか？\n\nいいえ、_Rx_ 変数を使う特定のWidgetだけが更新されます。\n\n言い換えるなら、**GetX**は _Rx_ 変数の値が変化したときだけ画面更新をしてくれるということです。\n\n```dart\n\nfinal isOpen = false.obs;\n\n// 同じ値なので何も起きません。\nvoid onButtonTap() => isOpen.value=false;\n```\n\n### 利点\n\n**GetX()**は何を更新して何をしないのか、の**細かい**コントロールが可能です。\n\nすべての更新するのでそのようなコントロールが不要な場合は、`GetBuilder` を検討してください。\nこれはわずか数行のコードで作られた、状態更新のためのシンプルなビルダーです。（`setState()`のようにブロックで）\nCPUへの影響を最小限にするために作られており、単一の目的(_状態_ の再構築)を果たすため、可能な限りリソース消費を抑えました。\n\n**強力な** 状態管理のソリューションを求めているなら、**GetX**で間違いはありません。\n\n変数をそのまま扱うことはできませんが、内部では `Stream` としてデータが扱われています。\n\nすべてが `Stream` なので、_RxDart_ を組み合わせることも可能ですし、\n\"_Rx_ 変数\" のイベントや状態を監視することも可能です。\n\nGetXは _MobX_ より簡単で、コード自動生成や記述量を減らした_BLoC_ 型アプローチと言えるかもしれません。\n値の末尾に `.obs` を付けるだけで**なんでも** _\"Observable(監視可能)\"_ にできるのです。\n\n### パフォーマンスの最大化\n\nビルドを最小限に抑えるための賢いアルゴリズムに加えて、\n**GetX**はコンパレーターを使用して状態が変更されたことを確認します。\n\nアプリでなにかしらのエラーが発生し、状態が変更された情報を\n二重に送信してしまったとしても**GetX**はクラッシュを防いでくれます。\n\n**GetX**では値が変化したときにはじめて「状態」が変化するためです。\nこれが **GetX** と _MobX の `computed`_ を使う際の主な違いです。\n2つの __Observable__ を組み合わせて一つが変化したとき、それを監視しているオブジェクトも変化します。\n\nこれは `GetX()` (`Observer()`のようなもの) において2つの変数を組み合わせた場合においても、\nそれが本当に状態の変化を意味するときだけWidgetの更新が行われるということでもあります。\n\n### リアクティブな変数の宣言\n\n変数を \"Observable\" にする方法は3つあります。\n\n1 - **`Rx{Type}`** を使用する\n\n``` dart\n// 初期値を入れることを推奨しますが、必須ではありません\nfinal name = RxString('');\nfinal isLogged = RxBool(false);\nfinal count = RxInt(0);\nfinal balance = RxDouble(0.0);\nfinal items = RxList<String>([]);\nfinal myMap = RxMap<String, int>({});\n```\n\n2 - **`Rx`** とジェネリクスによる型指定の組み合わせ\n\n``` dart\nfinal name = Rx<String>('');\nfinal isLogged = Rx<Bool>(false);\nfinal count = Rx<Int>(0);\nfinal balance = Rx<Double>(0.0);\nfinal number = Rx<Num>(0);\nfinal items = Rx<List<String>>([]);\nfinal myMap = Rx<Map<String, int>>({});\n\n// 任意の型を指定可能 - どんなクラスでもOK\nfinal user = Rx<User>();\n```\n\n3 - 最も実用的で簡単な方法として、**`.obs`** を値に付ける\n\n``` dart\nfinal name = ''.obs;\nfinal isLogged = false.obs;\nfinal count = 0.obs;\nfinal balance = 0.0.obs;\nfinal number = 0.obs;\nfinal items = <String>[].obs;\nfinal myMap = <String, int>{}.obs;\n\n// カスタムクラスのインスタンスにも付けられます\nfinal user = User().obs;\n```\n\n##### 初期値の設定\n\nご存知の通り、_Dart_ は現在 _null safety_ へ移行しているところです。\nそれに備えるために今後は _Rx_ 変数は常に**初期値**を設定してください。\n\n> **GetX** で変数を _Observable_ にしつつ _初期値_ を設定するのはとても簡単です。\n\n変数の末尾に `.obs` を付ける。**それだけ。**\nめでたく Observable とそのプロパティ `.value` (つまり _初期値_)ができました。\n\n### Observableの値をビュー内で使う\n\n``` dart\n// Controllerクラス\nfinal count1 = 0.obs;\nfinal count2 = 0.obs;\nint get sum => count1.value + count2.value;\n```\n\n``` dart\n// ビュークラス\nGetX<Controller>(\n  builder: (controller) {\n    print(\"count 1 rebuild\");\n    return Text('${controller.count1.value}');\n  },\n),\nGetX<Controller>(\n  builder: (controller) {\n    print(\"count 2 rebuild\");\n    return Text('${controller.count2.value}');\n  },\n),\nGetX<Controller>(\n  builder: (controller) {\n    print(\"count 3 rebuild\");\n    return Text('${controller.sum}');\n  },\n),\n```\n\n`count1.value++` を実行すると、以下の通りprintされます。\n\n* `count 1 rebuild`\n\n* `count 3 rebuild`\n\nなぜなら `count1` の値が `1` に変わり、それに伴ってgetter `sum` の値にも `1 + 0 = 1` と変化が起こるからです。\n\n今度は `count2.value++` を実行してみましょう。\n\n* `count 2 rebuild`\n\n* `count 3 rebuild`\n\nもうおわかりですね。これは `count2.value` が変わり、その結果 `sum` が `2` になったからです。\n\n* 注: デフォルト仕様では、`value` に変化がなかったとしても、それが最初のイベントであればWidgetを更新します。\n\n この仕様はbool変数の性質から来るものです。\n\nたとえばこの場合を想像してみてください。\n\n``` dart\nvar isLogged = false.obs;\n```\n\nそして、isLogged(ユーザーがログインしたかどうか)の変化をトリガーにever関数内のコールバックfireRouteを呼び出したいとします。\n\n``` dart\n@override\nonInit() async {\n  // everは引数1が変化するたびに引数2を実行するリスナー\n  ever(isLogged, fireRoute);\n  isLogged.value = await Preferences.hasToken();\n}\n\nfireRoute(logged) {\n  if (logged) {\n   Get.off(Home());\n  } else {\n   Get.off(Login());\n  }\n}\n```\n\nもし `hasToken` が `false` なら `isLogged` に変化はありません。すると `ever()` のコールバックは永遠に呼び出されないことになります。\nこのような挙動を防ぐために _Observable_ への最初の更新は、それがたとえ同じ `.value` だったとしても\n常にイベントを引き起こすようにしています。\n\nご参考までに、この仕様は以下の設定で解除することができます。\n `isLogged.firstRebuild = false;`\n\n### 更新条件を設定\n\nGetにはさらに洗練された「状態」のコントロール方法があります。イベント(Listへのオブジェクト追加など)に対して条件を付けることが可能です。\n\n``` dart\n// 引数1: Listにオブジェクトを加える条件。trueかfalseを返すこと\n// 引数2: 条件がtrueの場合に加える新しいオブジェクト\nlist.addIf(item < limit, item);\n```\n\n最低限のコードで、コード生成ツールも使わず、とても簡単ですね :smile:\n\nカウンターアプリもこのようにシンプルに実現できます。\n\n``` dart\nclass CountController extends GetxController {\n  final count = 0.obs;\n}\n```\n\nControllerを設定して、下記を実行するだけ。\n\n``` dart\ncontroller.count.value++\n```\n\nUIの数字が置き換わりましたね。このようにアプリのどこであっても更新をかけることができます。\n\n### .obsの使いどころ\n\n.obs を使うことでどんなものもObservableにすることができます。方法は2つ。\n\n* クラスのインスタンス変数をobsに変換する\n\n``` dart\nclass RxUser {\n  final name = \"Camila\".obs;\n  final age = 18.obs;\n}\n```\n\n* クラスのインスタンスを丸々obsに変換する\n\n``` dart\nclass User {\n  User({String name, int age});\n  var name;\n  var age;\n}\n\n// インスタンス化の際\nfinal user = User(name: \"Camila\", age: 18).obs;\n```\n\n### List(Rx)に関する補足\n\nList(Rx)はその中のオブジェクトと同様、監視可能(Observable)です。そのためオブジェクトを追加すると、List(Rx)に依存するWidgetは自動更新されます。\n\nまたList(Rx)をListとするために \".value\" を使う必要はありません。DartのAPIがこれを可能にしてくれました。ただ、残念ながら他のStringやintのようなプリミティブ型は拡張ができないため、.value を使う必要があります。getterやsetterを活用するのであればあまり問題になりませんが。\n\n``` dart\n// Controllerクラス\nfinal String title = 'User Info:'.obs\nfinal list = List<User>().obs;\n\n// ビュークラス\nText(controller.title.value), // Stringの場合は .value が必要\nListView.builder (\n  itemCount: controller.list.length // Listの場合は不要\n)\n```\n\nカスタムのクラスをObservableにした場合は、様々な方法で値を更新することができます。\n\n``` dart\n// モデルクラス\n// 属性をobsにするやり方ではなく、クラス全体をobsにする方法を採ります\nclass User() {\n  User({this.name = '', this.age = 0});\n  String name;\n  int age;\n}\n\n// Controllerクラス\nfinal user = User().obs;\n// user変数を更新するときはこのようなメソッドを作ります\nuser.update( (user) { // このパラメーターは更新するオブジェクトそのもの\nuser.name = 'Jonny';\nuser.age = 18;\n});\n// あるいは、この方法でも。変数名は呼び出し可能です。\nuser(User(name: 'João', age: 35));\n\n// ビュークラス\nObx(()=> Text(\"Name ${user.value.name}: Age: ${user.value.age}\"))\n// .value を使わずにモデルのプロパティにアクセスすることも可能です\nuser().name; // userがUserではないことに注目。user()でUserを受け取れます。\n```\n\nListのsetAllやsetRangeメソッドの代わりに、\"assign\" \"assignAll\" APIを使っていただくことも可能です。\n\"assign\" APIはListの内容をクリアした後に、指定した単独のオブジェクトを追加してくれます。\n\"assignAll\" APIはそのIterable版です。\n\n### なぜ「.value」を使う必要があるのか\n\nちょっとしたアノテーションとコード生成ツールを使って`String`や`int`で `.value` を使わなくて済むようにもすることはできますが、このライブラリの目的は「外部依存パッケージを減らす」ことです。私たちは、外部パッケージを必要としない、必須ツール（Route、依存オブジェクト、状態の管理）が揃った開発環境を軽量かつシンプルな方法で提供したいと考えています。\n\nまさに pubspecに3文字（get）とコロンを加えて、プログラミングを始めることができるのです。Route管理から状態管理まで、必要なソリューションが標準装備されています。GetXはシンプルさ、生産性、高いパフォーマンスを目指します。\n\nこれほど多機能であるにも関わらず、このライブラリの総容量は他の多くの状態管理ライブラリよりも少ないです。その点をご理解いただけるとうれしいです。\n\n`.value` が嫌でコード生成ツールを使いたいという方には、MobXは素晴らしいライブラリだと思いますし、Getと併用することもできます。逆に多くの外部パッケージに依存したくない方、パッケージ間の互換性を気にしたくない方、状態管理ツールや依存オブジェクトから状態更新エラーが出ているかどうかを気にせずプログラミングをしたい方、依存するControllerクラスのインスタンスがあるかどうかを都度都度心配したくない方にとってはGetはまさに最適です。\n\nMobXのコード生成や、BLoCのボイラープレートコードが気にならないのであれば、Route管理にだけでもGetをお使いいただけるとうれしいです。GetのSEMとRSMは必要に迫られて生まれたものです。私の会社で以前、90以上のControllerを持つプロジェクトがあり、それなりの性能のマシンでflutter cleanを行った後でさえ、コード生成ツールがタスクを完了するのに30分以上かかりました。もしあなたが大きなプロジェクトに関わっており、コード生成ツールが問題になっているのであれば、Getを検討してみてください。\n\nもちろん、コード生成ツールをGetXに導入したい方が実際にツールを作成してプロジェクトに貢献した場合は、このReadMeに代替ソリューションとして掲載させていただきます。私はすべての開発者のニーズをかなえたいわけではありませんが、今はこの質問に対しては、「すでにMobXのように同様のことを実現してくれる良いソリューションがある」とだけ言わせてください。\n\n### Obx()\n\nGetX()の代わりにObx()を使用することもできます。ObxはWidgetを生成する匿名関数をパラメーターに持ちます。複数のControllerに対応することができますが、自身はControllerのインスタンスを持たず、型指定もできません。そのため別途Controllerのインスタンスを作るか、`Get.find<Controller>()` でインスタンスを探しておく必要があります。\n\n### Worker\n\nWorker はイベント発生に伴って指定したコールバックを呼び出すことができます。\n\n``` dart\n/// `count1` が更新されるたびに第2引数のコールバックが実行される\never(count1, (_) => print(\"$_ has been changed\"));\n\n/// `count1` の最初の更新時のみ実行される\nonce(count1, (_) => print(\"$_ was changed once\"));\n\n/// DDoS攻撃対策に最適。たとえば、ユーザーが打鍵やクリックを止めて1秒後に実行など\ndebounce(count1, (_) => print(\"debouce$_\"), time: Duration(seconds: 1));\n\n/// 1秒以内の連続更新はすべて無視して実行しない\ninterval(count1, (_) => print(\"interval $_\"), time: Duration(seconds: 1));\n```\n\nすべてのWorker(`debounce` 以外) は `condition` パラメーターを持ちます。`condition` は `bool` でも `bool` を返すコールバックでも構いません。\nこの `condition` が Worker のコールバックを実行するかどうかを決めています。\n\nまた Worker は `Worker` インスタンスを返します。これは `dispose()` などを通じて Worker を破棄するときに使用します。\n\n\n* **`ever`**\n\n は _Rx_ 変数が新しい値になるたびに呼ばれます。\n\n* **`everAll`**\n\n `ever` とほぼ同じですが、_Rx_ 変数の `List` を受け取ります。いずれかの値が更新されれば、その更新後の値を受け取ってコールバックが実行されます。\n\n* **`once`**\n\n変数が最初に更新されたときのみに呼ばれます。\n\n* **`debounce`**\n\n'debounce' は検索機能などで導入するととても有益です。たとえば、ユーザーがタイピングを止めたときにのみAPIを呼び出したいときに使います。ユーザーが \"Jonny\" と入れたときに 5回も APIに問い合わせを行うのは避けたいですよね。Getなら \"debounce\" があるので大丈夫です。\n\n* **`interval`**\n\n`interval` は debounce とは異なります。ユーザーが1秒間に1000回変数に変更を加えた場合、debounceが一定期間経過後（デフォルトは800ミリ秒）に最後の変更イベントだけ送信するのに対して、intervalは代わりに一定期間の間のユーザーによるアクションをすべて無視します。intervalは1秒ごとにイベントを送信しており、3秒に設定した場合は1分間に20個のイベントを送信します。これはユーザーがキーやマウスを連打することで何かしらの報酬を得られる場合に、その悪用を避けるために使用できます(ユーザーが何かをクリックしてコインを獲得できるとします。たとえ何秒かかったとしても300回クリックすれば300枚のコインを得ることができてしまいます。intervalを使用してインターバルを3秒に設定した場合は、何回クリックしようが1分間で得られるコインの上限は20枚になります)。一方のdebounceはアンチDDosや、検索のように変更を加えるたびにonChangeからAPI問い合わせが発生するような機能に適しています。ユーザーが入力し終わるのを待ってリクエストを送信するのです。debounceを前述のコイン獲得のケースで使用した場合、ユーザーはコインを1枚しか獲得できません。これは指定した期間、ユーザーが動作を「一時停止」したときにのみ実行されるからです。\n\n* 注: Workerを使用する場合は、Controllerなどを起動するときに次のいずれかの方法で登録する必要があります。onInit（推奨）内、クラスのコンストラクタ、またはStatefulWidgetのinitState内（この方法は推奨しませんが、副作用はないはずです）。\n\n## 非リアクティブな状態管理\n\nGetはChangeNotifierを使わない軽量かつシンプルな状態管理機能を有しています。特にFlutterに慣れていない方のニーズを満たし、大規模なアプリケーションでも問題を起こすことがないと信じています。\n\nGetBuilderは複数の状態を扱う場面で使われることを想定して作られました。たとえばショッピングカートに30個の商品があるとします。そしてあなたが商品を一つ削除すると同時に、カートのリストが更新され、合計金額が更新され、アイテム数を示すバッジが更新されます。GetBuilderはこのようなユースケースに最適です。というのも、GetBuilderは状態をControllerで束ねてそのControllerに依存するすべてのWidgetを一度に更新させることができるからです。\n\nそれらとは独立したControllerが必要な場合は、GetBuilderのidプロパティに専用IDを割り当てるか、GetXを使ってください。ケースバイケースですが、そのような「独立した」Widetが多いほど GetX() のパフォーマンスが際立ち、複数の状態変化がありそれに伴うWidgetの更新が多いほど GetBuilder() のパフォーマンスが勝ることを覚えておいてください。\n\n### 利点\n\n1. 必要なWidgetのみ更新される。\n\n2. ChangeNotifierを使わず、メモリ使用量が少ない。\n\n3. StatefulWidgetのことはもう忘れましょう。Getでは必要ありません。他の状態管理ライブラリではStatefulWidgetを使用することがあるでしょう。しかしAppBarやScaffoldなどクラス内のほとんどのWidgetがStatelessであるにも関わらず、StatefulなWidgetの状態だけを保持する代わりに、クラス全体の状態を保持しているのはなぜでしょうか？Getならクラス全体をStatelessにすることができます。更新が必要なコンポーネントは GetBuilder などで囲むことで「状態」が保持されます。\n\n4. プロジェクトを整理しましょう！ControllerはUIの中にあってはいけません。TextEditControllerなどの類はすべてControllerクラスに配置してしまいましょう。\n\n5. Widgetのレンダリングが開始されると同時にイベントを実行してWidgetを更新させる必要がありますか？GetBuilderにはStatefulWidgetと同様の「initState」プロパティがあり、そこからControllerのイベントを直接呼び出すことができます。initStateを使用する必要はもうありません。\n\n6. StreamやTimerのインスタンスを破棄したい場合はGetBuilderのdisposeプロパティを利用してください。Widgetが破棄されると同時にイベントを呼び出すことができます。\n\n7. GetXとStreamController / StreamBuilderを組み合わせるなどしてStreamを普通に使っていただいても問題ありませんが、必要なときに限って使うことをおすすめします。Streamのメモリ消費は適度であり、リアクティブプログラミングは美しいですが、たとえば30ものStreamを同時に立ち上げることを考えてみてください。これはChangeNotifierを使うよりもよくないことのように思います。\n\n8. 必要以上にRAMを使わずWidgetを更新します。GetはGetBuilderのクリエーターIDのみを保存し、必要に応じてGetBuilderを更新します。何千ものGetBuilderを作成したとしても、ID保存のためのメモリ消費量は非常に少ないです。GetBuilderを新規に作成するということは、実際にはクリエーターIDを持つ GetBuilder の状態を共有しているに過ぎないためです。GetBuilderごとに状態が新たに作成されるわけではないため、特に大規模なアプリケーションでは多くのRAMを節約できます。基本的にGetXで作成するアプリケーションは全体的にStatelessであり、いくつかのStatefulなWidget(GetBuilder内のWidget)は単一の状態を持っているため、一つを更新すればすべてが更新されます。\n\n9. Getはアプリ全体の流れをよく把握しており、Controllerをメモリから破棄するタイミングを正確に知っています。実際の破棄はGetがやってくれるため、開発者が心配する必要はありません。\n\n### 使用例\n\n``` dart\n// Controllerクラスを作成してGetxControllerを継承しましょう\nclass Controller extends GetxController {\n  int counter = 0;\n  void increment() {\n    counter++;\n    update();\n    // increment 実行時にcounter変数に依存するUIを更新。\n    // GetBuilderを使うWidgetの場合はupdate()が必要。\n  }\n}\n// ビュー側のクラスでGetBuilderを使ってcounter変数を組み込む\nGetBuilder<Controller>(\n  init: Controller(), // 最初に使用するときのみ初期化\n  builder: (_) => Text(\n    '${_.counter}',\n  ),\n)\n// Controllerの初期化は最初の1回だけ行ってください。同じControllerを再度 GetBuilder / GetX で使用する場合は初期化する必要はありません。コントローラは、それを「init」とマークしたウィジェットがデプロイされると同時に、自動的にメモリから削除されます。Getがすべて自動で行ってくれるので、何も心配することはありません。同じControllerを2つ立ち上げることがないよう、それだけご注意ください。\n```\n\n**最後に**\n\n* 以上、Getを使った状態管理の手法をご説明させていただきました。\n\n* 注: もっと柔軟に管理する手法として、initプロパティを使わない方法もあります。Bindingsを継承したクラスを作成し、dependenciesメソッドをoverrideしてその中でGet.put()でControllerを注入してください(複数可)。このクラスとUI側のクラスを紐づけることでControllerをそのRoute内で使用できます。そしてそのControllerを初めて使用するとき、Getはdependencies内を見て初期化を実行してくれます。このlazy(遅延、消極的)ロードを維持しつつ、不要になったControllerは破棄し続けます。具体的な仕組みについてはpub.devの例をご参照ください。\n\nRouteを移動して以前使用したControllerのデータが必要になった場合は、再度GetBuilderを使用してください。initする必要はありません。\n\n``` dart\nclass OtherClass extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      body: Center(\n        child: GetBuilder<Controller>(\n          builder: (s) => Text('${s.counter}'),\n        ),\n      ),\n    );\n  }\n\n```\n\nGetBuilderの外でControllerを使用する場合は、Controller内にgetterを作成しておくと便利です。Controller.to で呼び出しましょう。(もしくは `Get.find<Controller>()` を使うのもありです)\n\n``` dart\nclass Controller extends GetxController {\n\n  /// 記述量を省くためにstaticメソッドにすることをおすすめします。\n  /// staticメソッド使う場合 → Controller.to.increment();\n  /// 使わない場合 → Get.find<Controller>().increment();\n  /// どちらを使ってもパフォーマンスに影響があったり副作用が出たりはしません。前者は型の指定が不要という違いがあるだけです\n  static Controller get to => Get.find(); // これを追加\n\n  int counter = 0;\n  void increment() {\n    counter++;\n    update();\n  }\n}\n```\n\nこれで以下のようにControllerに直接アクセスできます。\n\n``` dart\nFloatingActionButton(\n  onPressed: () {\n    Controller.to.increment(),\n  } // とっても簡単ですね！\n  child: Text(\"${Controller.to.counter}\"),\n),\n```\n\nFloatingActionButton を押すと counter変数 に依存するWidgetがすべて自動的に更新されます。\n\n### Controllerインスタンスの扱い\n\n次のような画面の流れがあるとします。\n\n `画面A => 画面B (Controller X を使用) => 画面C (Controller X を使用)`\n\n画面Aの段階ではまだ未使用なので、Controllerはメモリにありません(Getは基本lazyロードなので)。画面Bに遷移すると、Controllerがメモリ内に保存されます。画面Cでは画面Bと同じControllerを使用しているため、GetはBとCでControllerの状態を共有し、同じControllerがメモリ内に引き続きいることになります。画面Cを閉じてさらに画面Bを閉じ、画面Aに戻ったとしましょう。そこではControllerが使われていないため、GetはControllerをメモリから出してリソースを解放します。そこで再度画面Bに遷移すると、Controllerは再度メモリに保存されます。そして今度は画面Cに行かずに画面Aに戻ります。Getは同様にControllerをメモリから破棄してくれます。また、仮に画面CがControllerを使っておらず画面Cにいたとして、画面BをRouteスタックから削除したとしましょう。するとControllerを使用している画面(クラス)はなくなりますので、同様にメモリから破棄されます。Getが正常動作しないと考えられる唯一の例外は、画面Cにいるときに画面Bを誤ってRouteスタックから削除してしまい、Controllerの使用を試みたときです。この場合は、画面Bで作成されたControllerのクリエーターIDが削除されてしまったことが原因です(GetはクリエーターIDのないControllerはメモリから破棄するようプログラムされています)。もし意図があってこの事例に対応したい場合は、画面BのGetBuilderに \"autoRemove: false\" フラグを追加した上で、CクラスのGetBuilderに \"adoptID: true\" を追加してください。\n\n### StatefulWidgetsはもういらない\n\nStatefulWidgetsを使用すると、画面全体の状態を不必要に保存することになります。ウィジェットを最小限に再構築する必要がある場合は、Consumer/Observer/BlocProvider/GetBuilder/GetX/Obxの中に埋め込むことになりますが、それは別のStatefulWidgetになります。\nStatefulWidgetはStatelessWidgetよりも多くのRAMが割り当てられます。これは1つや2つのStatefulWidgetでは大きな違いは産まないかもしれませんが、それが100もあった場合は確実に違いが出ます。\nTickerProviderStateMixinのようなMixinを使用する必要がない限り、GetでStatefulWidgetを使用する必要はありません。\n\nたとえばinitState()やdispose()メソッドなど、StatefulWidgetのメソッドをGetBuilderから直接呼び出すことも可能です。\n\n``` dart\nGetBuilder<Controller>(\n  initState: (_) => Controller.to.fetchApi(),\n  dispose: (_) => Controller.to.closeStreams(),\n  builder: (s) => Text('${s.username}'),\n),\n```\n\nしかし、これよりもベターなアプローチはControllerの中で直接 onInit() や onClose() メソッドを呼び出すことです。\n\n``` dart\n@override\nvoid onInit() {\n  fetchApi();\n  super.onInit();\n}\n```\n\n* 注: コンストラクタを通じてControllerを立ち上げる必要はありません。このようなプラクティスは、パフォーマンス重視であるGetのControllerの作成や割り当ての原理、考え方から外れてしまいます（コンストラクタ経由でインスタンスを作成すれば、実際に使用される前の段階でControllerを生成し、メモリを割り当てることになります）。onInit() と onClose() メソッドはこのために作られたもので、Controllerのインスタンスが作成されたとき、または初めて使用されたときに呼び出されます（Get.lazyPutを使用しているか否か次第）。たとえば、データを取得するためにAPIを呼び出したい場合は initState/dispose の代わりに onInit() を使用し、Streamを閉じるなどのコマンドを実行する必要がある場合は onClose() を使用してください。\n\n### Getの目的\n\nこのパッケージの目的は、Routeのナビゲーション、依存オブジェクトと状態の管理のための完全なソリューションを、開発者が外部パッケージに\b極力依存せずに済むような形で提供し、高度なコード分離性（デカップリング）を実現することです。それを確実なものとするため、Getはあらゆる高レベルおよび低レベルのFlutter APIを取り込んでいます。これによりビューとロジックを切り分けることが容易になり、UIチームにはWidgetの構築に集中してもらい、ビジネスロジック担当チームにはロジックに集中してもらうことができます。Getを使うことでよりクリーンな作業環境を構築することができるのです。\n\n要するに、initState内でメソッドを呼び出してパラメーターを通じてControllerにデータを送信する必要も、そのためにControllerのコンストラクタを使用する必要もありません。Getには必要なタイミングでサービスを呼び出してくれう onInit() メソッドがあります。\nControllerが不要になれば、onClose() メソッドがジャストなタイミングでメモリから破棄してくれます。これにより、ビューとビジネスロジックを分離することができるのです。\n\nGetxController 内に dispose() メソッドがあっても何も起こらないので記述しないでください。ControllerはWidgetではないので「dispose」できません。たとえばController内でStreamを使用していてそれを閉じたい場合は、以下のように onClose() メソッドにコードを記述してください。\n\n``` dart\nclass Controller extends GetxController {\n  StreamController<User> user = StreamController<User>();\n  StreamController<String> name = StreamController<String>();\n\n  /// Streamを閉じる場合は dispose() ではなく onClose()\n  @override\n  void onClose() {\n    user.close();\n    name.close();\n    super.onClose();\n  }\n}\n```\n\nControllerのライフサイクルについて。\n\n* onInit() はControllerが作成されたタイミングで実行されます。\n* onClose() は onDelete() メソッドが実行される直前のタイミングで実行されます。\n* Controllerが削除されるとそのAPIにアクセスすることはできません。文字通りメモリからの削除だからです。削除のトレースログも残りません。\n\n### Controllerの様々な使用方法\n\nControllerインスタンスはGetBuilderのvalueを通じて使用することができます。\n\n``` dart\nGetBuilder<Controller>(\n  init: Controller(),\n  builder: (value) => Text(\n    '${value.counter}', // ここ\n  ),\n),\n```\n\nGetBuilderの外でControllerインスタンスを使う場合は、このアプローチをおすすめします。\n\n``` dart\nclass Controller extends GetxController {\n  static Controller get to => Get.find();\n[...]\n}\n// ビュー側で\nGetBuilder<Controller>(\n  init: Controller(), // 最初に使うときだけ必要\n  builder: (_) => Text(\n    '${Controller.to.counter}', // ここ\n  )\n),\n```\n\nもしくは\n\n``` dart\nclass Controller extends GetxController {\n // static get を省き、\n[...]\n}\n// ビュー側で\nGetBuilder<Controller>(\n  init: Controller(), // 最初に使うときだけ必要\n  builder: (_) => Text(\n    '${Get.find<Controller>().counter}', // ここ\n  ),\n),\n```\n\n* get_it や modular など他の依存オブジェクト管理ライブラリを使用しているため、単にControllerのインスタンスを渡したいだけの場合は、このような「非正規」な方法もあります。\n\n``` dart\nController controller = Controller();\n[...]\nGetBuilder<Controller>(\n  init: controller, // ここ\n  builder: (_) => Text(\n    '${controller.counter}', // ここ\n  ),\n),\n\n```\n\n### ユニークIDの設定\n\nGetBuilderを使ってWidgetの更新をコントロールしたい場合は、このようにユニークIDを振ってください。\n\n``` dart\nGetBuilder<Controller>(\n  id: 'text'\n  init: Controller(), // 最初に使うときだけ必要\n  builder: (_) => Text(\n    '${Get.find<Controller>().counter}', // ここ\n  ),\n),\n```\n\nそして以下のようにWidgetを更新します。\n\n``` dart\nupdate(['text']);\n```\n\nさらに更新に条件を設けることができます。\n\n``` dart\nupdate(['text'], counter < 10);\n```\n\nGetXはこの更新を自動で行ってくれます。指定したIDを持ち、その変数に依存するWidgetのみを更新します。また変数を前の値と同じ値に変更しても、それが状態の変化を意味しない場合はメモリとCPUサイクルを節約するためにWidgetを更新しません (画面に 3 が表示されているときに、変数を再び 3 に変更したとします。このような場合にWidgetを更新する状態管理ソリューションも存在しますが、GetXでは実際に状態が変更された場合にのみ更新されます）。\n\n## 状態管理ソリューションを混在させる\n\nMixinBuilderはObxとGetBuilderを併用したいというリクエストから発想して作られました。これは \".obs\" 変数の変更によるリアクティブな更新と、update() メソッドによるメカニカルな更新の両方を混在可能にします。ただし、GetBuiler / GetX / Obx / MixinBuilder の4つの中で最もリソースを消費するWidgetです。というのも、Widgetからのイベントを検知するためのSubscriptionに加えて、Controller自身のupdateメソッドも購読する必要があるからです。\n\nMixinBuilderに使用するControllerクラスには、変数を `.obs`（Observable）とするかどうかに関わらず、GetxControllerを継承したものを使用してください。GetxControllerにはライフサイクルがあり、onInit() および onClose() メソッドでイベントを「開始」したり「終了」したりすることができます。\n\n## StateMixin\n\n`StateMixin<T>` を使うことでさらに `UI` の「状態」を便利に扱うことができます。\n`with` を使って `StateMixin<T>` をControllerにミックスインしてください。Tにはモデルのクラス名が入ります。\n\n``` dart\nclass Controller extends GetController with StateMixin<User>{}\n```\n\n状態を変更するには `change()` メソッドを使ってください。\nパラメーターにはビューに渡すデータと「状態」をセットします。\n\n```dart\nchange(data, status: RxStatus.success());\n```\n\nRxStatus の「状態」は以下の4つです。\n\n``` dart\nRxStatus.loading(); // ロード中\nRxStatus.success(); // ロード成功\nRxStatus.empty(); // データが空\nRxStatus.error('message'); // エラー\n```\n\nそれぞれの「状態」をUIで表すには以下のようにします。\n\n```dart\nclass OtherClass extends GetView<Controller> {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n\n      body: controller.obx(\n        (state)=>Text(state.name),\n\n        // ここはカスタムのロードインジケーターでも可能ですが、\n        // デフォルトは Center(child:CircularProgressIndicator())\n        onLoading: CustomLoadingIndicator(),\n        onEmpty: Text('No data found'),\n\n        // ここもカスタムのエラーWidgetでも構いませんが、\n        // デフォルトは Center(child:Text(error))\n        onError: (error)=>Text(error),\n      ),\n    );\n}\n```\n\n## GetBuilder VS GetX VS Obx VS MixinBuilder\n\n私は10年間プログラミングに携わってきて、いくつか貴重な教訓を得ることができました。\n\nリアクティブプログラミングに初めて触れたとき、「おお、これはすごい」と感嘆せずにはいられませんでしたし、実際にすごいものでした。\nしかし、リアクティブプログラミングはすべての状況に適しているわけではありません。多くの場合、必要なのは2,3のWidgetの状態を同時に更新すること、またはローカルでの一時的な状態の変更であり、これらの場合はリアクティブである必要はありません。\n\nリアクティブプログラミングのRAM消費量の多さは、必要なときだけ、かつ1つのWidgetだけ同時に更新するようすることである程度補うことができます。ただ、たとえば80ものオブジェクトを持つリストがあったとして、それぞれが複数のStreamを持つのは得策ではありません。Dartのインスペクターを開いて、StreamBuilderがどれだけRAMを消費しているか見てみてください。私が伝えたいことを理解してもらえると思います。\n\nそのことを念頭に私はシンプルな状態管理ソリューションを作りました。このシンプルさに期待することは、リソース面で経済的である点、Widget単位ではなくブロック単位で状態を更新できる点であるべきです。\n\nGetBuilderはRAM消費の面で最も経済的なソリューションだと信じています（もしあれば、ぜひ教えてください）。\n\nしかし、GetBuilderは依然として update() により更新がかかるスタイルのメカニカルな状態管理ソリューションであり、notifyListeners() と呼び出し回数は変わりありません。\n\n一方で、ここでリアクティブプログラミングを使わないのは車輪の再発明なんじゃないかと思えるような状況もあります。この点を考慮して、GetX() は先進的な状態管理の手法を提供するために作られました。必要なものを必要なときだけ更新し、エラーが発生してユーザーが300ものイベントを同時に送信したとしても、GetX() は状態の変化をフィルタリングして画面を更新してくれます。\n\nGetX() は他のリアクティブな状態管理ソリューションに比べて経済的であることに変わりはありませんが、GetBuilder() よりは少しだけ多くのRAMを消費します。その点を考慮し、リソース消費を最大限活かすことを目指して Obx() は開発されました。GetX() や GetBuilder() と異なり、Obx() の中でControllerを初期化することはできません。Obx() は、子Widgetからの更新イベントを受け取る Stream購読Widgetでしかありません。GetX() よりは経済的ですが、GetBuilder() には負けます。GetBuilder() はWidgetのハッシュ値と状態のsetterを保持しているだけなので、これはある意味当然です。Obx() はControllerの型を指定する必要がなく、複数の異なるコントローラからの変更を聞くことができます。ただし、Obx() の外かBindingsで事前にControllerを初期化しておく必要があります。\n"
  },
  {
    "path": "documentation/kr_KO/dependency_management.md",
    "content": "# 종속성 관리\n- [종속성 관리](#종속성-관리)\n  - [인스턴스 메서드](#인스턴스-메서드)\n    - [Get.put()](#getput)\n    - [Get.lazyPut](#getlazyput)\n    - [Get.putAsync](#getputasync)\n    - [Get.create](#getcreate)\n  - [인스턴스화 된 메서드/클래스 사용](#인스턴스화-된-메서드/클래스-사용)\n  - [메서드간의 차이점](#메서드간의-차이점)\n  - [바인딩](#바인딩)\n    - [사용 방법](#사용-방법)\n    - [BindingsBuilder](#bindingsbuilder)\n    - [SmartManagement](#smartmanagement)\n      - [변경하는 방법](#변경하는-방법)\n      - [SmartManagement.full](#smartmanagementfull)\n      - [SmartManagement.onlyBuilders](#smartmanagementonlybuilders)\n      - [SmartManagement.keepFactory](#smartmanagementkeepfactory)\n    - [바인딩이 작동하는 자세한 설명](#바인딩이-작동하는-자세한-설명)\n  - [주석](#주석)\n\nGet은 Provider context, inheritedWidget 없이 단 1줄의 코드로 Bloc 나 Controller 같은 클래스를 찾을수 있는 간단하고 강력한 종속성 관리자가 있습니다.\n\n```dart\nController controller = Get.put(Controller()); // Controller controller = Controller(); 대체\n```\n\n사용중인 클래스 내에서 클래스를 인스턴스화하는 대신 Get 인스턴스 내에서 인스턴스화하여 앱 전체에서 사용할 수 있습니다.\n그러고나면 컨트롤러 (또는 Bloc 클래스)를 정상적으로 사용할 수 있습니다.\n\n- 주석: Get의 상태 관리자를 사용하는 경우 [바인딩](#바인딩) api에 더 많은 주의를 기울여야합니다. 그러면 뷰를 컨트롤러에 더 쉽게 연결할 수 있습니다.\n- 주석²: Get의 종속성 관리는 패키지의 다른 부분에서 분리되므로 예를 들어 앱이 이미 상태 관리자를 사용하고있는 경우라도(하나라도 상관 없음) 변경할 필요가 없습니다. 아무 문제 없이 종속성 주입 관리자를 사용할 수 있습니다.\n\n## 인스턴스 메서드\n메서드와 구성 파라미터는 다음과 같습니다:\n\n### Get.put()\n\n종속성 인스턴스화의 가장 흔한 방법 입니다. 예를 들어 뷰의 controller들에 좋습니다.\n\n```dart\nGet.put<SomeClass>(SomeClass());\nGet.put<LoginController>(LoginController(), permanent: true);\nGet.put<ListItemController>(ListItemController, tag: \"some unique string\");\n```\n\nput 사용시 설정 가능한 모든 사항:\n```dart\nGet.put<S>(\n  // 필수: cotroller나 어떤것이든 get에 저장하려는 클래스  \n  // 주석: \"S\"는 모든 유형의 클래스가 가능합니다.\n  S dependency\n\n  // 선택: 동일한 유형의 여러 클래스를 사용하기를 원하면\n  // 일반적으로 Get.find<Controller>() 로 클래스를 가져오므로\n  // 어떤 인스턴스인지 구분을 위해 tag를 사용해야합니다.\n  // 고유한 string 이여야 합니다.\n  String tag,\n\n  // 선택: 기본적으로 get은 더이상 사용하지 않는 인스턴스는 dispose 합니다. by default, get will dispose instances after they are not used anymore (example,\n  // (예를 들어 뷰의 controller가 닫힌 경우) 하지만 sharedPreferences와 같은 인스턴스는 앱 전체에서 유지되어야 할 필요가 있습니다.\n  // 이런 경우 사용합니다.\n  // 기본값은 false\n  bool permanent = false,\n\n  // 선택: 테스트에서 추상 클래스를 사용한 후에 다른 클래스로 교체하고 테스트를 수행합니다.\n  // 기본값은 false\n  bool overrideAbstract = false,\n\n  // 선택: 자체 종속성 대신에 함수로 종속성을 생성합니다.\n  // 이것은 일반적으로 사용되지 않습니다.\n  InstanceBuilderCallback<S> builder,\n)\n```\n\n### Get.lazyPut\n인스턴스를 사용하는 경우에만 의존성을 lazyLoad 할 수 있습니다. 계산 비용이 많이 드는 클래스나 한곳에서 다양한 클래스를 당장 사용하지 않으면서 인스턴스화 하기를 원한다면(Bindings 클래스처럼) 매우 유용합니다.\n\n```dart\n/// ApiMock은 처음으로 Get.find<ApiMock>을 사용하는 경우에만 호출됩니다.\nGet.lazyPut<ApiMock>(() => ApiMock());\n\nGet.lazyPut<FirebaseAuth>(\n  () {\n    // 어떤 로직이 필요하다면 ...\n    return FirebaseAuth();\n  },\n  tag: Math.random().toString(),\n  fenix: true\n)\n\nGet.lazyPut<Controller>( () => Controller() )\n```\n\nlazyPut을 사용시 설정 가능한 모든 사항:\n```dart\nGet.lazyPut<S>(\n  // 필수: 이 메서드는 처음으로 클래스가 호출할 때 실행될 것입니다.\n  InstanceBuilderCallback builder,\n  \n  // 선택: Get.put()과 같이 같은 클래스를 다중으로 인스턴스할 경우 사용합니다.\n  // 고유값이어야 합니다.\n  String tag,\n\n  // 선택: \"permanent\"와 유사합니다. 차이점은 인스턴스가 사용되지 않으면 폐기되지만\n  // 다시 사용할 때 Get이 바인딩 api의 \"SmartManagement.keepFactory\"와 동일하게 인스턴스를 재생성한다는 것입니다.\n  // 기본값은 false\n  bool fenix = false\n  \n)\n```\n\n### Get.putAsync\n만약 비동기로 인스턴스를 등록하길 원하면 `Get.putAsync`를 사용할 수 있습니다.:\n\n```dart\nGet.putAsync<SharedPreferences>(() async {\n  final prefs = await SharedPreferences.getInstance();\n  await prefs.setInt('counter', 12345);\n  return prefs;\n});\n\nGet.putAsync<YourAsyncClass>( () async => await YourAsyncClass() )\n```\n\nputAsync 사용시 설정 가능한 모든 사항:\n```dart\nGet.putAsync<S>(\n\n  // 필수: 클래스를 인스턴스화 하기 위해 실행되는 비동기 메서드입니다.\n  AsyncInstanceBuilderCallback<S> builder,\n\n  // 선택: Get.put()과 같이 같은 클래스를 다중으로 인스턴스할 경우 사용합니다.\n  // 고유값이어야 합니다.\n  String tag,\n\n  // 선택: Get.put()과 같이 앱 유지중에 인스턴스가 활성되어야 하는 경우 사용합니다.\n  // 기본값은 false\n  bool permanent = false\n)\n```\n\n### Get.create\n\n이것은 까다롭습니다. 이것이 무엇인지 상세한 설명과 다른것과의 차이점에 대해서는 [메서드간의 차이점:](#메서드간의-차이점) 섹션에서 확인할 수 있습니다.\n\n```dart\nGet.Create<SomeClass>(() => SomeClass());\nGet.Create<LoginController>(() => LoginController());\n```\n\ncreate 사용 시 설정 가능한 모든 사항:\n\n```dart\nGet.create<S>(\n  // 필수: `Get.find()`가 호출 될 때마다 만들어진 클래스를 반환하는 메서드입니다.\n  // 예시: Get.create<YourClass>(() => YourClass())\n  FcBuilderFunc<S> builder,\n\n  // 선택: Get.put()과 거의 동일하지만 동일 클래스의 여러 인스턴스가 필요할 때 사용합니다.\n  // 개개의 리스트별로 controller가 필요한 경우 유용합니다.\n  // 고유값이어야 합니다. 단지 tag에서 name으로 변경되었습니다.\n  String name,\n\n  // 선택: Get.put()과 같이 앱 유지중에 인스턴스가 활성되어야 하는 경우 사용합니다.\n  // Get.create에서 다른점은\n  // permanent의 기본값이 true 입니다.\n  bool permanent = true\n```\n\n## 인스턴스화 된 메서드/클래스 사용\n\n여러 경로를 탐색했고 controller에 남겨진 데이터가 필요하다고 상상해보세요. Provider 또는 Get_it과 결합된 상태 관리자가 필요합니다. 맞습니까? Get은 아닙니다.\n어떤 종속적인 추가가 필요 없고 단지 Get에게 controller를 \"find\"하라고 하면 됩니다:\n\n```dart\nfinal controller = Get.find<Controller>();\n// OR\nController controller = Get.find();\n\n// 그렇습니다. 마법 같아요. Get은 controller를 찾아 가져다 줍니다.\n// Get은 백만개의 contrller를 인스턴스화해서 가질수 있고 항상 올바르게 전달해 줍니다.\n```\n\n그리고 나서 얻어낸 controller에서 데이터를 가져올 수 있습니다:\n\n```dart\nText(controller.textFromApi);\n```\n\n반환된 값은 일반 클래스라서 무엇이든 할 수 있습니다:\n\n```dart\nint count = Get.find<SharedPreferences>().getInt('counter');\nprint(count); // out: 12345\n```\n\nGet의 인스턴스에서 삭제합니다:\n\n```dart\nGet.delete<Controller>(); // 보통 GetX는 미사용 controller를 삭제하기 때문에 수행할 필요가 없습니다\n```\n\n## 대체 인스턴스 지정\n\n현재 추가된 인스턴스는 `replace` 또는 `lazyReplace` 메소드를 사용하여 유사하거나 확장된 클래스 인스턴스로 교체할 수 있습니다. 이후 원본 클래스를 사용하여 찾을 수 있습니다.\n```dart\nabstract class BaseClass {}\nclass ParentClass extends BaseClass {}\n\nclass ChildClass extends ParentClass {\n  bool isChild = true;\n}\n\n\nGet.put<BaseClass>(ParentClass());\n\nGet.replace<BaseClass>(ChildClass());\n\nfinal instance = Get.find<BaseClass>();\nprint(instance is ChildClass); //true\n\n\nclass OtherClass extends BaseClass {}\nGet.lazyReplace<BaseClass>(() => OtherClass());\n\nfinal instance = Get.find<BaseClass>();\nprint(instance is ChildClass); // false\nprint(instance is OtherClass); //true\n```\n\n\n## 메서드간의 차이점\n\n첫째, Get.lazyPut의 `fenix`와 다른 메서드들의 `permanent`을 살펴보겠습니다.\n\n`permanent`와 `fenix` 사이의 근본적인 차이점은 인스턴스를 저장하는 방법입니다.\n\n추가 내용: 기본적으로 GetX는 사용하지 않을때 인스턴스를 삭제합니다.\n이것은 다음을 의미합니다: 만약 화면 1이 컨트롤러 1을 가지고 있고 화면 2가 컨트롤러 2를 가졌을때 스택에서 첫번째 경로가 제거되면(`Get.off()`나 `Get.offNamed()`를 사용했을 때처럼) 컨트롤러 1은 더이상 사용되지 않기 때문에 지워질 것입니다.\n\n하지만 `permanent:true`를 설정하면 컨트롤러가 화면이 바뀌는동안 사라지지 않을 것입니다. 즉, 전체 어플리케이션이 실행되는 동안에 계속 유지하려고 하는 서비스에 매우 유용합니다.\n\n반면 `fenix`는 화면이 바뀌는동안 컨트롤러가 사라지는 것은 상관없지만, 컨트롤러가 필요한 시점에 살아있어야 하는 서비스를 위해 존재합니다. 그래서 기본적으로는 사용하지 않는 컨트롤러/서비스/클래스를 폐기하지만, 필요한 경우 새 인스턴스를 \"남아있는 흔적으로부터 다시 생성\"합니다.\n\n메서드간 차이점에 대해:\n\n- Get.put과 Get.putAsync는 동일한 생성 명령을 따르지만 두번째가 비동기 메서드를 사용하는 것이 차이점입니다: 두 메서드는 인스턴스를 생성하고 초기화 합니다. 이것은 `permanent: false`와 `isSingleton: true` 파라미터들과 내부 `insert` 메서드를 사용하여 메모리에 직접 추가됩니다.(여기의 isSingleton 파라미터의 목적은 `dependency`에 의한 종속성을 사용할 것인지 `FcBuilderFunc`에 의한 종속성을 사용할 것인지 알려주는 것입니다.) 이후에 `Get.find()`는 즉시 초기화한 메모리안의 인스턴스를 호출합니다.\n\n- Get.create: 이름 그대로 종속성을 \"생성\"합니다! `Get.put()`과 마찬가지로 내부 메서드 `insert`를 호출하여 인스턴스화 합니다. 그러나 `permanent`가 true가 되고 `isSingleton`이 false가 됩니다(종속성을 \"생성중\"인 상태라 싱글톤 인스턴스가 될 방법이 없어서 false 입니다.) 그리고 `permanent: true`이기 때문에 기본적으로 화면 전환간에 손실되지 않는 장점이 있습니다! 또한 `Get.find()`는 즉시 호출되지 않으며 호출될 화면에서 사용되기를 기다립니다. `permanent` 파라미터를 사용하기 위한 방법으로 만들어졌습니다. 다음의 가치를 가지고 있습니다. 생성을 위한 목적으로 `Get.create()`는 공유되는 인스턴스가 아니지만 폐기되지 않습니다. 예를들어 리스트뷰 안의 버튼은 리스트를 위한 고유한 인스턴스입니다. - 이때문에 Get.create는 GetWidget과 함께 사용되어야만 합니다.\n\n- Get.lazyPut: 이름 그대로 lazy 처리됩니다. 인스턴스가 만들어지나 즉시 사용되도록 호출되지 않고 호출되기를 기다립니다. 다른 메서드와 다르게 `insert`가 여기에서 호출되지 않습니다. 대신 인스턴스는 메모리의 다른 부분에 추가됩니다. 인스턴스가 재생성 가능한지 아닌지를 책임지는 부분으로 \"factory\"라고 부릅니다. 나중에 사용할 어떤 것을 생성하기 원한다면 지금 사용했던 것과 섞이지 않아야 할 것입니다. 그리고 여기에서 `fenix` 마법이 시작됩니다: `fenix: false`를 그대로두고 `smartManagement`는 `keepFactory`가 아니면 `Get.find`를 사용할 때 인스턴스는 \"factory\"에서 공통 인스턴스 메모리 영역으로 위치가 변경됩니다. 바로 그뒤에 기본적으로 \"factory\"에서 제거됩니다. 이제 `fenix: true`로 설정하면 인스턴스는 전용부분에서 계속 존재하며 공통 영역으로 이동하여 미래에 다시 호출됩니다.\n\n## 바인딩\n\n이 패키지의 가장 큰 특이한점 중 하나는 아마도 라우트, 상태 관리자, 종속성 관리자의 완전한 통합의 가능성 일 것입니다.\n스택에서 라우트가 삭제되면 모든 컨트롤러, 변수 및 관련된 인스턴스 오브젝트가 메모리에서 제거됩니다. 스트림이나 타이머를 사용중이면 자동적으로 종료되고 이것에 대한 어떤 걱정도 할 필요가 없습니다.\nGet의 2.10 버전에는 Bindings API를 완전히 구현했습니다.\n이제 init 메서드는 더 이상 사용할 필요가 없습니다. 원하지 않으며 컨트롤러 타입도 필요 없습니다. 컨트롤러와 서비스를 위한 적절한 위치에서 시작할 수 있습니다.\n바인딩 클래스는 상태 관리자와 종속성 관리자에 라우트를 \"결합\"하는 동시에 종속성 주입을 분리하는 클래스입니다.\n이를 통해 Get은 특정 컨트롤러가 사용될때 표시되는 스크린을 알고 어디서 어떻게 이것이 제거 되는지 알수 있습니다.\n추가로 Binding 클래스로 SmartManager 구성을 제어 할 수 있습니다. 스택에서 경로를 제거하거나 경로를 사용한 위젯이 배치되거나 둘 다 배치되지 않을 때 정렬되도록 종속성을 설정 할 수 있습니다. 지능적으로 종속성 관리가 동작하지만 원하는대로 구성 할 수 있습니다.\n\n### 사용 방법\n\n- class를 생성하고 Binding을 implement 합니다.\n\n```dart\nclass HomeBinding implements Bindings {}\n```\n\nIDE가 자동적으로 \"종속적인\" 메서드를 오버라이딩할지 요청하며 램프를 클릭하기만 하면 됩니다. 그리고 메서드를 오버라이딩하고 해당 경로에 사용할 모든 클래스들을 추가하면 됩니다:\n\n```dart\nclass HomeBinding implements Bindings {\n  @override\n  void dependencies() {\n    Get.lazyPut<HomeController>(() => HomeController());\n    Get.put<Service>(()=> Api());\n  }\n}\n\nclass DetailsBinding implements Bindings {\n  @override\n  void dependencies() {\n    Get.lazyPut<DetailsController>(() => DetailsController());\n  }\n}\n```\n\n이제 라우트에 라우트, 종속성, 상태 관리자 사이를 연결하는데 해당 바인딩을 사용할 것이라고 알리기만 하면 됩니다.\n\n- 명명된 라우트 사용법:\n\n```dart\ngetPages: [\n  GetPage(\n    name: '/',\n    page: () => HomeView(),\n    binding: HomeBinding(),\n  ),\n  GetPage(\n    name: '/details',\n    page: () => DetailsView(),\n    binding: DetailsBinding(),\n  ),\n];\n```\n\n- 일반 라우트 사용법:\n\n```dart\nGet.to(Home(), binding: HomeBinding());\nGet.to(DetailsView(), binding: DetailsBinding())\n```\n\n이제 어플리케이션의 어디서도 메모리 관리에 대해서 걱정하지 않아도 됩니다. Get이 그것을 처리 할 것입니다.\n\nBinding 클래스는 라우트가 호출될 때 불려집니다. GetMaterialApp의 \"initialBinding\"에서 모든 종속성을 추가하여 생성할 수 있습니다.\n\n```dart\nGetMaterialApp(\n  initialBinding: SampleBind(),\n  home: Home(),\n);\n```\n\n### BindingsBuilder\n\n바인딩을 생성하는 기본 방법은 바인딩을 구현한 클래스를 만드는 것 입니다.\n하지만 대안으로 `BindingsBuilder` 콜백을 사용하여 간단하게 원하는 것을 인스턴스화하는 함수를 사용할 수 있습니다.\n\n예시:\n\n```dart\ngetPages: [\n  GetPage(\n    name: '/',\n    page: () => HomeView(),\n    binding: BindingsBuilder(() {\n      Get.lazyPut<ControllerX>(() => ControllerX());\n      Get.put<Service>(()=> Api());\n    }),\n  ),\n  GetPage(\n    name: '/details',\n    page: () => DetailsView(),\n    binding: BindingsBuilder(() {\n      Get.lazyPut<DetailsController>(() => DetailsController());\n    }),\n  ),\n];\n```\n\n이 방법은 각 라우트에 대해 한개의 바인딩 클래스 만드는 것을 피할수 있어서 더 간단하게 할 수 있습니다.\n\n두 방법 모두 완벽하게 작동하며 취향에 맞춰서 사용하시면 됩니다.\n\n### SmartManagement\n\nGetX는 기본적으로 메모리에서 사용되지 않는 컨트롤러들을 제거합니다. 문제가 생기거나 적절히 사용하지 않는 위젯도 마찬가지 입니다.\n이것이 종속성 관리의 `full`모드 입니다.\n하지만 GetX 클래스의 제거를 제어하는 방식을 변경하기 원한다면 `SmartManagement` 클래스로 다른 행동을 설정할 수 있습니다.\n\n#### 변경하는 방법\n\n구성을 변경(보통은 필요 없습니다)하려면 이렇게 하세요:\n\n```dart\nvoid main () {\n  runApp(\n    GetMaterialApp(\n      smartManagement: SmartManagement.onlyBuilders // 이곳\n      home: Home(),\n    )\n  )\n}\n```\n\n#### SmartManagement.full\n\n이것이 기본입니다. permanent가 설정되지 않으면 사용되지 않는 클래스를 제거합니다. 대부분의 경우 이 구성을 변경하지 않고 유지하십시오. GetX가 처음이라면 바꾸지 마십시오.\n\n#### SmartManagement.onlyBuilders\n이 옵션은 오직 컨트롤러가 `init:`에서 시작되었거나 `Get.lazyPut()`으로 바인딩되어 로드되면 제거됩니다.\n\n`Get.put()`이나 `Get.putAsync()` 또는 다른 접근을 를 사용하면 SmartManagement는 종속성 제거를 위한 권한을 가지지 못합니다.\n\n기본 동작은 SmartManagement.onlyBuilders와 다르게 \"Get.put\"으로 인스턴스화된 위젯들도 삭제됩니다.\n\n#### SmartManagement.keepFactory\n\nSmartManagement.full과 같이 더이상 사용되지 않으면 종속성이 제거됩니다. 하지만 factory가 유지되어 다시 인스턴스가 필요하면 종속성이 재생성됩니다.\n\n### 바인딩이 작동하는 자세한 설명\n바인딩은 다른 화면으로 이동하려고 클릭하는 순간에 임시 factory를 생성합니다. 그리고 화면 전환 애니메이션이 발생하는 즉시 제거됩니다.\n이 행위는 매우 빨라 분석기에 등록도 되지 않습니다.\n다시 화면으로 이동하면 새로운 임시 factory를 호출하므로 SmartManagement.keepFactory 사용을 선택할 수도 있습니다. 그러나 바인딩을 생성하지 않거나 동일한 바인딩에 대해 모든 종속성을 유지하고 싶다면 도움이 됩니다.\nFactory는 적은 메모리만 사용하고 인스턴스를 가지지 않지만 원하는 클래스의 \"형태\"를 가진 함수를 가집니다.\n메모리에서 매우 적은 비용을 가지지만 이 라이브러리의 목적이 최소 리소스를 사용하여 가능한 최대 성능을 가지는 것이라 GetX는 기본적으로 factory를 제거합니다.\n가장 편한방법을 취하십시오.\n\n## 주석\n\n- 다중 바인딩을 사용한다면 SmartManagement.keepFactory를 사용하지 마세요. 바인딩을 사용하지 않거나 GetMaterialApp의 initialBinding에 연결한 1개의 바인딩만 설계하세요.\n\n- 바인딩의 사용은 완전히 선택사항입니다. 클래스에서 `Get.put()`과 `Get.find()`를 사용하면 아무 문제없이 컨트롤러가 주어집니다.\n그러나 서비스나 다른 추상적인 동작을 원하면 더 나은 구성의 바인딩을 추천합니다.\n"
  },
  {
    "path": "documentation/kr_KO/route_management.md",
    "content": "- [라우트 관리](#라우트-관리)\n  - [사용하는 방법](#사용하는-방법)\n  - [이름없는 라우트 탐색](#이름없는-라우트-탐색)\n  - [이름있는 라우트 탐색](#이름있는-라우트-탐색)\n    - [이름있는 라우트에 데이터 보내기](#이름있는-라우트에-데이터-보내기)\n    - [동적 url 링크](#동적-url-링크)\n    - [미들웨어](#미들웨어)\n  - [context 없이 탐색](#context-없이-탐색)\n    - [SnackBars](#snackbars)\n    - [Dialogs](#dialogs)\n    - [BottomSheets](#bottomsheets)\n  - [중첩된 탐색](#중첩된-탐색)\n\n# 라우트 관리\n\n라우트 관리가 문제 있는 경우 GetX가 모든 것을 완벽히 설명해줍니다.\n\n## 사용하는 방법\n\npubspec.yaml 파일에 추가:\n\n```yaml\ndependencies:\n  get:\n```\n\ncontext 없이 routes/snackbars/dialogs/bottomsheets을 사용하거나 고급 GetX API를 사용하려면 MaterialApp 앞에 \"Get\"만 추가하여 GetMaterialApp으로 바꿔서 이용하세요!\n\n```dart\nGetMaterialApp( // 이전: MaterialApp(\n  home: MyHome(),\n)\n```\n\n## 이름없는 라우트 탐색\n\n새 화면으로 이동:\n\n```dart\nGet.to(NextScreen());\n```\n\nsnackbars, dialogs, bottomsheets 또는 Navigator.pop(context);로 보통 닫았던 것들을 닫기\n\n```dart\nGet.back();\n```\n\n다음 화면으로 이동하고 이전 화면에서 돌아오지 않는 경우 (스플래시나 로그인 화면 등을 사용하는 경우)\n\n```dart\nGet.off(NextScreen());\n```\n\n다음 화면으로 이동하고 이전 화면이 모두 닫히는 경우 (장바구니, 투표, 테스트에 유용함)\n\n```dart\nGet.offAll(NextScreen());\n```\n\n다음 화면으로 이동하고 돌아올때 바로 데이터를 받거나 업데이트할 경우:\n\n```dart\nvar data = await Get.to(Payment());\n```\n\n다른 화면에서 이전화면으로 데이터를 전달할때:\n\n```dart\nGet.back(result: 'success');\n```\n\n그리고 사용방법:\n\n예시:\n\n```dart\nif(data == 'success') madeAnything();\n```\n\n우리의 문법을 배우고 싶지 않습니까?\nNavigator를 navigator로 바꾸시면 됩니다. 그리고 context를 사용하지 않아도 표준 navigator의 모든 기능이 가능합니다.\n예시:\n\n```dart\n\n// 기본 Flutter navigator\nNavigator.of(context).push(\n  context,\n  MaterialPageRoute(\n    builder: (BuildContext context) {\n      return HomePage();\n    },\n  ),\n);\n\n// GetX는 context 필요 없이 Flutter 문법을 사용\nnavigator.push(\n  MaterialPageRoute(\n    builder: (_) {\n      return HomePage();\n    },\n  ),\n);\n\n// GetX 문법 (이것은 동의하지 않겠지만 더 좋습니다)\nGet.to(HomePage());\n\n\n```\n\n## 이름있는 라우트 탐색\n\n- namedRoutes로 탐색하기를 선호하면 GetX도 지원합니다.\n\nnextScreen으로 이동\n\n```dart\nGet.toNamed(\"/NextScreen\");\n```\n\n다음으로 이동하고 트리에서 이전 화면을 지웁니다.\n\n```dart\nGet.offNamed(\"/NextScreen\");\n```\n\n다음으로 이동하고 트리에서 이전 화면 전체를 지웁니다.\n\n```dart\nGet.offAllNamed(\"/NextScreen\");\n```\n\nGetMaterialApp를 사용하여 라우트들을 정의:\n\n```dart\nvoid main() {\n  runApp(\n    GetMaterialApp(\n      initialRoute: '/',\n      getPages: [\n        GetPage(name: '/', page: () => MyHomePage()),\n        GetPage(name: '/second', page: () => Second()),\n        GetPage(\n          name: '/third',\n          page: () => Third(),\n          transition: Transition.zoom  \n        ),\n      ],\n    )\n  );\n}\n```\n\n정의 안된 라우트로 이동시 제어 (404 에러), GetMaterialApp에 unknownRoute를 정의할 수 있습니다.\n\n```dart\nvoid main() {\n  runApp(\n    GetMaterialApp(\n      unknownRoute: GetPage(name: '/notfound', page: () => UnknownRoutePage()),\n      initialRoute: '/',\n      getPages: [\n        GetPage(name: '/', page: () => MyHomePage()),\n        GetPage(name: '/second', page: () => Second()),\n      ],\n    )\n  );\n}\n```\n\n### 이름있는 라우트에 데이터 보내기\n\n무엇이든 인수를 통해 전달합니다. GetX는 String, Map, List, 클래스 인스턴스등 모든 것을 허용합니다.\n\n```dart\nGet.toNamed(\"/NextScreen\", arguments: 'Get is the best');\n```\n\n클래스 또는 컨트롤러에서:\n\n```dart\nprint(Get.arguments);\n// 출력: Get is the best\n```\n\n### 동적 url 링크\n\nGetX는 웹과 같이 향상된 동적 url을 제공합니다. 웹 개발자들은 아마 Flutter에서 이미 이 기능을 원하고 있을 것 입니다. 대부분의 경우 패키지가 이 기능을 약속하고 URL이 웹에서 제공하는 것과 완전히 다른 구문을 제공하는 것을 보았을 것입니다. 하지만 GetX는 이 기능을 해결합니다.\n\n```dart\nGet.offAllNamed(\"/NextScreen?device=phone&id=354&name=Enzo\");\n```\n\ncontroller/bloc/stateful/stateless 클래스에서:\n\n```dart\nprint(Get.parameters['id']);\n// 출력: 354\nprint(Get.parameters['name']);\n// 출력: Enzo\n```\n\nGetX는 쉽게 NamedParameters 전달을 할 수 있습니다:\n\n```dart\nvoid main() {\n  runApp(\n    GetMaterialApp(\n      initialRoute: '/',\n      getPages: [\n      GetPage(\n        name: '/',\n        page: () => MyHomePage(),\n      ),\n      GetPage(\n        name: '/profile/',\n        page: () => MyProfile(),\n      ),\n       //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.\n       GetPage(\n        name: '/profile/:user',\n        page: () => UserProfile(),\n      ),\n      GetPage(\n        name: '/third',\n        page: () => Third(),\n        transition: Transition.cupertino  \n      ),\n     ],\n    )\n  );\n}\n```\n\n경로 명으로 데이터 보냄\n\n```dart\nGet.toNamed(\"/profile/34954\");\n```\n\n다음 화면에서 파라미터로 데이터를 가져옴\n\n```dart\nprint(Get.parameters['user']);\n// 출력: 34954\n```\n\n\n또는 이와 같은 여러 매개 변수를 보냅니다.\n\n```dart\nGet.toNamed(\"/profile/34954?flag=true\");\n```\n\n두 번째 화면에서 일반적으로 매개 변수별로 데이터를 가져옵니다.\n\n```dart\nprint(Get.parameters['user']);\nprint(Get.parameters['flag']);\n// 출력: 34954 true\n```\n\n\n\n이제 Get.toNamed()를 사용하여 어떤 context도 없이 명명된 라우트를 탐색하고 (BLoC 또는 Controller 클래스로 부터 직접 라우트를 호출할 수 있음) 앱이 웹으로 컴파일되면 경로는 url에 표시됩니다. <3\n\n### 미들웨어\n\n만약 GetX 이벤트를 받아서 행동을 트리거 하려면 routingCallback을 사용하면 가능합니다.\n\n```dart\nGetMaterialApp(\n  routingCallback: (routing) {\n    if(routing.current == '/second'){\n      openAds();\n    }\n  }\n)\n```\n\nGetMaterialApp을 사용하지 않는다면 수동 API를 사용해서 Middleware observer를 추가할 수 있습니다.\n\n```dart\nvoid main() {\n  runApp(\n    MaterialApp(\n      onGenerateRoute: Router.generateRoute,\n      initialRoute: \"/\",\n      navigatorKey: Get.key,\n      navigatorObservers: [\n        GetObserver(MiddleWare.observer), // 여기 !!!\n      ],\n    ),\n  );\n}\n```\n\nMiddleWare class 생성\n\n```dart\nclass MiddleWare {\n  static observer(Routing routing) {\n    /// 각 화면의 routes, snackbars, dialogs와 bottomsheets에서 추가하여 받을 수 있습니다.\n    /// If you need to enter any of these 3 events directly here,\n    /// you must specify that the event is != Than you are trying to do.\n    if (routing.current == '/second' && !routing.isSnackbar) {\n      Get.snackbar(\"Hi\", \"You are on second route\");\n    } else if (routing.current == '/third'){\n      print('last route called');\n    }\n  }\n}\n```\n\n이제, 코드에서 Get을 사용하세요:\n\n```dart\nclass First extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        leading: IconButton(\n          icon: Icon(Icons.add),\n          onPressed: () {\n            Get.snackbar(\"hi\", \"i am a modern snackbar\");\n          },\n        ),\n        title: Text('First Route'),\n      ),\n      body: Center(\n        child: ElevatedButton(\n          child: Text('Open route'),\n          onPressed: () {\n            Get.toNamed(\"/second\");\n          },\n        ),\n      ),\n    );\n  }\n}\n\nclass Second extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        leading: IconButton(\n          icon: Icon(Icons.add),\n          onPressed: () {\n            Get.snackbar(\"hi\", \"i am a modern snackbar\");\n          },\n        ),\n        title: Text('second Route'),\n      ),\n      body: Center(\n        child: ElevatedButton(\n          child: Text('Open route'),\n          onPressed: () {\n            Get.toNamed(\"/third\");\n          },\n        ),\n      ),\n    );\n  }\n}\n\nclass Third extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: Text(\"Third Route\"),\n      ),\n      body: Center(\n        child: ElevatedButton(\n          onPressed: () {\n            Get.back();\n          },\n          child: Text('Go back!'),\n        ),\n      ),\n    );\n  }\n}\n```\n\n## context 없이 탐색\n\n### SnackBars\n\nFlutter로 간단한 SnackBar를 사용하려면 Scaffold의 context가 반드시 주어지거나 Scaffold에 GlobalKey를 추가해서 사용해야만 합니다.\n\n```dart\nfinal snackBar = SnackBar(\n  content: Text('Hi!'),\n  action: SnackBarAction(\n    label: 'I am a old and ugly snackbar :(',\n    onPressed: (){}\n  ),\n);\n// 위젯 트리에서 Scaffold를 찾아서 사용하면\n// SnackBar가 보여집니다.\nScaffold.of(context).showSnackBar(snackBar);\n```\n\nGet을 사용할때:\n\n```dart\nGet.snackbar('Hi', 'i am a modern snackbar');\n```\n\nGet을 사용하면 코드의 어디에서든지 Get.snackbar를 호출하거나 원하는데로 수정하기만 하면 됩니다!\n\n```dart\nGet.snackbar(\n  \"Hey i'm a Get SnackBar!\", // title\n  \"It's unbelievable! I'm using SnackBar without context, without boilerplate, without Scaffold, it is something truly amazing!\", // message\n  icon: Icon(Icons.alarm),\n  shouldIconPulse: true,\n  onTap:(){},\n  barBlur: 20,\n  isDismissible: true,\n  duration: Duration(seconds: 3),\n);\n\n\n  ////////// ALL FEATURES //////////\n  //     Color colorText,\n  //     Duration duration,\n  //     SnackPosition snackPosition,\n  //     Widget titleText,\n  //     Widget messageText,\n  //     bool instantInit,\n  //     Widget icon,\n  //     bool shouldIconPulse,\n  //     double maxWidth,\n  //     EdgeInsets margin,\n  //     EdgeInsets padding,\n  //     double borderRadius,\n  //     Color borderColor,\n  //     double borderWidth,\n  //     Color backgroundColor,\n  //     Color leftBarIndicatorColor,\n  //     List<BoxShadow> boxShadows,\n  //     Gradient backgroundGradient,\n  //     TextButton mainButton,\n  //     OnTap onTap,\n  //     bool isDismissible,\n  //     bool showProgressIndicator,\n  //     AnimationController progressIndicatorController,\n  //     Color progressIndicatorBackgroundColor,\n  //     Animation<Color> progressIndicatorValueColor,\n  //     SnackStyle snackStyle,\n  //     Curve forwardAnimationCurve,\n  //     Curve reverseAnimationCurve,\n  //     Duration animationDuration,\n  //     double barBlur,\n  //     double overlayBlur,\n  //     Color overlayColor,\n  //     Form userInputForm\n  ///////////////////////////////////\n```\n\n기존 스낵바를 선호하거나 한 줄만 추가하는 것을 포함하여 처음부터 커스텀하려는 경우(Get.snackbar는 필수로 제목과 메시지를 사용함) 다음을 사용할 수 있습니다.\nGet.snackbar가 빌드된 RAW API를 제공하는`Get.rawSnackbar ();`.\n\n### Dialogs\n\ndialog 열기:\n\n```dart\nGet.dialog(YourDialogWidget());\n```\n\ndefault dialog 열기:\n\n```dart\nGet.defaultDialog(\n  onConfirm: () => print(\"Ok\"),\n  middleText: \"Dialog made in 3 lines of code\"\n);\n```\n\nshowGeneralDialog 대신에 Get.generalDialog를 사용할 수 있습니다.\n\ncupertinos를 포함한 다른 모든 Flutter 대화 상자 위젯의 경우 context 대신 Get.overlayContext를 사용하고 코드의 어느 곳에서나 열 수 있습니다.\n오버레이를 사용하지 않는 위젯의 경우 Get.context를 사용할 수 있습니다.\n이 두 context는 탐색 context 없이 inheritedWidget이 사용되는 경우를 제외하고 99%의 경우에 UI의 context를 대체하여 동작합니다.\n\n### BottomSheets\n\nGet.bottomSheet는 showModalBottomSheet와 같지만 context가 필요 없습니다.\n\n```dart\nGet.bottomSheet(\n  Container(\n    child: Wrap(\n      children: <Widget>[\n        ListTile(\n          leading: Icon(Icons.music_note),\n          title: Text('Music'),\n          onTap: () {}\n        ),\n        ListTile(\n          leading: Icon(Icons.videocam),\n          title: Text('Video'),\n          onTap: () {},\n        ),\n      ],\n    ),\n  )\n);\n```\n\n## 중첩된 탐색\n\nGetX는 Fultter의 중첩된 탐색을 더 쉽게 만듭니다.\ncontext가 필요 없고 Id로 탐색 스택을 찾을 수 있습니다.\n\n- 주석: 병렬 탐색 스택을 만드는 것은 위험 할 수 있습니다. 이상적인 것은 NestedNavigators를 사용하지 않거나 아껴서 사용하는 것입니다. 프로젝트에 필요한 경우 여러 탐색 스택을 메모리에 유지하는 것이 RAM 소비에 좋지 않을 수 있음을 명심하십시오.\n\n간단합니다:\n\n```dart\nNavigator(\n  key: Get.nestedKey(1), // index로 key를 생성\n  initialRoute: '/',\n  onGenerateRoute: (settings) {\n    if (settings.name == '/') {\n      return GetPageRoute(\n        page: () => Scaffold(\n          appBar: AppBar(\n            title: Text(\"Main\"),\n          ),\n          body: Center(\n            child: TextButton(\n              color: Colors.blue,\n              onPressed: () {\n                Get.toNamed('/second', id:1); // index로 중첩된 경로를 탐색\n              },\n              child: Text(\"Go to second\"),\n            ),\n          ),\n        ),\n      );\n    } else if (settings.name == '/second') {\n      return GetPageRoute(\n        page: () => Center(\n          child: Scaffold(\n            appBar: AppBar(\n              title: Text(\"Main\"),\n            ),\n            body: Center(\n              child:  Text(\"second\")\n            ),\n          ),\n        ),\n      );\n    }\n  }\n),\n```\n"
  },
  {
    "path": "documentation/kr_KO/state_management.md",
    "content": "- [상태 관리자](#상태-관리자)\n  - [반응형 상태 관리자](#반응형-상태-관리자)\n    - [장점](#장점)\n    - [최대의 성능](#최대의-성능)\n    - [반응형 변수 선언하기](#반응형-변수-선언하기)\n        - [반응형 상태를 갖는 간단한 방법](#반응형-상태를-갖는-간단한-방법)\n    - [변수를 화면에 적용하기](#변수를-화면에-적용하기)\n    - [재빌드에 조건 걸기](#재빌드에-조건-걸기)\n    - [.obs를 사용하는 방법](#obs를-사용하는-방법)\n    - [List를 사용할 때](#list를-사용할-때)\n    - [어째서 .value를 사용하는가](#어째서-value를-사용하는가)\n    - [Obx()](#obx)\n    - [Workers](#workers)\n  - [간단한 상태 관리자](#간단한-상태-관리자)\n    - [장점](#장점-1)\n    - [사용법](#사용법)\n    - [controller의 동작 방식](#controller의-동작-방식)\n    - [StatefulWidget을 더 이상 사용할 필요없습니다](#statefulwidget을-더-이상-사용할-필요없습니다)\n    - [이 패키지의 목표](#이-패키지의-목표)\n    - [다른 사용법](#다른-사용법)\n    - [고유 ID](#고유-id)\n  - [2개의 상태 관리자 섞어쓰기](#2개의-상태-관리자-섞어쓰기)\n  - [GetBuilder vs GetX vs Obx vs MixinBuilder](#getbuilder-vs-getx-vs-obx-vs-mixinbuilder)\n\n# 상태 관리자\n\nGetX는 다른 상태 관리자처럼 Streams나 ChangeNotifier를 사용하지 않습니다. 어째서일까요? GetX를 사용하면 Android, iOS, 웹, Linux, macOS, Linux 용 어플리케이션뿐만 아니라, 서버 어플리케이션도 Flutter/GetX의 문법으로 만들 수 있습니다. 반응 시간을 줄이고, RAM을 효율적으로 사용하기 위해, 우리는 GetValue와 GetStream을 만들었습니다. GetValue와 GetStream은 적은 연산 자원으로 낮은 레이턴시와 높은 퍼포먼스를 보여줍니다. 우리는 이를 토대로 상태관리를 포함해 모든 리소스를 빌드합니다.\n\n- _복잡도_: 어떤 상태관리자들은 복잡하고 매우 비슷한 형태를 띕니다. GetX를 이용하면 모든 이벤트를 위한 클래스를 정의할 필요가 없습니다. 이는 당신의 코드를 매우 깔끔하게 만들어주며, 적을 코드들을 줄여줍니다. 많은 Flutter 개발자들이 이런 이유로 개발을 포기해왔지만, 드디어 상태관리를 해결해줄 엄청나게 간단한 방법이 나왔습니다.\n- _code generators에 의존하지 않음_: 당신은 어플리케이션 개발을 위한 로직을 작성하는데 개발시간의 절반을 할애했을 것입니다. 어떤 상태관리자들은 code generator에 의존하여 읽기 쉬운 코드를 작성했을 것입니다. 변수를 바꾸고 build_runner를 실행해야 하는 것은 비생산적일 수 있으며, 심지어 Flutter가 이를 반영되기를 기다리면서 커피 한 잔을 즐겨야 할 정도로 오래 기다릴 수 있습니다. GetX는 모든것을 즉각적으로 반응합니다. code generator에 의존하지 않고, 모든 면에서 당신의 생산성을 높여줍니다.\n- _필요없는 context_: 아마 당신은 비즈니스 로직을 UI에 반영하기 위해, 여러 위젯 컨트롤러에 context를 넘겨주었을 것입니다. context를 이용한 위젯을 사용하기 위해, context를 다양한 클래스와 함수들을 이용하여 전달하였을 것입니다. GetX를 이용하면 그럴 필요가 없습니다. context없이 controller만으로 접근하여 사용할 수 있습니다. 말 그대로 아무 의미 없이 context를 파라미터로 넘겨줄 필요가 없습니다.\n- _세분화된 컨트롤_: 대부분의 상태관리자들은 ChangeNotifier을 기반으로 동작합니다. ChangeNotifier는 notifyListeners가 호출되면 모든 위젯들에게 알릴 것입니다. 만약 당신 스크린에 수많은 ChangeNotifier 클래스를 갖는 40개의 위젯이 있다면, 한 번 업데이트 할 때마다 모든 위젯들이 다시 빌드될 것입니다. GetX를 이용하면 위젯이 중첩되더라도, 변경된 위젯만 다시 빌드됩니다. 한 Obx가 ListView를 보고있고, 다른 Obx가 ListView 안의 checkbox를 보고있을 때, checkBox 값이 변경되면, checkBox만 업데이트 되고, ListView 값이 변경되면 ListView만 업데이트 됩니다.\n- _**정말** 바뀌었을 때만 재구성_: GetX는 흐름제어를 합니다. '진탁'이라는 Text를 화면에 보여준다고 해봅시다. 만약 당신이 observable 변수인 '진탁'을 다시 한 번 '진탁'으로 변경한다면, 그 위젯은 재구성되지 않습니다. 왜냐하면 GetX는 '진탁'이 이미 Text로 보여주고 있다는 것을 알고 있기 때문에, 불필요한 재구성을 하지 않습니다. 대부분(모두일 수도 있는) 지금까지의 대부분의 상태관리자들은 스크린에 다시 빌드하여 보여줍니다.\n\n## 반응형 상태 관리자\n\n반응형 프로그래밍은 복잡하다고 말해지기 때문에 많은 사람들이 접하기 힘들게 합니다. GetX는 반응형 프로그래밍을 꽤 간단한 것으로 만들어줍니다:\n\n- StreamControllers를 생성할 필요가 없습니다.\n- StreamBuilder를 각 변수마다 생성할 필요가 없습니다.\n- 각 상태마다 클래스를 만들어줄 필요가 없습니다.\n- 초기값을 위한 get을 만들어줄 필요가 없습니다.\n\nGetX와 함께하는 반응형 프로그래밍은 setState를 사용하는 것만큼 쉽습니다.\n\n이름 변수가 하나 있고, 이 변수가 변경될 때마다 해당 변수를 사용하는 모든 위젯들이 자동적으로 변경된다고 해봅시다.\n\n여기 이름 변수가 있습니다.\n\n```dart\nvar name = 'Jonatas Borges';\n```\n\n이 변수를 observable로 만들고 싶다면, 맨 뒤에 \".obs\"만 붙이면 됩니다.\n\n```dart\nvar name = 'Jonatas Borges'.obs;\n```\n\n이게 끝입니다. 정말 쉽죠?\n\n지금부터, 우리는 이런 반응형-\".obs\"(ervables) 변수들을 _Rx_ 라고 부르겠습니다.\n\n우리가 내부에서 무엇을 했나요? 우리는 `String`의 `Stream`에 초기값인 `\"Jonatas Borges\"`를 할당했습니다. 우리는 `\"Jonatas Borges\"`을 사용하는 위젯들에게, 이제 이 변수에 \"속한다\"고 알리며 이 Rx 변수가 바뀔 때마다, 그 위젯들도 바뀌어야 한다고 알립니다.\n\n이것이 Dart 언어의 기능에 기반한, **GetX의 마법**입니다.\n\n하지만, 알다시피 static 클래스들은 \"자동 변경\"할 힘이 없기 때문에, `위젯`은 함수 안에 있는 경우에만 변경이 가능합니다.\n\n몇몇 변수를 동일한 범위 내에서 변화시키고 싶을 때, 당신은 `StreamBuilder`를 생성하여 이 변수를 지켜보면서 변화를 감지하고, \"연쇄적으로\" 중첩된 `StreamBuilder`를 만들 것입니다, 맞죠?\n\n아뇨, 더 이상 `StreamBuilder`를 만들 필요 없습니다. 하지만 static 클래스를 사용한다는 점은 맞아요.\n\n특정한 위젯을 변경하고 싶을 때, 우리는 모양이 비슷한 코드들을 봐야 했습니다. 그건 Flutter 방식이죠. **GetX**를 이용하면 이런 비슷한 모양의 코드는 잊어버릴 수 있습니다.\n\n`StreamBuilder( … )`? `initialValue: …`? `builder: …`? 아뇨, 당신은 그저 `Obx()` 위젯 안에 변수를 넣기만 하면 됩니다.\n\n```dart\nObx (() => Text (controller.name));\n```\n\n_당신이 기억해야할 것은?_  `Obx(() =>`만 기억하세요.\n\n당신은 화살표함수를 통해 그 위젯을 `Obx()`으로 전달하는 것입니다. (그 _Rx_ 의 \"Observer\")\n\n`Obx`는 꽤 스마트하며 `controller.name`이 바뀔 경우에만 바뀔 것입니다.\n\n만약 `name`이 `\"John\"`이고, 당신이 이를 `\"John\"` (`name.value = \"John\"`)으로 바꾼다면, 기존 `value`와 동일하므로 화면상으로 바뀌는 것이 없습니다. 그리고 `Obx`는 리소스를 아끼기 위해 새 값을 무시하고 재빌드하지 않습니다. **놀랍지 않나요?**\n\n> 그래서, 제가 만약 5개의 _Rx_ (observable) 변수를 `Obx`안에 가지고 있다면 어떻게 되나요?\n\n그 변수들 중 **아무거나** 변경이 되었을 때 업데이트 됩니다.\n\n> 그리고 제가 만약 클래스 안에 30개의 변수를 갖고 있고 하나만 업데이트 했다면, 클래스 안의 **모든** 변수가 업데이트 되나요?\n\n아뇨, 단지 그 _Rx_ 변수를 사용하는 **특정한 위젯만** 업데이트 됩니다.\n\n그래서 **GetX**는 _Rx_ 변수의 변경이 있을 때만 화면에 업데이트 합니다.\n\n```\nfinal isOpen = false.obs;\n\n// 아무일도 일어나지 않습니다. 동일한 값이기 때문입니다.\nvoid onButtonTap() => isOpen.value=false;\n```\n### 장점\n\n**GetX()** 는 업데이트된 것들을 **세부적으로** 제어해야할 때 유용합니다.\n\n어떤 동작을 수행할 때 모든 변수가 수정되어 `고유 ID`가 필요없을 때 `GetBuilder`를 사용하세요. `GetBuilder`는 단 몇줄의 코드로 상태를 변경시켜줍니다(`setState()`처럼). 이것은 단순하면서 CPU에 최소한의 부담을 주며, State 재빌드라는 하나의 목적을 수행하기 위해 가능한 한 최소의 리소스를 사용합니다.\n\n**강력한** 상택 관리자가 필요하다면, **GetX**와 함께하세요.\n\nGetX는 변수를 이용하지 않고, 내부에서 모든 것이 `Streams`로 구성된 __flow__ 를 이용합니다. \n모든 것이 `Streams`이기 때문에, 접속사로써 _rxDart_ 를 이용합니다.\n모든 것이 `Streams`이기 때문에, 각 \"_Rx_ 변수\"의 `event`를 주시할 수 있습니다.\n\n말 그대로 _BLoC_ 의 접근 법이며, generator와 decoration 없이 _MobX_ 보다 쉽습니다. \n**모든 것들을** `.obs`를 붙임으로써 _\"Observable\"_ 하게 만들 수 있습니다.\n\n### 최대의 성능\n\n최소의 재빌드를 위해 똑똑한 알고리즘을 적용하기 위해, **GetX**는 상태가 변했는지 확인하는 comparator를 사용합니다.\n\n당신의 앱에서 에러가 발생하고 상태 변경을 중복하여 보내면, **GetX**는 충돌하지 않도록 보장해줍니다.\n\n**GetX**를 사용하면 `value`가 변경된 경우만 상태가 변경됩니다.\n이 점이 **GetX**와 _`computed`를 사용하는 MobX_ 와의 주요 차이점입니다.\n2개의 __observable__ 변수를 결합하고 하나만 변경되는 경우, 그 _observable_ 를 참조하는 것 또한 변경됩니다.\n\n**GetX**를 사용하면, 2개의 변수를 결합한 경우 (`Oberver()`와 비슷한)`GetX()`는 정말 상태가 변경된 경우만 재빌드됩니다.\n\n### 반응형 변수 선언하기\n\n변수를 \"observable\"하게 만드는 방법은 3가지가 있습니다.\n\n\n1 - 첫 번째 방법: **`Rx{Type}`**.\n\n```dart\n// 초기값을 설정하는 것을 추천하지만, 필수는 아닙니다.\nfinal name = RxString('');\nfinal isLogged = RxBool(false);\nfinal count = RxInt(0);\nfinal balance = RxDouble(0.0);\nfinal items = RxList<String>([]);\nfinal myMap = RxMap<String, int>({});\n```\n\n2 - 두 번째 방법: **`Rx`**와 Dart의 제너릭을 이용 `Rx<Type>`\n\n```dart\nfinal name = Rx<String>('');\nfinal isLogged = Rx<Bool>(false);\nfinal count = Rx<Int>(0);\nfinal balance = Rx<Double>(0.0);\nfinal number = Rx<Num>(0);\nfinal items = Rx<List<String>>([]);\nfinal myMap = Rx<Map<String, int>>({});\n\n// 커스텀 클래스 - 그 어떤 클래스도 가능합니다\nfinal user = Rx<User>();\n```\n\n3 - The third, more practical, easier and preferred approach, just add **`.obs`** as a property of your `value`:\n\n3 - 세 번째 방법: 실용적이며 쉽고 선호되는 방법으로, 단순히 **`.obs`**를 `value`의 속성으로 덧붙이는 방법\n\n```dart\nfinal name = ''.obs;\nfinal isLogged = false.obs;\nfinal count = 0.obs;\nfinal balance = 0.0.obs;\nfinal number = 0.obs;\nfinal items = <String>[].obs;\nfinal myMap = <String, int>{}.obs;\n\n// 커스텀 클래스 - 그 어떤 클래스도 가능합니다\nfinal user = User().obs;\n```\n\n##### 반응형 상태를 갖는 간단한 방법\n\n알다시피 _Dart_ 는 _null safety_ 가 곧 도입될 것입니다.\n이를 대비하기 위해 지금부터, _Rx_ 변수를 항상 **초기값**으로 초기화해주세요.\n\n> 변수를 **GetX** 를 이용하여 _observable_ + _초기값_ 으로 바꾸는 것은 매우 쉽고 실용적입니다.\n\n변수의 맨 뒤에 \"`.obs`\" 글자를 붙이기만 하면 되고, **이게 다입니다**. \n당신은 변수를 observable 하게 만들었으며 `.value`를 이용하여 _초기값_ 에 접근할 수 있습니다.\n\n\n### 변수를 화면에 적용하기\n\n```dart\n// controller file\nfinal count1 = 0.obs;\nfinal count2 = 0.obs;\nint get sum => count1.value + count2.value;\n```\n\n```dart\n// view file\nGetX<Controller>(\n  builder: (controller) {\n    print(\"count 1 rebuild\");\n    return Text('${controller.count1.value}');\n  },\n),\nGetX<Controller>(\n  builder: (controller) {\n    print(\"count 2 rebuild\");\n    return Text('${controller.count2.value}');\n  },\n),\nGetX<Controller>(\n  builder: (controller) {\n    print(\"sum rebuild\");\n    return Text('${controller.sum}');\n  },\n),\n```\n\n`count1.value++`를 하면, 다음이 출력됩니다:\n- `count 1 rebuild` \n- `sum rebuild`\n\nbecause `count1` has a value of `1`, and `1 + 0 = 1`, changing the `sum` getter value.\n\n왜냐하면 `count1`은 `1`을 갖고 있고, `1 + 0 = 1`이며 `sum` getter의 값을 변경하기 때문입니다.\n\n`count2.value++`를 하면, 다음이 출력됩니다:\n- `count 2 rebuild` \n- `sum rebuild`\n\n왜냐하면 `count2.value`가 바뀌었고 `sum` 결과는 이제 `2`이기 때문입니다.\n\n\n- 참고: 기본적으로, 동일한 `value`로 변경되더라도, 첫 번째 이벤트는 위젯을 재빌드합니다. 이 동작은 Boolean 변수로 인해 일어납니다.\n\n다음과 같이 했다고 생각해봅시다:\n\n```dart\nvar isLogged = false.obs;\n```\n\n그리고 `ever`에서 이벤트를 발생시키기 위해, 사용자가 \"로그인\" 되어있는지 확인한다고 해봅시다.\n\n```dart\n@override\nonInit(){\n  ever(isLogged, fireRoute);\n  isLogged.value = await Preferences.hasToken();\n}\n\nfireRoute(logged) {\n  if (logged) {\n   Get.off(Home());\n  } else {\n   Get.off(Login());\n  }\n}\n```\n\n만약 `hasToken`이 `false`라면, `isLogged`에 변화는 없을 것입니다. 그러면 `ever()`는 호출되지 않을 것입니다.\n이런 동작을 피하기 위해서, `.value`가 동일한 값으로 변경되더라도 _observable_ 의 첫 변경은 이벤트를 발생시킬 것입니다.\n\n이런 동작을 원하지 않는다면, 다음으로 막을 수 있습니다:\n`isLogged.firstRebuild = false;`\n\n\n### 재빌드에 조건 걸기\n\n또한, Get은 정교한 상태 관리 기능을 제공합니다. 특정 조건에서 이벤트를 조건화할 수 있습니다.(리스트에 요소를 추가하는 등)\n\n```dart\n// 첫 번째 parameter: 조건, 반드시 true 혹은 false를 return\n// 두 번째 parameter: 조건이 true 일 경우 적용할 새 value \nlist.addIf(item < limit, item);\n```\n\ndecoration 없이, code generator 없이, 복잡함 없이 :smile:\n\nFlutter의 counter 앱을 아시나요? 당신의 Controller 클래스는 아마 다음과 같을 것입니다.\n\n```dart\nclass CountController extends GetxController {\n  final count = 0.obs;\n}\n```\n\n간단합니다:\n\n```dart\ncontroller.count.value++\n```\n\n어디에서 변경되든지 간에 관계없이, counter 변수를 당신의 UI 내에서 업데이트 할 수 있습니다.\n\n### .obs를 사용하는 방법\n\n그 어떠한 것도 obs로 바꿀 수 있습니다. 2가지 방법이 있습니다.\n\n* 클래스 값들을 obs로 바꿀 수 있습니다.\n```dart\nclass RxUser {\n  final name = \"Camila\".obs;\n  final age = 18.obs;\n}\n```\n\n* 또는 클래스 전체를 observable로 만들 수 있습니다.\n```dart\nclass User {\n  User({String name, int age});\n  var name;\n  var age;\n}\n\n// 인스턴스화 할때\nfinal user = User(name: \"Camila\", age: 18).obs;\n```\n\n### List를 사용할 때\n\n리스트내 요소들과 마찬가지로 리스트 또한 완벽하게 observable로 만들 수 있습니다. 이렇게 하면, 리스트에 요소를 추가하였을 때 자동적으로 그 리스트를 사용하는 위젯들을 리빌드할 수 있습니다.\n\n리스트는 \".value\"를 이용할 필요가 없습니다. 놀랍게도 dart api가 \".value\" 없이도 사용할 수 있게 만들어줍니다.\n불행히도 String, int와 같은 primitive type들은 확장할 수 없기때문에 \".value\"가 반드시 필요합니다만, getter와 setter를 이용하면 이러한 문제는 해결됩니다.\n\n```dart\n// On the controller\nfinal String title = 'User Info:'.obs\nfinal list = List<User>().obs;\n\n// on the view\nText(controller.title.value), // String은 .value가 필요합니다\nListView.builder (\n  itemCount: controller.list.length // 리스트는 .value가 필요없습니다.\n)\n```\n\n당신이 만든 observable 클래스를 만들었을 때, 업데이트를 하는 다른 방법이 있습니다.\n\n```dart\n// model 파일에서\n// 각 field들을 observable로 만드는 대신, 클래스 전체를 observable로 만들 것입니다.\nclass User() {\n  User({this.name = '', this.age = 0});\n  String name;\n  int age;\n}\n\n\n// controller 파일에서\nfinal user = User().obs;\n// when you need to update the user variable:\n// user의 변수를 업데이트해야할 때\nuser.update( (user) { // 이 parameter는 업데이트 하길 원하는 인스턴스 자체입니다.\nuser.name = 'Jonny';\nuser.age = 18;\n});\n// user 인스턴스를 업데이트하는 또다른 방법\nuser(User(name: 'João', age: 35));\n\n// on view:\nObx(()=> Text(\"Name ${user.value.name}: Age: ${user.value.age}\"))\n// .value 없이 model의 value에 접근할 수 있습니다.\nuser().name; // User 클래스가 아니라, user 변수임을 주의하세요 (변수는 소문자 u를 갖고 있습니다.)\n```\n\n원하지 않으면 set을 이용하지 않아도 됩니다. \"assign\"과 \"assignAll\" api를 이용할 수 있습니다.\n\"assign\" api는 당신의 리스트를 비우고, 채우고 싶은 하나의 요소를 넣을 수 있습니다.\n\"assignAll\" api는 존재하는 리스트를 비우고, 삽입하길 원하는 iterable 객체들을 추가할 수 있습니다.\n\n### 어째서 .value를 사용하는가\n\ncode generator와 decoration을 이용하면 `String`과 `int`와 같은 타입에도 '.value'를 이용하지 않아도 되었겠지만, 이 라이브러리의 목표는 외부 종속성을 피하는 것입니다. 우리는 외부 패키지를 이용하지 않고, 간단하고 가벼우며 성능좋은  필수요소들(라우트 관리, 종속성 관리, 상태 관리)을 제공하고, 쾌적한 프로그래밍 환경을 제공하고 싶었습니다.\n\n단 3글자(get)와 콜론(;)만 pubspec에 적고 프로그래밍을 시작하세요. 모든 솔루션들이 기본적으로 제공되며, 쉽고 생산성과 성능 좋게 라우트와 상태 관리를 할 수 있습니다.\n\n이 라이브러리는 완벽한 솔루션임에도 불구하고 단일 상태 관리 패키지보다 가볍습니다. 이 점을 꼭 아셔야 합니다.\n\n만약 `.value`가 code generator처럼 당신을 괴롭힌다면, MobX가 훌륭한 대안으로 Get과 함께 활용할 수 있습니다. pubspec에서 단일 종속성을 원하고, 호환되지 않는 버전의 패키지들을 걱정하지 않고 프로그래밍을 시작하길 원하거나, 상태 업데이트 오류가 상태 관리자나 패키지에서 비롯되는 경우, controller에 사용가능성에 대한 걱정하기 원하지 않고 말그대로 \"프로그래밍만\"을 하고 싶은 경우, get은 완벽한 방안입니다.\n\n당신이 MobX의 code  generator를 이용하는데 문제가 없었거나 BloC의 boilerplate를 이용하는데 문제가 없었다면, Get을 라우트하는데 쉽게 사용할 수 있을 것이며 상태 관리자를 갖고 있다는 사실을 잊을 것입니다. Get의 SEM과 RSM은 필수적으로 탄생했습니다. 저희 회사에는 90개의 controller가 넘는 프로젝트가 있었는데, 충분히 좋은 디바이스에서도 flutter clean 이후, code generator는 작업을 끝내는데 30분 이상이 걸렸습니다. 당신의 프로젝트에 5, 10, 15개 정도의 controller들만 있다면 어떤 상태 관리자들도 충분히 좋겠지만, 엄청 큰 프로젝트를 진행하고 있다면 code generator는 문제를 일으킬 것입니다. get은 매우 훌륭한 해결책입니다.\n\n누군가 이 프로젝트에 기여하고자 code generator나 비슷한 것을 만들고 있다면, 저는 이 readme로 링크시키겠습니다. 저한테 필요한 것들이 모든 개발자에게 필요한 것들은 아니겠지만, 지금으로써는 MobX와 같은 좋은 솔루션들이 있다고 말할 수 있습니다. \n\n### Obx()\n\n바인딩을 이용해 Get을 입력하는 것은 불필요합니다. 익명 함수만 받는 GetX 대신 Obx 위젯을 이용할 수 있습니다. 타입을 이용하지 않는다면, 변수를 사용하기 위한 controller 객체를 이용하거나, `Get.find<Controller>().value` 혹은 `Controller.to.value`를 이용하여 value에 접근하면 됩니다. \n\n### Workers\n\nWorker는 이벤트가 일어났을 때, 특정 콜백함수들을 호출하는 것을 도와줍니다.\n\n```dart\n/// 'count1'이 변경될 때마다 호출\never(count1, (_) => print(\"$_ has been changed\"));\n\n/// 'count1'이 처음으로 변경될 때 호출\nonce(count1, (_) => print(\"$_ was changed once\"));\n\n/// Anti DDos - 'count1'이 변경되고 1초간 변화가 없을 때 호출\ndebounce(count1, (_) => print(\"debouce$_\"), time: Duration(seconds: 1));\n\n/// 'count1'이 변경되고 있는 동안 1초 간격으로 호출\ninterval(count1, (_) => print(\"interval $_\"), time: Duration(seconds: 1));\n```\n(`debounce`를 제외한)모든 worker들은 `condition` parameter를 가집니다. 이 parameter는 `bool` 이거나 `bool`을 return 하는 콜백함수입니다. 이 `condition`은 `callback` 함수가 언제 실행될지 정의합니다.\n\n모든 worker들은 `Worker` 객체를 return하며, `dispose()`를 이용하여 worker 동작을 취소시킬 수 있습니다.\n \n- **`ever`**\n_Rx_ 변수가 바뀔 때마다 항상 호출됩니다.\n\n- **`everAll`**\n`ever`처럼, `List` _Rx_ 변수가 주어지고 변경될 때마다 호출됩니다. \n\n- **`once`**\n변수가 최초로 변경될 때(한 번만) 호출됩니다.\n\n- **`debounce`**\n'debounce'는 검색 함수를 구현하는 데에 매우 유용합니다. API 호출을 타이핑이 모두 끝났을 때만 호출 시킬 수 있습니다. 만약 사용자가 \"진탁\"을 타이핑한다면, 당신은 'ㅈ,ㅣ,ㄴ,ㅌ,ㅏ,ㄱ'에 해당하는 6번의 검색을 해야할 것입니다. Get을 이용하면 이런 일은 일어나지 않을 것입니다. 왜냐하면 \"debounce\" Worker는 타이핑이 끝났을 때에만 검색하도록 만들어주기 때문입니다.\n\n- **`interval`**\n'interval'은 debounce와 다릅니다. 사용자가 1초에 1000번의 변화를 주는 행동을 한다고 해봅시다. debounce는 마지막 변화가 있은 후, 정해진 시간(기본적으로는 800ms)이 지나면 한 번만 호출됩니다. interval은 정해진 시간동안 사용자의 행동들을 무시합니다. 사용자가 1분동안 1초에 1000번의 변화를 주는 행동을 지속한다면, debounce는 사용자가 행동을 멈춘 후 한 번만 호출됩니다. 1초로 time이 설정된 interval은 매 초마다 1번씩 총 60번 호출되며, 3초로 time이 설정된 interval은 3초마다 1번씩 총 20번 호출 될 것입니다. interval은 엄청 빠른 터치(클릭)를 이용한 어뷰징(abusing)을 막는데 사용하는 데에 사용하기를 추천합니다.(예를 들어 특정 버튼을 눌러 코인을 얻는다고 해봅시다. 1분에 300번의 터치를 한다면, 사용자는 1분에 300코인을 얻을 것입니다. 하지만 interval를 이용하여 3초를 time으로 설정하면 사용자가 300번을 터치하든, 수 천번을 터치하든지 간에 20코인밖에 얻지 못할 것입니다.) 검색과 같이 변화가 api를 통해 쿼리를 호출해야 하는 경우, debounce는 DDos 공격을 막는데 효과적입니다. debounce는 사용자가 타이핑을 멈추길 기다리고, 멈추면  호출되기 때문입니다. 위쪽의 코인 시나리오에 대입해서 생각해보면, 터치를 \"멈춘\" 때, 코인 1개만 얻을 수 있을 것입니다.\n  \n\n\n- 참고: Worker는 Controller 혹은 클래스를 시작할 때만 사용할 수 있습니다. 그래서 항상 onInit 내에 있거나(권장사항), 클래스 생성자, StatefulWidget의 initState 안에(권장하지는 않지만 부작용은 없습니다.) 있어야 합니다.\n\n## 간단한 상태 관리자\n\nGet은 ChangeNotifier를 사용하지 않고, 엄청나게 가볍고 사용하기 쉬운 상태 관리자를 제공합니다. 이 상태 관리자는 Flutter가 처음인 사람들의 요구를 충족하며 대규모 어플리케이션에서도 문제를 발생시키지 않습니다.\n\nGetBuilder는 여러 상태 컨트롤을 정확하게 해내는 것을 목표로 합니다. 장바구니에 30개의 상품이 있고, 사용자가 하나를 삭제하기 위해 터치(클릭)하면 상품 목록이 업데이트 되어 가격과 품목 수가 줄어든다고 해봅시다. 이런 상황에서 GetBuilder는 매우 유용합니다. 왜냐하면 상태들을 그룹화하여 \"연산 로직\"없이 한 번에 변경하기 때문입니다. GetBuilder는 이런 상황을 고려하여 만들어졌습니다. 일시적인 상태 변화를 위해 setState를 사용하면 되므로 상태 관리자가 필요없기 때문입니다.\n\n이렇게 하면 개별적 controller를 원하는 경우, 각 ID를 할당해주거나 GetX를 사용할 수 있습니다. 어떤 것을 선택할지 당신에게 달려있지만 이 점을 기억하세요. \"개별\" 위젯이 많은 경우에는 GetX의 성능이 뛰어나고, 상태 변화가 여러 번 일어나는 경우에는 GetBuilder의 성능이 뛰어납니다.\n\n\n\n### 장점\n\n1. 필요한 위젯만 업데이트 해줍니다.\n\n2. ChangeNotifier를 사용하지 않고, 적은 메모리(거의 0mb)를 이용하여 상태 관리를 해줍니다.\n\n3. StatfulWidget을 이용 안 해도 됩니다! Get을 이용하면 더 이상 StatefulWidget이 필요 없습니다. 다른 상태 관리자들을 사용하면, Provider, BLoC, MobX Controller 등의 객체를 갖기 위해 StatefulWidget을 사용해야 합니다. appBar, Scaffold, 그리고 대부분의 위젯들이 StatelessWidget로 구성된 것을 생각해본 적이 있나요? Get은 이 부분도 해결해줍니다. 모든 것들을 Stateless로 만드세요. 하나의 위젯만 업데이트할 필요가 있다면, GetBuilder로 감싸면 해당 상태를 가질 수 있습니다.\n\n4. 당신의 프로젝트를 잘 정돈할 수 있습니다! Controller들은 UI내에 두지 않고, TextEditController나 다른 controller 들을 당신의 Controller 클래스 내에 두세요!\n\n5. 렌더링 된 직후, 위젯을 업데이트하기 위해 이벤트를 발생시킬 필요가 있나요? GetBuilder는 StatefulWidget처럼 \"initState\"를 갖고 있습니다. 그리고 controller로부터 직접적으로 이벤트를 호출하고, 더 이상 이벤트를 initState내에 배치할 필요가 없습니다. \n\n6. timers 등과 같은 streams를 닫는 행동을 트리거해야 하나요? GetBuilder는 dispose 또한 갖고 있어서, 위젯이 없어지자마자 dispose를 호출할 수 있습니다.\n\n7. streams는 정말 필요할 때만 사용하세요. StreamController와 StreamBuilder는 controller 안에 정상적으로 사용할 수 있습니다만! 기억하세요. stream은 메모리를 적당히 사용하지만, 남용해서는 안됩니다. 30개의 stream이 동시에 열려있다면 ChangeNotifier보다 안좋습니다(ChangeNotifier는 매우 나쁩니다).\n\n8. RAM의 소모 없이 위젯을 업데이트 하세요. Get은 GetBuilder의 creator ID만 저장하고 필요한 경우에만 해당 GetBuilder만 업데이트 합니다. 수천개의 GetBuilder가 있어도 get은 ID를 저장하는데 매우 적은 메모리를 사용합니다. 새 GetBuilder를 생성한다면, creator ID를 갖고 있는 GetBuilder의 상태를 공유합니다. 각 GetBuilder의 새 상태는 생성 되지 않기 때문에 큰 규모의 어플리케이션에서도 **많은** RAM 자원을 절약합니다. 기본적으로 당신의 어플리케이션은 전반적으로 Stateless 이고, 극히 일부의 위젯만 단일 상태를 가진 (GetBuilder를 포함한)Stateful일 것이기 때문에, 하나의 업데이트만으로 그것들을 전부 업데이트 합니다. 상태는 단  하나뿐입니다.\n\n9. Get은 전지적으로 대부분의 경우 어느 타이밍에 메모리에서 제거해야할 지 알 고 있습니다. 당신은 언제 컨트롤러를 dispose해야하는지만 걱정하세요.\n\n### 사용법\n\n```dart\n// GetxController를 상속(extends)하는 controller 클래스를 만드세요\nclass Controller extends GetxController {\n  int counter = 0;\n  void increment() {\n    counter++;\n    update(); // increment()가 호출되었을 때, counter 변수가 변경되어 UI에 반영되어야 한다는 것을 update()로 알려주세요\n  }\n}\n// 당신의 Stateless/Stateful 클래스에서, increment()가 호출되었을 때 GetBuilder를 이용해 Text를 업데이트 하세요\nGetBuilder<Controller>(\n  init: Controller(), // 맨 처음만! 초기화(init)해주세요\n  builder: (_) => Text(\n    '${_.counter}',\n  ),\n)\n\n// controller는 처음만 초기화하면 됩니다. 같은 controller로 GetBuilder를 또 사용하려는 경우에는 init을 하지 마세요.\n// 중복으로 'init'이 있는 위젯이 배치되자마자, controller는 자동적으로 메모리에서 제거될 것입니다.\n// 걱정하실 필요 없이, Get은 자동적으로 controller를 찾아서 해줄겁니다. 그냥 2번 init하지 않는 것만 하시면 됩니다. \n```\n\n**끝입니다!**\n\n- 당신은 이미 Get을 이용하여 상태관리를 어떻게 하는지 다 배우셨어요!\n\n- 참고: 큰 규모의 프로젝트를 진행하면서 init 속성을 사용하지 않을 수도 있습니다. 그럴 때에는, Binding 클래스를 상속(extends)한 클래스를 만들고, 그 클래스 내에서 해당 라우트에 생성되어야 하는 controller를 선언하세요. controller가 즉각적으로 만들어지지는 않지만, controller가 처음 사용될 때 Get이 알아서 잘 만들어줄 것입니다. Get은 lazyLoad를 지원하며, controller가 더 이상 필요하지 않을 때 dispose를 해줍니다. 사용예제는 pub.dev에서 확인하세요.\n\n수많은 라우트를 진행하면서 예전에 사용하였던 controller의 데이터가 필요하면, GetBuilder를 다시 사용하시면 됩니다 (init 없이):\n\n```dart\nclass OtherClass extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      body: Center(\n        child: GetBuilder<Controller>(\n          builder: (s) => Text('${s.counter}'),\n        ),\n      ),\n    );\n  }\n\n```\n\nGetBuilder 밖의 여러 곳에서 controller를 사용해야 하는 경우, 간단하게 Controller 클래스 안의 getter로 접근할 수 있습니다. (아니면 `Get.find<Controller>()`를 사용하세요)\n\n```dart\nclass Controller extends GetxController {\n\n  /// You do not need that. I recommend using it just for ease of syntax.\n  /// with static method: Controller.to.increment();\n  /// with no static method: Get.find<Controller>().increment();\n  /// 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.\n  static Controller get to => Get.find(); // add this line\n\n  int counter = 0;\n  void increment() {\n    counter++;\n    update();\n  }\n}\n```\n\n그리고 아래와 같은 방법으로, controller에 바로 접근하세요:\n\n```dart\nFloatingActionButton(\n  onPressed: () {\n    Controller.to.increment(),\n  } // This is incredibly simple!\n  child: Text(\"${Controller.to.counter}\"),\n),\n```\n\nFloatingActionButton을 눌렀을 때, counter 변수를 주시(listen)하고 있는 위젯은 자동적으로 업데이트됩니다.\n\n### controller의 동작 방식\n\n아래와 같은 상황을 가정해보겠습니다:\n\n`Class A => Class B (has controller X) => Class C (has controller X)`\n\nA 클래스에서 controller를 아직 사용하지 않았기 때문에, controller는 메모리에 없습니다(Get은 lazyLoad를 지원합니다). B 클래스에서는 controller를 사용하기 때문에 메모리에 로드됩니다. C 클래스에서는 B 클래스에서 사용한 controller와 같은 controller를 사용하기 때문에, Get은 B의 controller와 C의 controller의 상태를 공유하며, 그 동일한 controller는 여전히 메모리에 있습니다. 그리고 C 화면과 B 화면을 닫으면, Get은 자동적으로 controller X (B와 C에서 쓰인 controller)를 메모리에서 해제해줄 것입니다. 왜냐하면 A 클래스에서는 controller X를 사용하지 않기 때문이죠. 만약 B 화면으로 라우팅한다면 controller X는 다시 메모리에 로드됩니다. 그리고 C 화면으로 라우팅되는 대신, A 화면으로 되돌아간다면 같은 방식으로 controller X는 메모리에서 해제됩니다. 만약 클래스 C에서 controller를 사용하지 않고, 클래스 B가 메모리에서 해제된다면, controller를 사용하는 클래스가 없기 때문에 같은 방식으로 controller는 메모리에서 해제됩니다. Get이 에러날 수 있는 유일한 예외 상황은 B가 예기치않게 라우트 상에서 제거되고, C에서 controller를 사용하려고 하는 경우입니다. 이 경우, B에 있던 controller의 creator ID가 제거되는데, Get은 creator ID를 갖고 있지 않은 controller는 메모리에서 제거하도록 프로그래밍되어 있습니다. 이런 일을 원하지 않으신다면, \"authoRemove: false\" 플래그를 B 클래스의 GetBuilder에 추가하고, \"assignId: true\"를 C 클래스의 GetBuilder에 추가해주세요.\n\n### StatefulWidget을 더 이상 사용할 필요없습니다\n\nSatefullWidget을 사용한다는 것은 위젯을 최소한으로 재빌드해야하는 경우에도, 위젯을 Consumer / Oberver / BlocProvider / GetBuilder / GetX / Obx 안에 넣어줄 것이기 때문에, 또다른 StatefulWidget을 사용하는 것과 마찬가지이므로 화면 전체의 상태를 불필요하게 저장합니다. StatefulWidget 클래스는 StatelessWidget 클래스보다 더 많은 RAM 할당이 필요한 큰 규모의 클래스입니다. 1개나 2개 정도의 클래스라면 별 차이가 없겠지만, 100개 이상부터는 차이가 있을 것입니다! TickerProviderStateMixin과 같은 mixin이 필요없는 경우, Get을 사용하면 StatefulWidget은 필요 없습니다.\n\nStatefulWidget에서 메소드를 직접적으로 호출하는 것처럼, Getbuilder를 통해 메소드를 호출할 수 있습니다.\ninitState()나 dispose()를 호출할 필요가 있을 때에도, 직접적으로 호출할 수 있습니다.\n\n```dart\nGetBuilder<Controller>(\n  initState: (_) => Controller.to.fetchApi(),\n  dispose: (_) => Controller.to.closeStreams(),\n  builder: (s) => Text('${s.username}'),\n),\n```\n\n위 방법보다 더 좋은 방법은 Controller에서 onInit()과 onClose()를 이용하는 것입니다.\n\n```dart\n@override\nvoid onInit() {\n  fetchApi();\n  super.onInit();\n}\n```\n\n- 참고: controller가 처음 불려졌을 때 어떤 메소드가 호출되길 원하는 경우, (좋은 성능을 목표로하는 Get 패키지를 이용하면)이를 위해서 생성자를 **사용할 필요가 없습니다**. 생성자를 사용한다는 것은 controller가 생성되거나 할당되었을 때의 로직에서 벗어나는 일이기 때문에 좋지 않습니다. (controller 객체를 생성하려하면 생성자는 즉시 호출되며, controller를 사용하기 이전부터 메모리에 로드됩니다. 이러한 동작은 이 라이브러리의 성능을 저해합니다.) onInit()과 onClose()는 이를 위해 만들어졌습니다. Get.lazyPut하는지 여부에 따라, controller가 생성되거나 처음 사용될 때 onInit()과 onClose()가 호출됩니다. API를 호출하기 위한 데이터를 초기화 등을 위해 구식 방식의 initState/dispose를 사용하는 대신 onInit()을 사용하고, stream을 닫는 등의 동작이 필요하면 onClose()를 사용하세요. \n\n### 이 패키지의 목표\n\n이 패키지의 목표는 당신에게 최소의 종속성(pubspec의 dependencies)으로 라우트/상태/종속성 관리를 위한 완전한 솔루션을 제공하는 것입니다. Get은 어떤 종속성에서도, 어떤 버전의 Flutter API를 사용하더라도 동작하도록 보장해줍니다. 어떤 종속성에서도 당신의 프로젝트가 동작하도록 단일 패키지로 모든 것을 집약하였습니다. 이런 방법으로 당신은 화면상 위젯들만 신경쓰고, 팀원 중 일부는 비즈니스 로직에만 신경쓸 수 있도록 하였습니다. 이 점은 당신에게 더 나은 작업환경을 제공합니다.  팀원 중 일부는 controller에 보내지는 데이터에 신경 쓰지 않고 위젯에만 집중하고, 다른 팀원들은 위젯 배치에는 신경쓰지 않고 비즈니스 로직에만 집중하여 작업할 수 있습니다.\n\n간단히 말하면: 여러 메소드들을 initState에서 호출할 필요도 없고, 메소드들을 parameter로 controller에 넘겨줄 필요 없고, controller 생성자를 호출할 필요도 없습니다. 여러분의 서비스가 시작하고 호출되는 onInit()를 이용하면 됩니다. 그리고 controller가 더 이상 필요 없을 때 메모리에서 제거 될 때 호출되는 onClose()를 이용하세요. 이 방법으로 화면 구성은 위젯 배치만 신경써도 되게 해줍니다.\n\nGetxController 안에서 dispose를 호출하지 마세요. 아무동작도 하지 않을 뿐더러 controller는 위젯이  아니기 때문에 \"dispose\"할 수 없다는 점을 기억하세요. Get에 의해 자동적으로 똑똑하게 메모리에서 해제 될 것입니다. 만약 stream들을 닫고 싶다면 onClose() 메소드 안에서 닫아주세요. 예를 들어:\n\n```dart\nclass Controller extends GetxController {\n  StreamController<User> user = StreamController<User>();\n  StreamController<String> name = StreamController<String>();\n\n  /// dispose가 아니라 onClose()에서 stream을 닫으세요\n  @override\n  void onClose() {\n    user.close();\n    name.close();\n    super.onClose();\n  }\n}\n```\n\nController 생명 주기:\n\n- onInit()은 생성되었을 때 호출\n- onClose()는 delete 메소드를 준비하기 위해 닫히는 경우\n- deleted: controller가 메모리에서 해제되어 더 이상 API에 접근할 수 없을 때. 말 그대로 삭제되어 추적할 수 없습니다.\n\n### 다른 사용법\n\nController 객체를 GetBuilder 안에서 value로 직접 접근할 수 있습니다:\n\n```dart\nGetBuilder<Controller>(\n  init: Controller(),\n  builder: (value) => Text(\n    '${value.counter}', // 여기!\n  ),\n),\n```\n\nGetBuilder 바깥에서도 controller 객체가 필요하면, 다음과 같이 접근할 수 있습니다:\n\n```dart\nclass Controller extends GetxController {\n  static Controller get to => Get.find();\n[...]\n}\n// 화면상\nGetBuilder<Controller>(  \n  init: Controller(), // 각 controller를 처음 사용할 때 init 하세요\n  builder: (_) => Text(\n    '${Controller.to.counter}', // 여기!\n  )\n),\n```\n\n아니면\n\n```dart\nclass Controller extends GetxController {\n // static Controller get to => Get.find(); // static get 없이\n[...]\n}\n// stateless/stateful 클래스에서\nGetBuilder<Controller>(  \n  init: Controller(), // 각 controller를 처음 사용할 때 init 하세요\n  builder: (_) => Text(\n    '${Get.find<Controller>().counter}', // 여기!\n  ),\n),\n```\n\n- \"비표준\"적인 방식의 접근도 다음과 같이 가능합니다. get_it, modular 등과 같은 다른 종속성 관리자를 사용한다면, 아래와 같이 controller 객체를 전달해줄 수 있습니다:\n\n```dart\nController controller = Controller();\n[...]\nGetBuilder<Controller>(\n  init: controller, // 여기!\n  builder: (_) => Text(\n    '${controller.counter}', // 여기!\n  ),\n),\n\n```\n\n### 고유 ID\n\nGetBuilder로 위젯의 업데이트를 좀 더 세분화하여 다루고 싶다면, 고유 ID를 부여하세요:\n\n```dart\nGetBuilder<Controller>(\n  id: 'text'\n  init: Controller(), // 각 controller를 처음 사용할 때 init 하세요\n  builder: (_) => Text(\n    '${Get.find<Controller>().counter}', // 여기!\n  ),\n),\n```\n\n그리고 다음과 같이 update 하세요:\n\n```dart\nupdate(['text']);\n```\n\n또, update하는데 조건도 줄 수 있습니다:\n\n```dart\nupdate(['text'], counter < 10);\n```\n\nGetX는 위젯이 정말 값이 변경되었을 때에만 재빌드합니다. 만약 변수의 값이 전과 같은 값으로 변경되었다면, GetX는 메모리와 CPU 자원을 아끼기 위해 재빌드하지 않습니다.(화면에 3이라는 숫자가 보여지고 있고, 그 숫자가 다시 3으로 변경된 경우를 가정하겠습니다. 대부분의 상태 관리자들은 이러한 경우에 재빌드를 합니다만, GetX를 사용하면 정말 값이 변경되었을 때에만 재빌드를 합니다.)\n\n## 2개의 상태 관리자 섞어쓰기\n\n단 하나의 반응변수(.obs)와 다른 메커니즘(update())가 모두 필요해서 Getbuilder 안에 Obx를 넣어야 하는 경우가 필요했습니다. 이 경우를 위해 MixinBuilder가 만들어졌습니다. \".obs\"변수의 값이 바뀔 때 즉각적으로 바뀌는 것과 update()를 통해 바뀌는 것 모두를 지원합니다. 하지만, 이 위젯이 GetBuilder, GetX, Obx 보다 더 많은 리소스를 필요로합니다. 왜냐하면 controller의 update() 메소드와 자식으로부터의 .obs 변수의 변화를 주시하고 있어야 하기 때문입니다.\n\nGetxController를 상속(extends)하는 것은 중요합니다. onInit()과 onClose()에서 \"시작\"과 \"종료\" 이벤트를 수행할 수 있는 생명 주기를 갖고 있기 때문입니다. 이를 위해서 어떤 클래스를 사용해도 괜찮지만, obervable한 변수든 아니든 간에 GetXController를 사용해 변수를 다루길 적극 권장합니다.\n\n\n## GetBuilder vs GetX vs Obx vs MixinBuilder\n\n10년간 프로그래밍을 하며 일해오면서, 귀중한 교훈을 얻을 수 있었습니다.\n\n반응형 프로그래밍을 처음 접했을 때 \"와, 진짜 굉장한데!\"라고 느꼈고, 실제로도 반응형 프로그래밍은 정말 놀랍습니다. 하지만, 모든 상황에서 올바르지는 않습니다. 많은 경우 2개내지 3개의 위젯의 상태를 동시에 변경하거나 일시적으로 변경해야하는데, 반응형 프로그래밍은 나쁘지 않지만 적적하지 않습니다.\n\n반응형 프로그래밍은 각각의 워크플로우를 위한 RAM 자원을 많이 필요로 합니다. 하나의 위젯만이 재빌드 되어야 하는 경우는 괜찮지만, 리스트에 80개 가량의 요소가 있고, 각각 stream이 있을 경우에는 좋지 않습니다. dart inspect 창을 열고 StreamBuilder가 얼마나 많은 리소스를 사용하는지 보신다면, 제 말이 이해가 가실겁니다.\n\n이런 생각에, 저는 간단한 상태 관리자를 만들었습니다. 간단합니다. 그리고 이것이 여러분이 정말 요구하는 것이에요: 블록 단위로 매우 경제적이고 간단하게 상태를 업데이트합니다. \n\n`GetBuilder`는 RAM의 측면에서 가장 경제적입니다. 이보다 더 경제적인 방법은 없을 겁니다(만약 그런 방법을 고안하신다면, 꼭 저희에게 알려주세요!)\n\n하지만 `GetBuilder`는 수동적인 상태 관리자입니다. Provider의 notifyListeners()를 호출하는 것처럼 update()를 호출해야만 합니다.\n\n반응형 프로그래밍이 정말 도움이 되는 상황들이 많습니다. 이를 활용하지 않는건 바퀴를 다시 만드는 것과 마찬가지입니다. 이런 생각에, `GetX`는 상태 관리자로 가장 현대적이고 높은 수준의 기능들을 제공하기 위해 만들어졌습니다. 이것은 필요한 것들을 필요한 때에 업데이트합니다. 만약 에러가 있고 300개의 상태가 동시에 변경되면, `GetX`는 화면상에 반영되어야할 것들만 필터링하여 업데이트 합니다.\n\n`GetX`는 다른 반응형 상태 관리자들보다 경제적이지만, `GetBuiler`보다 조금 더 RAM을 소모합니다. 능동적이면서 RAM의 최대한 효율적으로 사용하기 위해 `Obx`가 만들어졌습니다. `GetX`와 `GetBuilder`와 다르게 `Obx`안에서 controller를 초기화할 수 없습니다. 단지 자식으로부터 변화를 감지하는 StreamSubscription을 갖고 있는 위젯일 뿐입니다. `Obx`는 `GetX`보다는 경제적이지만 `GetBuilder`보다는 덜 경제적입니다. 왜냐하면 `Obx`는 반응적이고, `GetBuilder`는 위젯의 해시코드와 StateSetter만 저장하는 최적의 접근 방식을 갖고 있기 때문입니다. `Obx`를 이용하면 controller의 타입을 적어줄 필요가 없고, 여러 개의 다른 controller 변화를 감지합니다. 하지만 사용 전에 초기화거나, readme에 있는 예제처럼 사용하거나, Binding 클래스를 사용해야 합니다.\n"
  },
  {
    "path": "documentation/pt_BR/dependency_management.md",
    "content": "# Gerenciamento de dependência\n- [Gerenciamento de dependência](#gerenciamento-de-dependência)\n  - [Gerenciamento de dependências simples](#gerenciamento-de-dependências-simples)\n  - [Métodos de criar instâncias](#métodos-de-criar-instâncias)\n    - [Get.put()](#getput)\n    - [Get.lazyPut](#getlazyput)\n    - [Get.putAsync](#getputasync)\n    - [Get.create](#getcreate)\n  - [Usando as classes/dependências instanciadas](#usando-as-classesdependências-instanciadas)\n  - [Diferenças entre os métodos](#diferenças-entre-os-métodos)\n  - [Bindings](#bindings)\n    - [Classe Bindings](#classe-bindings)\n    - [BindingsBuilder](#bindingsbuilder)\n    - [SmartManagement](#smartmanagement)\n      - [Como alterar](#como-alterar)\n      - [SmartManagement.full](#smartmanagementfull)\n      - [SmartManagement.onlyBuilders](#smartmanagementonlybuilders)\n      - [SmartManagement.keepFactory](#smartmanagementkeepfactory)\n      - [Como os Bindings funcionam](#como-os-bindings-funcionam)\n  - [Notas](#notas)\n\nGet tem um gerenciador de dependência simples e poderoso que permite você pegar a mesma classe que seu Bloc ou Controller com apenas uma linha de código, sem Provider context, sem inheritedWidget:\n\n```dart\nController controller = Get.put(Controller()); // Em vez de Controller controller = Controller();\n```\n\nEm vez de instanciar sua classe dentro da classe que você está usando, você está instanciando ele dentro da instância do Get, que vai fazer ele ficar disponível por todo o App\n\nPara que então você possa usar seu controller (ou uma classe Bloc) normalmente\n\n- Nota: Se você está usando o gerenciado de estado do Get, você não precisa se preocupar com isso, só leia a documentação, mas dê uma atenção a api [Bindings](#bindings), que vai fazer tudo isso automaticamente para você.\n- Nota²: O gerenciamento de dependência do get é desacoplado de outras partes do package, então se por exemplo seu aplicativo já está usando um outro gerenciador de estado (qualquer um, não importa), você não precisa de reescrever tudo, pode simplesmente usar só a injeção de dependência sem problemas\n\n## Métodos de criar instâncias\nTodos os métodos e seus parâmetros configuráveis são:\n\n### Get.put()\nA forma mais comum de instanciar uma dependência. Bom para os controllers das views por exemplo.\n\n```dart\nGet.put<Classe>(Classe());\n\nGet.put<LoginController>(LoginController(), permanent: true);\n\nGet.put<ListItemController>(\n  ListItemController,\n  tag: \"uma string única\",\n);\n```\n\nE essas são todas as opções que você pode definir:\n```dart\nGet.put<S>(\n  // obrigatório: a classe que você quer salvar, como um controller ou qualquer outra coisa\n  // obs: Esse \"S\" significa que pode ser qualquer coisa\n  S dependency\n\n  // opcional: isso é pra quando você quer múltiplas classess que são do mesmo tipo\n  // já que você normalmente pega usando \"Get.find<Controller>()\",\n  // você precisa usar uma tag para dizer qual das instâncias vc precisa\n  // precisa ser uma string única\n  String tag,\n\n  // opcional: por padrão, get vai descartar as instâncias quando elas não são mais usadas (exemplo,\n  // o controller de uma view que foi fechada) // Mas talvez você precisa quea instância seja mantida por todo o app, como a instância do SharedPreferences por exemplo\n  // então vc usa isso\n  // padrão: false\n  bool permanent = false,\n\n  // opcional: permite criar a dependência usando uma função em vez da dependênia em si\n  InstanceBuilderCallback<S> builder,\n)\n```\n\n### Get.lazyPut\nÉ possível que você vá inserir essa instância, mas sabe que não vai usá-la imediatamente no app.\nNesses casos pode ser usado o lazyPut que só cria a instância no momento que ela for necessária pela primeira vez.\nÉ útil também caso seja uma classe que é muito pesada e você não quer carregar ela junto com tudo quando o app abre.\n\n```dart\n/// ApiMock só será instanciado quando Get.find<ApiMock> for usado pela primeira vez\nGet.lazyPut<ApiMock>(() => ApiMock());\n\nGet.lazyPut<FirebaseAuth>(\n  () {\n    // ... alguma lógica se necessário\n    return FirebaseAuth();\n  },\n  tag: Math.random().toString(),\n  fenix: true\n)\n\nGet.lazyPut<Controller>( () => Controller() )\n```\n\nE essas são todas as opções que você pode definir:\n```dart\nGet.lazyPut<S>(\n  // obrigatório: um método que vai ser executado quando sua classe é chamada pela primeira vez\n  InstanceBuilderCallback builder,\n  \n  // opcional: igual ao Get.put(), é usado quando você precisa de múltiplas instâncias de uma mesma classe\n  // precisa ser uma string única\n  String tag,\n\n  // opcional: é similar a \"permanent\", mas a instância é descartada quando\n  // não é mais usada e é refeita quando precisa ser usada novamente\n  // Assim como a opção SmartManagement.keepFactory na api Bindings\n  // padrão: false\n  bool fenix = false\n  \n)\n```\n\n### Get.putAsync\nSe você quiser criar uma instância assíncrona, você pode usar `Get.putAsync`:\n\n```dart\nGet.putAsync<SharedPreferences>(() async {\n  final prefs = await SharedPreferences.getInstance();\n  await prefs.setInt('counter', 12345);\n  return prefs;\n});\n\nGet.putAsync<SuaClasseAssincrona>( () async => await SuaClasseAssincrona() )\n```\n\nE essas são todas as opções que você pode definir:\n```dart\nGet.putAsync<S>(\n\n  // Obrigatório: um método assíncrono que vai ser executado para instanciar sua classe\n  AsyncInstanceBuilderCallback<S> builder,\n\n  // opcional: igual ao Get.put(), é usado quando você precisa de múltiplas instâncias de uma mesma classe\n  // precisa ser uma string única\n  String tag,\n\n  // opcional: igual ao Get.put(), usado quando você precisa manter a instância ativa no app inteiro.\n  // padrão: false\n  bool permanent = false\n```\n\n### Get.create\nEsse é mais específico. Uma explicação detalhada do que esse método é e as diferenças dele para os outros podem ser encontradas em [Diferenças entre os métodos](#diferenças-entre-os-métodos)\n\n\n```dart\nGet.Create<SomeClass>(() => SomeClass());\nGet.Create<LoginController>(() => LoginController());\n```\n\nE essas são todas as opções que você pode definir:\n```dart\nGet.create<S>(\n  // Obrigatório: Uma função que retorna uma classe que será \"fabricada\" toda vez que Get.find() for chamado\n  InstanceBuilderCallback<S> builder,\n\n  // opcional: igual ao Get.put(), mas é usado quando você precisa de múltiplas instâncias de uma mesma classe. \n  // Útil caso você tenha uma lista em que cada item precise de um controller próprio\n  // precisa ser uma string única. Apenas mudou o nome de tag para name.\n  String name,\n\n  // opcional: igual ao Get.put(), usado quando você precisa manter a instância ativa no app inteiro. A diferença\n  // é que com Get.create o permanent está habilitado por padrão\n  bool permanent = true\n```\n\n## Usando as classes/dependências instanciadas\n\nAgora, imagine que você navegou por inúmeras rotas e precisa de dados que foram deixados para trás em seu controlador. Você precisaria de um gerenciador de estado combinado com o Provider ou Get_it, correto? Não com Get. Você só precisa pedir ao Get para \"procurar\" pelo seu controlador, você não precisa de nenhuma dependência adicional para isso:\n\n```dart\nfinal controller = Get.find<Controller>();\n// OU\nController controller = Get.find();\n// Sim, parece Magia, o Get irá descobrir qual é seu controller, e irá te entregar.\n// Você pode ter 1 milhão de controllers instanciados, o Get sempre te entregará o controller correto.\n// Apenas se lembre de Tipar seu controller, final controller = Get.find(); por exemplo, não irá funcionar.\n```\n\nE então você será capaz de recuperar os dados do seu controller que foram obtidos anteriormente:\n\n```dart\nText(controller.textFromApi);\n```\n\nJá que o valor retornado é uma classe normal, você pode fazer o que quiser com ela:\n\n```dart\nint valor = Get.find<SharedPreferences>().getInt('contador');\nprint(valor); // Imprime: 123456\n```\n\nPara remover a instância do Get:\n\n```dart\nGet.delete<Controller>();\n```\n\n## Diferenças entre os métodos\n\nPrimeiro, vamos falar do `fenix` do Get.lazyPut e o `permanent` dos outros métodos.\n\nA diferença fundamental entre `permanent` e `fenix` está em como você quer armazenar as suas instâncias.\n\nReforçando: por padrão, o Get apaga as instâncias quando elas não estão em uso.\nIsso significa que: Se a tela 1 tem o controller 1 e a tela 2 tem o controller 2 e você remove a primeira rota da stack (usando `Get.off()` ou `Get.offNamed`), o controller 1 perdeu seu uso portanto será apagado.\n\nMas se você optar por usar `permanent: true`, então ela não se perde nessa transição - o que é muito útil para serviços que você quer manter rodando na aplicação inteira.\n\nJá o `fenix`, é para serviços que você não se preocupa em perder por uma tela ou outra, mas quando você precisar chamar o serviço, você espera que ele \"retorne das cinzas\" (`fenix: true`), criando uma nova instância.\n\nProsseguindo com as diferenças entre os métodos:\n\n- Get.put e Get.putAsync seguem a mesma ordem de criação, com a diferença que o Async opta por aplicar um método assíncrono: Esses dois métodos criam e já inicializam a instância. Esta é inserida diretamente na memória, através do método interno `insert` com os parâmetros `permanent: false` e `isSingleton: true` (esse parâmetro `isSingleton` serve apenas para dizer se é para utilizar a dependência colocada em `dependency`, ou se é para usar a dependência colocada no `InstanceBuilderCallback`). Depois disso, é chamado o `Get.find` que imediatamente inicializa as instâncias que estão na memória. \n\n- Get.create: Como o nome indica, você vai \"criar\" a sua dependência! Similar ao `Get.put`, ela também chama o método interno `insert` para instanciamento. Contudo, `permanent` e `isSingleton` passam a ser `true` e `false` (Como estamos \"criando\" a nossa dependência, não tem como ela ser um Singleton de algo, logo, `false`). E por ser `permanent: true`, temos por padrão o benefício de não se perder entre telas! Além disso, não é chamado o `Get.find`, logo ela fica esperando ser chamada para ser usada. Ele é criado dessa forma para aproveitar o uso do parâmetro `permanent`, já que, vale ressaltar, o Get.create foi criado com o objetivo de criar instâncias não compartilhadas, mas que não se perdem, como por exemplo um botão em um listView, que você quer uma instância única para aquela lista - por conta disso, o Get.create deve ser usado em conjunto com o GetWidget. \n\n- Get.lazyPut: Como o nome dá a entender, é um processo preguiçoso (lazy). A instância é criada, mas ela não é chamada para uso logo em seguida, ela fica aguardando ser chamada. Diferente dos outros métodos, o `insert` não é chamado. Ao invés disso, a instância é inserida em outra parte na memória, uma parte responsável por dizer se a instância pode ser recriada ou não, vamos chamá-la de \"fábrica\". Se queremos criar algo para ser chamado só depois, não vamos misturá-lo com as coisas que estão sendo usadas agora. E é aqui que entra a mágica do `fenix`. Se você optou por deixar `fenix: false`, e seu `smartManagement` não for `keepFactory`, então ao usar o `Get.find` a instância passa da \"fábrica\" para a área comum das instância. Em seguinda, por padrão é removida da \"fábrica\". Agora, se você optou por  `fenix: true`, a instância continua a existir nessa parte dedicada, mesmo indo para a área comum, para ser chamada futuramente caso precise. \n\n## Bindings\n\nUm dos grandes diferenciais desse package, talvez, seja a possibilidade de integração total com rotas, gerenciador de estado e gerenciador de dependências.\n\nQuando uma rota é removida da stack, todos os controllers, variáveis e instâncias de objetos relacionados com ela são removidos da memória. Se você está usando streams ou timer, eles serão fechados automaticamente, e você não precisa se preocupar com nada disso.\n\nNa versão 2.10 Get implementou completamente a API Bindings.\n\nAgora você não precisa mais usar o método `init`. Você não precisa nem tipar seus controllers se não quiser. Você pode começar seus controllers e services num lugar apropriado para isso.\n\nA classe Binding é uma classe que vai desacoplar a injeção de dependência, enquanto liga as rotas ao gerenciador de estados e o gerenciador de dependências.\n\nIsso permite Get saber qual tela está sendo mostrada quando um controller particular é usado e saber onde e como descartar o mesmo.\n\nSomando a isso, a classe Binding vai permitir que você tenha um controle de configuração SmartManager. Você pode configurar as dependências que serão organizadas quando for remover a rota da stack, ou quando o widget que usa ele é definido, ou nada disso. Você vai ter gerenciador de dependências inteligente trabalhando para você, e você pode configurá-lo como quiser.\n\n### Classe Bindings\n\nCrie uma classe qualquer que implemente a Bindings.\n\n```dart\nclass HomeBinding implements Bindings {}\n```\n\nSua IDE vai automaticamente te perguntar para dar override no método `dependencies()`, aí você clica na lâmpada, clica em \"override the method\", e insira todas as classes que você vai usar nessa rota:\n\n```dart\nclass HomeBinding implements Bindings{\n  @override\n  void dependencies() {\n    Get.lazyPut<HomeController>(() => HomeController());\n    Get.lazyPut<Service>(()=> Api());\n  }\n}\n\nclass DetalhesBinding implements Bindings {\n  @override\n  void dependencies() {\n    Get.lazyPut<DetalhesController>(() => DetalhesController());\n  }\n}\n```\n\nAgora você só precisa informar sua rota que você vai usar esse binding para fazer a conexão entre os gerenciadores de rotas, dependências e estados.\n\nUsando rotas nomeadas\n\n```dart\ngetPages: [\n  GetPage(\n    name: '/',\n    page: () => HomeView(),\n    binding: HomeBinding(),\n  ),\n  GetPage(\n    name: '/detalhes',\n    page: () => DetalhesView(),\n    binding: DetalhesBinding(),\n  ),\n];\n```\n\nUsando rotas normais:\n\n```dart\nGet.to(Home(), binding: HomeBinding());\nGet.to(DetalhesView(), binding: DetalhesBinding())\n```\n\nEntão, você não vai precisar se preocupar com gerenciamento da memória da sua aplicação mais, Get vai fazer para você.\n\nA classe Bindings é chamada quando uma rota é chamada. Você pode criar uma Binding inicial no seu GetMaterialApp para inserir todas as dependências que serão criadas.\n\n```dart\nGetMaterialApp(\n  initialBinding: SampleBind(),\n  home: Home(),\n)\n```\n\n### BindingsBuilder\n\nA forma padrão de criar um binding é criando uma classe que implementa o Bindings.\n\nMas alternativamente, você também pode usar a função `BindingsBuilder` par que você possa simplesmente usar uma função pra criar essas instâncias\n\nExemplo:\n\n```dart\ngetPages: [\n  GetPage(\n    name: '/',\n    page: () => HomeView(),\n    binding: BindingsBuilder(() {\n      Get.lazyPut<ControllerX>(() => ControllerX());\n      Get.put<Service>(()=> Api());\n    }),\n  ),\n  GetPage(\n    name: '/detalhes',\n    page: () => DetalhesView(),\n    binding: BindingsBuilder(() {\n      Get.lazyPut<DetalhesController>(() => DetalhesController());\n    }),\n  ),\n];\n```\n\nDessa forma você pode evitar criar uma classe Binding para cada rota, deixando tudo mais simples.\n\nAs duas formas funcionam perfeitamente e você é livre para usar o que mais se encaixa no seu estilo de uso\n\n### SmartManagement\n\nGetX por padrão descarta controllers não utilizados da memória, mesmo que uma falha ocorra e um widget que usa ele não for propriamente descartado.\nEssa é o chamado modo `full` do gerenciamento de dependências.\nMas se você quiser mudar a forma que o GetX controla o descarte das classes, você tem a sua disposição a classe `SmartManagement` que pode definir diferentes comportamentos.\n\n#### Como alterar\n\nSe você quiser alterar essa configuração (que normalmente você não precisa mudar) essa é a forma:\n\n```dart\nvoid main () {\n  runApp(\n    GetMaterialApp(\n      smartManagement: SmartManagement.onlyBuilders //Aqui\n      home: Home(),\n    )\n  )\n}\n```\n\n#### SmartManagement.full\n\nÉ o padrão. Descarta as classes que não estão mais sendo utilizadas e que não foram definidas para serem permanents. Na grande maioria dos casos você não vai querer nem precisar alterar essa configuração. Se você for novo com GetX, não altere isto.\n\n#### SmartManagement.onlyBuilders\nCom essa opção, somente controllers iniciados pelo `init:` or iniciados dentro de um Binding com `Get.lazyPut()` serão descartados.\n\nSe você usar `Get.put()` ou `Get.putAsync()` or qualquer outra forma, SmartManagement não vai ter permissão para excluir essa dependência.\n\nCom o comportamento padrão, até widgets instanciados com `Get.put()` serão removidos, ao contrário do `SmartManagement.onlyBuilders`.\n\n#### SmartManagement.keepFactory\n\nAssim como o modo `full`, ele vai descartar as dependências quando não estiverem sendo mais utilizadas. Porém, ele irá manter a \"factory\" de cada dependência. Isso significa que caso você precise de da dependência novamente, ele vai recriar aquele instância novamente.\n\n#### Como os Bindings funcionam\nBindings cria fábricas transitórias, que são criadas no momento que você clica para ir para outra tela, e será destruído assim que a animação de mudança de tela acontecer.\nÉ tão pouco tempo, tão rápido, que o analyzer sequer conseguirá registrá-lo.\nQuando você navegar para essa tela novamente, uma nova fábrica temporária será chamada, então isso é preferível à usar `SmartManagement.keepFactory`, mas se você não quer ter o trabalho de criar Bindings, ou deseja manter todas suas dependências no mesmo Binding, isso certamente irá te ajudar.\nFábricas ocupam pouca memória, elas não guardam instâncias, mas uma função com a \"forma\" daquela classe que você quer.\nIsso é muito pouco, mas como o objetivo dessa lib é obter o máximo de desempenho possível usando o mínimo de recursos, Get remove até as fábricas por padrão. Use o que achar mais conveniente para você.\n\n## Notas\n\n* Nota: NÃO USE SmartManagement.keepfactory se você está usando vários Bindings. Ele foi criado para ser usado sem Bindings, ou com um único Binding ligado ao GetMaterialApp lá no `initialBinding`\n\n* Nota²: Usar Bindings é completamente opcional, você pode usar Get.put() e Get.find() em classes que usam o controller sem problemas. Porém, se você trabalhar com Services ou qualquer outra abstração, eu recomendo usar Bindings. Especialmente em grandes empresas.\n"
  },
  {
    "path": "documentation/pt_BR/route_management.md",
    "content": "- [Navegação sem rotas nomeadas](#navegação-sem-rotas-nomeadas)\n  - [SnackBars](#snackbars)\n  - [Dialogs](#dialogs)\n  - [BottomSheets](#bottomsheets)\n- [Navegar com rotas nomeadas](#navegar-com-rotas-nomeadas)\n  - [Enviar dados para rotas nomeadas](#enviar-dados-para-rotas-nomeadas)\n    - [Links de Url dinâmicos](#links-de-url-dinâmicos)\n    - [Middleware](#middleware)\n  - [Change Theme](#change-theme)\n  - [Configurações Globais Opcionais](#configurações-globais-opcionais)\n  - [Nested Navigators](#nested-navigators)\n\n## Navegação sem rotas nomeadas\n\nPara navegar para uma próxima tela:\n\n```dart\nGet.to(ProximaTela());\n```\n\nPara fechar snackbars, dialogs, bottomsheets, ou qualquer coisa que você normalmente fecharia com o `Navigator.pop(context)` (como por exemplo fechar a View atual e voltar para a anterior):\n\n```dart\nGet.back();\n```\n\nPara ir para a próxima tela e NÃO deixar opção para voltar para a tela anterior (bom para SplashScreens, telas de login e etc.):\n\n```dart\nGet.off(ProximaTela());\n```\n\nPara ir para a próxima tela e cancelar todas as rotas anteriores (útil em telas de carrinho, votações ou testes):\n\n```dart\nGet.offAll(ProximaTela());\n```\n\nPara navegar para a próxima rota, e receber ou atualizar dados assim que retornar da rota:\n\n```dart\nvar dados = await Get.to(Pagamento());\n```\n\nNa outra tela, envie os dados para a rota anterior:\n\n```dart\nGet.back(result: 'sucesso');\n```\n\nE use-os:\n\n```dart\nif (dados == 'sucesso') fazerQualquerCoisa();\n```\n\nNão quer aprender nossa sintaxe?\nApenas mude o `Navigator` (letra maiúscula) para `navigator` (letra minúscula), e você terá todas as funcionalidades de navegação padrão, sem precisar usar `context`\n\nExemplo:\n\n```dart\n// Navigator padrão do Flutter\nNavigator.of(context).push(\n  context,\n  MaterialPageRoute(\n    builder: (BuildContext context) {\n      return HomePage();\n    },\n  ),\n);\n\n// Get usando a sintaxe Flutter sem precisar do context\nnavigator.push(\n  MaterialPageRoute(\n      builder: (_) {\n      return HomePage();\n    },\n  ),\n);\n\n// Sintaxe do Get (é bem melhor, mas você tem o direito de discordar)\nGet.to(HomePage());\n```\n\n### SnackBars\n\nPara ter um `SnackBar` simples no Flutter, você precisa do `context` do Scaffold, ou uma `GlobalKey` atrelada ao seu Scaffold.\n\n```dart\nfinal snackBar = SnackBar(\n  content: Text('Olá!'),\n  action: SnackBarAction(\n    label: 'Eu sou uma SnackBar velha e feia :(',\n    onPressed: (){}\n  ),\n);\n// Encontra o Scaffold na árvore de Widgets e\n// o usa para mostrar o SnackBar\nScaffold.of(context).showSnackBar(snackBar);\n```\n\nCom o Get:\n\n```dart\nGet.snackbar('Olá', 'eu sou uma SnackBar moderna e linda!');\n```\n\nCom Get, tudo que você precisa fazer é chamar `Get.snackbar()` de qualquer lugar no seu código, e/ou customizá-lo da forma que quiser!\n\n```dart\nGet.snackbar(\n  \"Ei, eu sou uma SnackBar Get!\", // título\n  \"É inacreditável! Eu estou usando uma SnackBar sem context, sem boilerplate, sem Scaffold!\", // mensagem\n  icon: Icon(Icons.alarm),\n  shouldIconPulse: true,\n  onTap:(){},\n  barBlur: 20,\n  isDismissible: true,\n  duration: Duration(seconds: 3),\n);\n\n\n  ////////// TODOS OS RECURSOS //////////\n  //     Color colorText,\n  //     Duration duration,\n  //     SnackPosition snackPosition,\n  //     Widget titleText,\n  //     Widget messageText,\n  //     bool instantInit,\n  //     Widget icon,\n  //     bool shouldIconPulse,\n  //     double maxWidth,\n  //     EdgeInsets margin,\n  //     EdgeInsets padding,\n  //     double borderRadius,\n  //     Color borderColor,\n  //     double borderWidth,\n  //     Color backgroundColor,\n  //     Color leftBarIndicatorColor,\n  //     List<BoxShadow> boxShadows,\n  //     Gradient backgroundGradient,\n  //     TextButton mainButton,\n  //     OnTap onTap,\n  //     bool isDismissible,\n  //     bool showProgressIndicator,\n  //     AnimationController progressIndicatorController,\n  //     Color progressIndicatorBackgroundColor,\n  //     Animation<Color> progressIndicatorValueColor,\n  //     SnackStyle snackStyle,\n  //     Curve forwardAnimationCurve,\n  //     Curve reverseAnimationCurve,\n  //     Duration animationDuration,\n  //     double barBlur,\n  //     double overlayBlur,\n  //     Color overlayColor,\n  //     Form userInputForm\n  ///////////////////////////////////\n```\n\nSe você prefere a SnackBar tradicional, ou quer customizar por completo, como por exemplo fazer ele ter uma só linha (`Get.snackbar` tem os parâmetros `title` e `message` obrigatórios), você pode usar `Get.rawSnackbar();` que fornece a API bruta na qual `Get.snackbar` foi contruído.\n\n### Dialogs\n\nPara abrir um dialog:\n\n```dart\nGet.dialog(SeuWidgetDialog());\n```\n\nPara abrir um dialog padrão:\n\n```dart\nGet.defaultDialog(\n  onConfirm: () => print(\"Ok\"),\n  middleText: \"Dialog made in 3 lines of code\",\n);\n```\n\nVocê também pode usar `Get.generalDialog` em vez de `showGeneralDialog`.\n\nPara todos os outros Widgets do tipo dialog do Flutter, incluindo os do Cupertino, você pode usar `Get.overlayContext` em vez do `context`, e abrir em qualquer lugar do seu código.\n\nPara widgets que não usam `overlayContext`, você pode usar `Get.context`. Esses dois contextos vão funcionar em 99% dos casos para substituir o context da sua UI, exceto em casos onde o `inheritedWidget` é usado sem a navigation context.\n\n### BottomSheets\n\n`Get.bottomSheet()` é tipo o `showModalBottomSheet()`, mas não precisa do context.\n\n```dart\nGet.bottomSheet(\n  Container(\n    child: Wrap(\n      children: <Widget>[\n        ListTile(\n          leading: Icon(Icons.music_note),\n          title: Text('Música'),\n          onTap: () {}\n        ),\n        ListTile(\n          leading: Icon(Icons.videocam),\n          title: Text('Vídeo'),\n          onTap: () {},\n        ),\n      ],\n    ),\n  ),\n);\n```\n\n## Navegar com rotas nomeadas\n\n- Se você prefere navegar por rotas nomeadas, Get também dá suporte a isso:\n\nPara navegar para uma nova tela\n\n```dart\nGet.toNamed(\"/ProximaTela\");\n```\n\nPara navegar para uma tela sem a opção de voltar para a rota atual.\n\n```dart\nGet.offNamed(\"/ProximaTela\");\n```\n\nPara navegar para uma nova tela e remover todas rotas anteriores da stack\n\n```dart\nGet.offAllNamed(\"/ProximaTela\");\n```\n\nPara definir rotas, use o `GetMaterialApp`:\n\n```dart\nvoid main() {\n  runApp(\n    GetMaterialApp(\n      initialRoute: '/',\n      getPages: [\n        GetPage(name: '/', page: () => Home()),\n        GetPage(name: '/login', page: () => Login()),\n        GetPage(name: '/cadastro', page: () => Cadastro(), transition: Transition.cupertino),\n      ]\n    )\n  );\n}\n```\n\nPara lidar com a navegação para rotas não definidas (erro 404), você pode definir uma página unknownRoute em GetMaterialApp.\n\n```dart\nvoid main() {\n  runApp(\n    GetMaterialApp(\n      unknownRoute: GetPage(name: '/notfound', page: () => UnknownRoutePage()),\n      initialRoute: '/',\n      getPages: [\n        GetPage(name: '/', page: () => MyHomePage()),\n        GetPage(name: '/second', page: () => Second()),\n      ],\n    )\n  );\n}\n```\n\n### Enviar dados para rotas nomeadas\n\nApenas envie o que você quiser no parâmetro `arguments`. Get aceita qualquer coisa aqui, seja String, Map, List, ou até a instância de uma classe.\n\n```dart\nGet.toNamed(\"/ProximaTela\", arguments: 'Get é o melhor');\n```\n\nNa sua classe ou controller:\n\n```dart\nprint(Get.arguments); //valor: Get é o melhor\n```\n\n#### Links de Url dinâmicos\n\nGet oferece links de url dinâmicos assim como na Web.\nDesenvolvedores Web provavelmente já queriam essa feature no Flutter, e muito provavelmente viram um package que promete essa feature mas entrega uma sintaxe totalmente diferente do que uma url teria na web, mas o Get também resolve isso.\n\n```dart\nGet.offAllNamed(\"/ProximaTela?device=phone&id=354&name=Enzo\");\n```\n\nna sua classe controller/bloc/stateful/stateless:\n\n```dart\nprint(Get.parameters['id']); // valor: 354\nprint(Get.parameters['name']); // valor: Enzo\n```\n\nVocê também pode receber parâmetros nomeados com o Get facilmente:\n\n```dart\nvoid main() => runApp(\n  GetMaterialApp(\n    initialRoute: '/',\n    getPages: [\n      GetPage(name: '/', page: () => Home()),\n      /// Importante! ':user' não é uma nova rota, é somente uma\n      /// especificação do parâmentro. Não use '/segunda/:user/' e '/segunda'\n      /// se você precisa de uma nova rota para o user, então\n      /// use '/segunda/user/:user' se '/segunda' for uma rota\n      GetPage(name: '/segunda/:user', page: () => Segunda()), // recebe a ID\n      GetPage(name: '/terceira', page: () => Terceira(), transition: Transition.cupertino),\n    ]\n  ),\n);\n```\n\nEnvie dados na rota nomeada\n\n```dart\nGet.toNamed(\"/segunda/34954\");\n```\n\nNa segunda tela receba os dados usando `Get.parameters[]`\n\n```dart\nprint(Get.parameters['user']);\n// valor: 34954\n```\n\n\nou envie vários parâmetros como este\n\n```dart\nGet.toNamed(\"/profile/34954?flag=true\");\n```\n\nNa segunda tela, pegue os dados por parâmetros normalmente\n```dart\nprint(Get.parameters['user']);\nprint(Get.parameters['flag']);\n// valor: 34954 true\n```\n\n\n\nE agora, tudo que você precisa fazer é usar `Get.toNamed)` para navegar por suas rotas nomeadas, sem nenhum `context` (você pode chamar suas rotas diretamente do seu BLoc ou do Controller), e quando seu aplicativo é compilado para a web, suas rotas vão aparecer na url ❤\n\n#### Middleware\n\nSe você quer escutar eventos do Get para ativar ações, você pode usar `routingCallback` para isso\n\n```dart\nGetMaterialApp(\n  routingCallback: (route){\n    if(routing.current == '/segunda'){\n      openAds();\n    }\n  }\n)\n```\n\nSe você não estiver usando o `GetMaterialApp`, você pode usar a API manual para anexar um observer Middleware.\n\n```dart\nvoid main() {\n  runApp(\n    MaterialApp(\n      onGenerateRoute: Router.generateRoute,\n      initialRoute: \"/\",\n      navigatorKey: Get.key,\n      navigatorObservers: [\n        GetObserver(MiddleWare.observer), // AQUI !!!\n      ],\n    )\n  );\n}\n```\n\nCriar uma classe MiddleWare\n\n```dart\nclass MiddleWare {\n  static observer(Routing routing) {\n    /// Você pode escutar junto com as rotas, snackbars, dialogs\n    /// e bottomsheets em cada tela.\n    /// Se você precisar entrar em algum um desses 3 eventos aqui diretamente,\n    /// você precisa especificar que o evento é != do que você está tentando fazer\n    if (routing.current == '/segunda' && !routing.isSnackbar) {\n      Get.snackbar(\"Olá\", \"Você está na segunda rota\");\n    } else if (routing.current =='/terceira'){\n      print('última rota chamada');\n    }\n  }\n}\n```\n\nAgora, use Get no seu código:\n\n```dart\nclass Primeira extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        leading: IconButton(\n          icon: Icon(Icons.add),\n          onPressed: () {\n            Get.snackbar(\"Oi\", \"eu sou uma snackbar moderna\");\n          },\n        ),\n        title: Text('Primeira rota'),\n      ),\n      body: Center(\n        child: ElevatedButton(\n          child: Text('Abrir rota'),\n          onPressed: () {\n            Get.toNamed(\"/segunda\");\n          },\n        ),\n      ),\n    );\n  }\n}\n\nclass Segunda extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        leading: IconButton(\n          icon: Icon(Icons.add),\n          onPressed: () {\n            Get.snackbar(\"Oi\", \"eu sou uma snackbar moderna\");\n          },\n        ),\n        title: Text('Segunda rota'),\n      ),\n      body: Center(\n        child: ElevatedButton(\n          child: Text('Abrir rota'),\n          onPressed: () {\n            Get.toNamed(\"/terceira\");\n          },\n        ),\n      ),\n    );\n  }\n}\n\nclass Terceira extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: Text(\"Terceira Rota\"),\n      ),\n      body: Center(\n        child: ElevatedButton(\n          onPressed: () {\n            Get.back();\n          },\n          child: Text('Voltar!'),\n        ),\n      ),\n    );\n  }\n}\n```\n\n### Change Theme\n\nPor favor não use nenhum widget acima do `GetMaterialApp` para atualizá-lo. Isso pode ativar keys duplicadas. Muitas pessoas estão acostumadas com a forma pré-história de criar um widget `ThemeProvider` só pra mudar o tema do seu app, e isso definitamente NÃO é necessário com o Get.\n\nVocê pode criar seu tema customizado e simplesmente adicionar ele dentro de `Get.changeTheme()` sem nenhum boilerplate para isso:\n\n```dart\nGet.changeTheme(ThemeData.light());\n```\n\nSe você quer criar algo como um botão que muda o tema com um toque, você pode combinar duas APIs do Get para isso, a API que checa se o tema dark está sendo usado, e a API de mudança de tema. E dentro de um `onPressed` você coloca isso:\n\n```dart\nGet.changeTheme(Get.isDarkMode? ThemeData.light(): ThemeData.dark());\n```\n\nQuando o modo escuro está ativado, ele vai alterar para o modo claro, e vice versa.\n\nSe você quer saber a fundo como mudar o tema, você pode seguir esse tutorial no Medium que até te ensina a persistir o tema usando Get e shared_preferences:\n\n- [Dynamic Themes in 3 lines using Get](https://medium.com/swlh/flutter-dynamic-themes-in-3-lines-c3b375f292e3) - Tutorial by [Rod Brown](https://github.com/RodBr).\n\n### Configurações Globais Opcionais\n\nVocê pode mudar configurações globais para o Get. Apenas adicione `Get.config` no seu código antes de ir para qualquer rota ou faça diretamente no seu GetMaterialApp\n\n```dart\n// essa forma\nGetMaterialApp(\n  enableLog: true,\n  defaultTransition: Transition.fade,\n  opaqueRoute: Get.isOpaqueRouteDefault,\n  popGesture: Get.isPopGestureEnable,\n  transitionDuration: Get.defaultDurationTransition,\n  defaultGlobalState: Get.defaultGlobalState,\n);\n\n// ou essa\nGet.config(\n  enableLog = true,\n  defaultPopGesture = true,\n  defaultTransition = Transitions.cupertino\n)\n```\n### Nested Navigators\n\nGet fez a navegação aninhada no Flutter mais fácil ainda. Você não precisa do `context`, e você encontrará sua `navigation stack` pela ID.\n\n* Nota: Criar navegação paralela em stacks pode ser perigoso. O idela é não usar `NestedNavigators`, ou usar com moderação. Se o seu projeto requer isso, vá em frente, mas fique ciente que manter múltiplas stacks de navegação na memória pode não ser uma boa ideia no quesito consumo de RAM.\n\nVeja como é simples:\n```dart\nNavigator(\n  key: nestedKey(1), // crie uma key com um index\n  initialRoute: '/',\n  onGenerateRoute: (settings) {\n    if (settings.name == '/') {\n      return GetPageRoute(\n        page: () => Scaffold(\n          appBar: AppBar(\n            title: Text(\"Principal\"),\n          ),\n          body: Center(\n            child: TextButton(\n              color: Colors.blue,\n              child: Text(\"Ir para a segunda\"),\n              onPressed: () {\n                Get.toNamed('/segunda', id:1); // navega pela sua navegação aninhada usando o index\n              },\n            )\n          ),\n        ),\n      );\n    } else if (settings.name == '/segunda') {\n      return GetPageRoute(\n        page: () => Center(\n          child: Scaffold(\n            appBar: AppBar(\n              title: Text(\"Principal\"),\n            ),\n            body: Center(\n              child:  Text(\"Segunda\")\n            ),\n          ),\n        ),\n      );\n    }\n  }\n),\n```\n"
  },
  {
    "path": "documentation/pt_BR/state_management.md",
    "content": "- [Simple State Manager](#simple-state-manager)\n  - [Uso do gerenciador de estado simples](#uso-do-gerenciador-de-estado-simples)\n    - [Sem StatefulWidget](#sem-statefulwidget)\n      - [Formas de uso](#formas-de-uso)\n- [Reactive State Manager](#reactive-state-manager)\n  - [GetX vs GetBuilder vs Obx vs MixinBuilder](#getx-vs-getbuilder-vs-obx-vs-mixinbuilder)\n- [Workers](#workers)\n\n## Simple State Manager\n\nHá atualmente vários gerenciadores de estados para o Flutter. Porém, a maioria deles envolve usar `ChangeNotifier` para atualizar os widgets e isso é uma abordagem muito ruim no quesito performance em aplicações de médio ou grande porte. Você pode checar na documentação oficial do Flutter que o [`ChangeNotifier` deveria ser usado com um ou no máximo dois listeners](https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html), fazendo-o praticamente inutilizável em qualquer aplicação média ou grande. \n\nOutros gerenciadores de estado são bons, mas tem suas nuances.\n\n* BLoC é bem seguro e eficiente, mas é muito complexo (especialmente para iniciantes), o que impediu pessoas de desenvolverem com Flutter. \n* MobX é mais fácil que o BLoc e é reativo, quase perfeito eu diria, mas você precisa usar um code generator que, para aplicações de grande porte, reduz a produtividade (você terá que beber vários cafés até que seu código esteja pronto denovo depois de um `flutter clean`, o que não é culpa do MobX, na verdade o code generator que é muito lento!).\n* Provider usa o `InheritedWidget` para entregar o mesmo listener, como uma forma de solucionar o problema reportado acima com o ChangeNotifier, o que indica que qualquer acesso ao ChangeNotifier dele tem que ser dentro da árvore de widgets por causa do `context` necessário para acessar o Inherited.\n\nGet não é melhor ou pior que nenhum gerenciador de estado, mas você deveria analisar esses pontos tanto quanto os argumentos abaixo para escolher entre usar Get na sua forma pura, ou usando-o em conjunto com outro gerenciador de estado.\n\nDefinitivamente, Get não é o inimigo de nenhum gerenciador, porque Get é um microframework, não apenas um gerenciador, e pode ser usado tanto sozinho quanto em conjunto com eles.\n\nGet tem um gerenciador de estado que é extremamente leve e fácil que não usa ChangeNotifier, vai atender a necessidade especialmente daqueles novos no Flutter, e não vai causar problemas em aplicações de grande porte.\n\n**Que melhoras na performance o Get traz?**\n\n1. Atualiza somente o widget necessário.\n\n2. Não usa o `ChangeNotifier`, é o gerenciador de estado que utiliza menos memória (próximo de 0mb até agora).\n\n3. Esqueça StatefulWidget's! Com Get você nunca mais vai precisar deles. Com outros gerenciadores de estado, você provavelmente precisa usar um StatefulWidget para pegar a instância do seu Provider, BLoc, MobX controller, etc. Mas já parou para pensar que seu AppBar, seu Scaffold e a maioria dos widgets que estão na sua classe são stateless? Então porque salvar o estado de uma classe inteira, se você pode salvar somente o estado de um widget stateful? Get resolve isso também. Crie uma classe Stateless, faça tudo stateless. Se você precisar atualizar um único componente, envolva ele com o `GetBuilder`, e seu estado será mantido.\n\n4. Organize seu projeto de verdade! Controllers não devem ficar na sua UI, coloque seus `TextEditController`, ou qualquer controller que você usa dentro da classe Controller.\n\n5. Você precisa acionar um evento para atualizar um widget assim que ele é renderizado? GetBuilder tem a propriedade `initState()` assim como um StatefulWidget, e você pode acionar eventos a partir do seu controller, diretamente de lá. Sem mais de eventos serem colocados no initState.\n\n6. Você precisa acionar uma ação como fechar Streams, timers, etc? GetBuilder também tem a propriedade `dispose()`, onde você pode acionar eventos assim que o widget é destruído.\n\n7. Use `Stream`s somente se necessário. Você pode usar seus StreamControllers dentro do seu controller normalmente, e usar `StreamBuilder` normalmente também, mas lembre-se, um Stream consume uma memória razoável, programação reativa é linda, mas você não abuse. 30 Streams abertos simultaneamente podem ser ainda piores que o `ChangeNotifier` (e olha que o ChangeNotifier é bem ruim)\n\n8. Atualizar widgets sem gastar memória com isso. Get guarda somente a \"ID do criador\" do GetBuilder, e atualiza esse GetBuilder quando necessário. O consumo de memória do ID do GetBuilder é muito baixo mesmo para milhares de GetBuilders. Quando você cria um novo GetBuilder, na verdade você está compartilhando o estado do GetBuilder quem tem um ID do creator. Um novo estado não é criado para cada GetBuilder, o que reduz MUITO o consumo de memória RAM em aplicações grandes. Basicamente sua aplicação vai ser toda stateless, e os poucos widgets que serão Stateful (dentro do GetBuilder) vão ter um estado único, e assim atualizar um deles vai atualizar todos eles. O estado é um só.\n\n9. Get é onisciente e na maioria dos casos sabe o momento exato de tirar um controller da memória. Você não precisa se preocupar com quando descartar o controller, Get sabe o melhor momento para fazer isso.\n\nVamos analisar o seguite exemplo:\n\n`Class A => Class B (ControllerX) => Class C (ControllerX)`\n\n* Na classe A o controller não está ainda na memória, porque você ainda não o usou (Get carrega só quando precisa).\n\n* Na classe B você usou o controller, e ele entrou na memória.\n\n* Na classe C você usou o mesmo controller da classe B, então o Get vai compartilhar o estado do controller B com o controller C, e o mesmo controller ainda estará na memória.\n\n* Se você fechar a classe C e classe B, Get vai tirar o controller X da memória automaticamente e liberar recursos, porque a classe A não está usando o controller.\n\n* Se você navegar para a Classe B denovo, o controller X vai entrar na memória denovo.\n\n* Se em vez de ir para a classe C você voltar para a classe A, Get vai tirar o controller da memória do mesmo jeito.\n\n* Se a classe C não usar o controller, e você tirar a classe B da memória, nenhuma classe estaria usando o controller X, e novamente o controller seria descartado.\n\n**Nota**: A única exceção que pode atrapalhar o Get, é se\nVocê remover classe B da rota de forma inesperada, e tentasse usar o controller na classe C. Nesse caso, o ID do creator do controller que estava em B seria deletado, e o Get foi programado para remover da memória todo controller que não tem nenhum ID de creator. Se é sua intenção fazer isso, adicione a config `autoRemove: false` no GetBuilder da classe B, e use `adoptID = true;` no GetBuilder da classe C.\n\n### Uso do gerenciador de estado simples\n\n```dart\n// Crie a classe Controller e entenda ela do GetController\nclass Controller extends GetController {\n  int counter = 0;\n  void increment() {\n    counter++;\n    update(); // use update() para atualizar a variável counter na UI quando increment for chamado\n  }\n}\n// Na sua classe Stateless/Stateful, use o GetBuilder para atualizar o texto quando a função increment for chamada\nGetBuilder<Controller>(\n  init: Controller(), // INICIE O CONTROLLER SOMENTE NA PRIMEIRA VEZ\n  builder: (controller) => Text(\n    '${controller.counter}',\n  ),\n),\n// Inicialize seu controller somente uma vez. Na segunda vez que você for usar  GetBuilder para o mesmo controller, não Inicialize denovo. Seu controller será automaticamente removido da memória. Você não precisa se preocupar com isso, Get vai fazer isso automaticamente, apenas tenha certeza que você não vai inicializar o mesmo controller duas vezes.\n```\n\n**Feito!**\n\nVocê já aprendeu como gerenciar estados com o Get.\n\nNota: Você talvez queira uma maior organização, e não querer usar a propriedade `init`. Para isso, você pode criar uma classe e extendê-la da classe `Bindings`, e nela mencionar os controllers que serão criados dentro daquela rota. Controllers não serão criados naquele momento exato, muito pelo contrário, isso é apenas uma declaração, para que na primeira vez que vc use um Controller, Get vai saber onde procurar. Get vai continuar no formato \"lazyLoad\" (carrega somente quando necessário) e vai continuar descartando os Controllers quando eles não forem mais necessários. Veja pub.dev example para ver como funciona.\n\nSe você navegar por várias rotas e precisa de algum dado que estava em um outro controller previamente utilizado, você só precisa utilizar o GetBuilder novamente (sem o init):\n\n```dart\nclass OutraClasse extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      body: Center(\n        child: GetBuilder<Controller>(\n          builder: (s) => Text('${s.counter}'),\n        ),\n      ),\n    );\n  }\n}\n```\n\nSe você precisa utilizar seu controller em vários outros lugares, e fora do GetBuilder, apenas crie um getter no seu controller que você consegue ele facilmente (ou use `Get.find<Controller>()` )\n\n```dart\nclass Controller extends GetController {\n\n  /// Você não precisa disso. Eu recomendo usar isso apenas\n  /// porque a sintaxe é mais fácil.\n  /// com o método estático: Controller.to.increment();\n  /// sem o método estático: Get.find<Controller>().increment();\n  /// Não há diferença em performance, nem efeito colateral por usar esse sintaxe. Só uma não precisa da tipage, e a outra forma a IDE vai autocompletar.\n  static Controller get to => Get.find(); // adicione esta linha\n\n  int counter = 0;\n  void increment() {\n    counter++;\n    update();\n  }\n}\n```\n\nE então você pode acessar seu controller diretamente, desse jeito:\n\n```dart\nFloatingActionButton(\n  onPressed:(){\n    Controller.to.increment(),\n  } // Isso é incrivelmente simples!\n  child: Text(\"${Controller.to.counter}\"),\n),\n```\n\nQuando você pressionar o FloatingActionButton, todos os widgets que estão escutando a variável `counter` serão atualizados automaticamente.\n\n#### Sem StatefulWidget\n\nUsar StatefulWidget's significa guardar o estado de telas inteiras desnecessariamente, mesmo porque se você precisa recarregar minimamente algum widget, você vai incorporá-lo num Consumer/Observer/BlocProvider/GetBuilder/GetX/Obx, que vai ser outro StatefulWidget.\nA classe StatefulWidget é maior que a classe StatelessWidget, o que vai alocar mais memória, e isso pode não fazer uma diferença significativa com uma ou duas classes, mas com certeza fará quando você tiver 100 delas!\n\nA não ser que você precise usar um mixin, como o `TickerProviderStateMixin`, será totalmente desnecessário usar um StatefulWidget com o Get.\n\nVocê pode chamar todos os métodos de um StatefulWidget diretamente de um GetBuilder.\nSe você precisa chamar o método `initState()` ou `dispose()` por exemplo, é possível chamá-los diretamente:\n\n```dart\nGetBuilder<Controller>(\n  initState: (_) => Controller.to.fetchApi(),\n  dispose: (_) => Controller.to.closeStreams(),\n  builder: (s) => Text('${s.username}'),\n),\n```\n\nUma abordagem muito melhor que isso é usar os métodos `onInit()` e `onClose()` diretamente do seu controller.\n\n```dart\n@override\nvoid onInit() {\n  fetchApi();\n  super.onInit();\n}\n```\n\n* Nota: Se você quiser executar um método no momento que o controller é chamado pela primeira vez, você NÃO precisa usar construtores para isso, na verdade, usando um package que é focado em performance como o Get, isso chega no limite de má prática, porque se desvia da lógica de que os controllers são criados ou alocados (Se você criar uma instância desse controller, o construtor vai ser chamado imediatamente, e ele será populado antes de ser usado, ou seja, você está alocando memória e não está utilizando, o que fere os princípios desse package). Os métodos `onInit()` e `onClose()` foram criados para isso, eles serão chamados quando o controller é criado, ou usados pela primeira vez, dependendo de como você está utilizando o Get (lazyPut ou não). Se quiser, por exemplo, fazer uma chamada para sua API para popular dados, você pode esquecer do estilo antigo de usar `initState()/dispose()`, apenas comece sua chamada para a api no `onInit`, e apenas se você precisar executar algum comando como fechar stream, use o `onClose()`.\n\nO propósito desse package é precisamente te dar uma solução completa para navegação de rotas, gerenciamente de dependências e estados, usando o mínimo possível de dependências, com um alto grau de desacoplamento. Get envolve em todas as APIs de baixo e alto nível dentro de si mesmo, para ter certeza que você irá trabalhar com o mínimo possível de acoplamento.\n\nNós centralizamos tudo em um único package. Dessa forma, você pode colocar somente widgets na sua view, e o controller pode ter só lógica de negócio, sem depender de nenhum elemento da View. Isso fornece um ambiente de trabalho muito mais limpo, para que parte do seu time possa trabalhar apenas com os widgets, sem se preocupar sobre enviar dados para o controller, e outra parte se preocupe apenas com a lógica de negócio, sem depender de nenhum elemento da view.\n\nEntão, para simplificar isso:\n\nVocê não precisa chamar métodos no `initState()` e enviá-los para seu controller via parâmetros, nem precisa do construtor do controller pra isso, você possui o método `onInit()` que é chamado no momento certo para você inicializar seus services.\n\nVocê não precisa chamar o método `dispose()`, você tem o método `onClose()` que vai ser chamado no momento exato quando seu controller não for mais necessário e será removido da memória. Dessa forma, você pode deixar a view somente para os widgets, e o controller só para as regras de negócio.\n\nNão chame o método `dispose()` dentro do GetController, não vai fazer nada. Lembre-se que o controller não é um widget, você não deveria usar o dispose lá, e esse método será automaticamente e inteligentemente removido da memória pelo Get. Se você usou algum stream no controller e quer fechá-lo, apenas insira o método para fechar os stream dentro do método `onClose()`.\n\nExemplo:\n\n```dart\nclass Controller extends GetController {\n  var user = StreamController<User>();\n  var name = StreamController<String>();\n\n  /// fechar stream = método onClose(), não dispose().\n  @override\n  void onClose() {\n    user.close();\n    name.close();\n    super.onClose();\n  }\n}\n```\n\nCiclo de vida do controller:\n\n* `onInit()`: Onde ele é criado.\n* `onClose()`: Onde ele é fechado para fazer mudanças em preparação para o método delete()\n* deleted: Você não tem acesso a essa API porque ela está literalmente removendo o controller da memória. Está literalmente deletado, sem deixar rastros.\n\n##### Formas de uso\n\nVocê pode usar uma instância do Controller diretamente no `value` do GetBuilder\n\n```dart\nGetBuilder<Controller>(  \n  init: Controller(),\n  builder: (value) => Text(\n    '${value.counter}', //aqui\n  )\n),\n```\n\nVocê talvez também precise de uma instância do seu controller fora do GetBuilder, e você pode usar essas abordagens para conseguir isso:\n\nessa:\n\n```dart\nclass Controller extends GetController {\n  static Controller get to => Get.find(); // criando um getter estático\n  [...]\n}\n// Na sua view/tela\nGetBuilder<Controller>(\n  init: Controller(), // use somente uma vez por controller, não se esqueça\n  builder: (_) => Text(\n    '${Controller.to.counter}', //aqui\n  )\n),\n```\n\nou essa:\n\n```dart\nclass Controller extends GetController {\n // sem nenhum método estático\n[...]\n}\n// Numa classe stateful/stateless\nGetBuilder<Controller>(\n  init: Controller(), // use somente uma vez por controller, não se esqueça\n  builder: (_) => Text(\n    '${Get.find<Controller>().counter}', //aqui\n  )\n),\n```\n\n* Você pode usar outras abordagens \"menos regulares\". Se você está utilizando outro gerenciador de dependências, como o get_it, modular, etc., e só quer entregar a instância do controller, pode fazer isso:\n\n```dart\nController controller = Controller();\n[...]\nGetBuilder<Controller>(\n  init: controller, //aqui\n  builder: (_) => Text(\n    '${controller.counter}', // aqui\n  )\n),\n\n```\n\nEssa abordagem não é recomendada, uma vez que você vai precisar descartar os controllers manualmente, fechar seus stream manualmente, e literalmente abandonar um dos grandes benefícios desse package, que é controle de memória inteligente. Mas se você confia no seu potencial, vai em frente!\n\nSe você quiser refinar o controle de atualização de widgets do GetBuilder, você pode assinalar a ele IDs únicas\n\n```dart\nGetBuilder<Controller>(\n  id: 'text'\n  init: Controller(), // use somente uma vez por controller, não se esqueça\n  builder: (_) => Text(\n    '${Get.find<Controller>().counter}', //aqui\n  )\n),\n```\n\nE atualizá-los dessa forma:\n\n```dart\nupdate(['text']);\n```\n\nVocê também pode impor condições para o update acontecer:\n\n```dart\nupdate(['text'], counter < 10);\n```\n\nGetX faz isso automaticamente e somente reconstrói o widget que usa a exata variável que foi alterada. Se você alterar o valor da variável para o mesmo valor que ela era anteriormente e isso não sugira uma mudança de estado, GetX não vai reconstruir esse widget, economizando memória e ciclos de CPU (Ex: 3 está sendo mostrado na tela, e você muda a variável para ter o valor 3 denovo. Na maioria dos gerenciadores de estado, isso vai causar uma reconstrução do widget, mas com o GetX o widget só vai reconstruir se de fato o estado mudou).\n\nGetBuilder é focado precisamente em múltiplos controles de estados. Imagine que você adicionou 30 produtos ao carrinho, você clica pra deletar um deles, e ao mesmo tempos a lista é atualizada, o preço é atualizado e o pequeno círculo mostrando a quantidade de produtos é atualizado. Esse tipo de abordagem faz o GetBuilder excelente, porque ele agupa estados e muda todos eles de uma vez sem nenhuma \"lógica computacional\" pra isso. GetBuilder foi criado com esse tipo de situação em mente, já que pra mudanças de estados simples, você pode simplesmente usar o `setState()`, e você não vai precisar de um gerenciador de estado para isso. Porém, há situações onde você quer somente que o widget onde uma certa variável mudou seja reconstruído, e isso é o que o GetX faz com uma maestria nunca vista antes.\n\nDessa forma, se você quiser controlar individualmente, você pode assinalar ID's para isso, ou usar GetX. Isso é com você, apenas lembre-se que quando mais \"widgets individuais\" você tiver, mais a performance do GetX vai se sobressair. Mas o GetBuilder vai ser superior quando há multiplas mudanças de estado.\n\nVocê pode usar os dois em qualquer situação, mas se quiser refinar a aplicação para a melhor performance possível, eu diria isso: se as suas variáveis são alteradas em momentos diferentes, use GetX, porque não tem competição para isso quando o widget é para reconstruir somente o que é necessário. Se você não precisa de IDs únicas, porque todas as suas variáveis serão alteradas quando você fazer uma ação, use GetBuilder, porque é um atualizador de estado em blocos simples, feito com apenas algumas linhas de código, para fazer justamente o que ele promete fazer: atualizar estado em blocos. Não há forma de comparar RAM, CPU, etc de um gerenciador de estado gigante com um simples StatefulWidget (como GetBuilder) que é atualizado quando você chama `update()`. Foi feito de uma forma simples, para ter o mínimo de lógica computacional, somente para cumprir um único papel e gastar o mínimo de recursos possível.\nSe você quer um gerenciador de estados poderoso, você pode ir sem medo para o GetX. Ele não funciona com variáveis, mas sim fluxos. Tudo está em seus streams por baixo dos panos. Você pode usar `rxDart` em conjunto com ele, porque tudo é um stream, você pode ouvir o evento de cada \"variável\", porque tudo é um stream, é literalmente BLoc, só que mais fácil que MobX e sem code generators ou decorations.\n\n## Reactive State Manager\n\nSe você quer poder, Get té dá o mais avançado gerenciador de estado que você pode ter.\nGetX foi construído 100% baseado em Stream, e te dá todo o poder de fogo que o BLoc te dá, com uma sintaxe mais fácil que a do MobX.\nSem decorations, você poder tornar qualquer coisa em um `Observable` com somete um `.obs`\n\nPerformance máxima: Somando ao fato de ter um algoritmo inteligente para reconstrução mínima, Get usa comparadores para ter certeza que o estado mudou. Se você encontrar erros na sua aplicação, e enviar uma mudança de estado duplicada, Get vai ter certeza que sua aplicação não entre em colapso.\n\nO estado só muda se o valor mudar. Essa é a principal diferença entre Get, e usar o `Computed` do MobX. Quando juntar dois observables, se um deles é alterado, a escuta daquele observable vai mudar. Com Get, se você juntar duas variáveis (que na verdade é desnecessário), GetX(similar ao Observer) vai somente mudar se implicar numa mudança real de estado. Exemplo:\n\n```dart\nfinal count1 = 0.obs;\nfinal count2 = 0.obs;\nint get sum => count1.value + count2.value;\n```\n\n```dart\nGetX<Controller>(\n  builder: (_) {\n    print(\"count 1 foi reconstruído\");\n    return Text('${_.count1.value}');\n  },\n),\nGetX<Controller>(\n  builder: (_) {\n    print(\"count 2 foi reconstruído\");\n    return Text('${_.count2.value}');\n  },\n),\nGetX<Controller>(\n  builder: (_) {\n    print(\"sum foi reconstruído\");\n    return Text('${_.sum}');\n  },\n),\n```\n\nSe nós incrementarmos o número do `count1`, somente `count1` e `sum` serão reconstruídos, porque `count1` agora tem um valor de 1, e 1 + 0 = 1, alterando o valor do `sum`.\n\nSe nós mudarmos `count2`, somente `count2` e `sum` serão reconstruídos, porque o valor do 2 mudou, e o resultado da variável `sum` é agora 2.\n\nSe definirmos o valor de `count1` para 1, nenhum widget será reconstruído, porque o valor já era 1.\n\nSe definirmos o valor de `count1` para 1 denovo, e definirmos o valor de `count2` para 2, então somente o `count2`e o `sum` vão ser reconstruídos, simplesmente porque o GetX não somente altera o que for necessário, ele também evita eventos duplicados.\n\nSomando a isso, Get provê um controle de estado refinado. Você pode adicionar uma condição a um evento (como adicionar um objeto a uma lista).\n\n```dart\nlist.addIf(item < limit, item);\n```\n\nSem decorations, sem code generator, sem complicações, GetX vai mudar a forma que você controla seus estados no Flutter, e isso não é uma promessa, isso é uma certeza!\n\nSabe o app de contador do Flutter? Sua classe Controller pode ficar assim:\n\n```dart\nclass CountController extends RxController {\n  final count = 0.obs;\n}\n```\n\nE com um simples:\n\n```dart\ncontroller.count.value++\n```\n\nVocê pode atualizar a variável counter na sua UI, independente de onde esteja sendo armazenada.\n\nVocê pode transformar qualquer coisa em obs:\n\n```dart\nclass RxUsuario {\n  final nome = \"Camila\".obs;\n  final idade = 18.obs;\n}\n\nclass Usuario {\n  Usuario({String nome, int idade});\n  final rx = RxUsuario();\n\n  String get nome => rx.nome.value;\n  set nome(String value) => rx.nome.value = value;\n\n  int get idade => rx.idade.value;\n  set idade(int value) => rx.idade.value = value;\n}\n```\n\n```dart\n\nvoid main() {\n  final usuario = Usuario();\n  print(usuario.nome);\n  usuario.idade = 23;\n  usuario.rx.idade.listen((int idade) => print(idade));\n  usuario.idade = 24;\n  usuario.idade = 25;\n}\n___________\nsaída:\nCamila\n23\n24\n25\n```\n\nTrabalhar com `Lists` usando Get é algo muito agradável. Elas são completamente observáveis assim como os objetos dentro dela. Dessa forma, se você adicionar uma valor a lista, ela vai automaticamente reconstruir os widgets que a usam.\n\nVocê também não precisa usar `.value` com listas, a api dart nos permitiu remover isso. Infelizmente tipos primitivos como String e int não podem ser extendidos, fazend o uso de `.value` obrigatório, mas isso não será um problema se você usar getters e setters para esses.\n\n```dart\nfinal list = List<Usuario>().obs;\n\nListView.builder (\nitemCount: list.length\n)\n```\n\nVocê não precisa trabalhar com sets se não quiser. Você pode usar as APIs `assign` e `assignAll`\n\nA api `assign` vai limpar sua lista e adicionar um único objeto que você quer.\n\nA api `assignAll`  vai limpar sua lista e vai adicionar objetos `Iterable` que você precisa.\n\nNós poderíamos remover a obrigação de usar o value em String e int com uma simples decoration e code generator, mas o propósito desse package é precisamente não precisar de nenhuma dependência externa. É para oferecer um ambiente pronto para programar, envolvendo os essenciais (gerenciamento de rotas, dependências e estados), numa forma simples, leve e performática sem precisar de packages externos. Você pode literalmente adicionar 3 letras e um ':' no seu pubspec.yaml e começar a programar. Todas as soluções incluídas por padrão, miram em facilidade, produtividade e performance.\n\nO peso total desse package é menor que o de um único gerenciador de estado, mesmo sendo uma solução completa, e isso é o que você precisa entender.\n\nSe você está incomodado com o `.value`, e gosta de code generator, MobX é uma excelente alternativa, e você pode usá-lo em conjunto com o Get. Para aqueles que querem adicionar uma única dependência no pubspec.yaml e começar a programar sem se preocupar sobre a versão de um package sendo incompatível com outra, ou se o erro de uma atualização do estado está vindo do gerenciador de estado ou da dependência, ou ainda, não quer se preocupar com a disponibilidade de controllers, prefere literalmente \"só programar\", Get é perfeito.\n\nAgora se você não tem problemas com o code generator do MobX, ou não vê problema no boilerplate do BLoc, você pode simplesmente usar o Get para rotas, e esquecer que nele existe um gerenciador de estado. Get nasceu da necessidade, minha empresa tinha um projeto com mais de 90 controllers e o code generator simplesmente levava mais de 30 minutos para completar suas tarefas depois de um `flutter clean` numa máquina razoavelmente boa, se o seu projeto tem 5, 10, 15 controllers, qualquer gerenciador de estado vai ter satisfazer.\n\nSe você tem um projeto absurdamente grande, e code generator é um problema para você, então você foi presenteado com essa solução que é o Get.\n\nObviamente, se alguém quiser contribuir para o projeto e criar um code generator, or algo similar, eu vou linkar no README como uma alternativa, minha necessidade não é a necessidade de todos os devs, mas por agora eu digo: há boas soluções que já fazem isso, como MobX.\n\nTipagem no Get usando Bindings é desnecessário. Você pode usar o widget `Obx()` em vez do GetX, e ele só recebe a função anônima que cria o widget.\n\n### GetX vs GetBuilder vs Obx vs MixinBuilder\n\nEm uma década de trabalho com programação eu fui capaz de aprender umas lições valiosas.\n\nMeu primeiro contato com programação reactiva foi tão \"Nossa, isso é incrível\" e de fato é incrível.\n\nPorém, não é ideal para todas as situações. De vez em quando tudo que você precisa é mudar o estado de duas ou três variáveis ao mesmo tempo, ou uma mudança de estado diferente, que nesses casos a programação reativa não é ruim, mas não é apropriado.\n\nProgramação reativa tem um consumo de RAM maior que pode ser compensado pelo fluxo individual, que vai se encarregar que apenas o Widget necessário é reconstruído, mas criar uma lista com 80 objetos, cada um com vários streams não é uma boa ideia. Abra o `dart inspect` e cheque quando um StreamBuilder consome, e você vai entender o que eu estou tentando dizer a você.\n\nCom isso em mente, eu criar o gerenciador de estados simples. É simples, e é exatamente o que você deve exigir dele: alterar vários estados em blocos de uma forma simples, e mais econômico possível.\n\nGetBuilder economiza muito quando se trata de RAM, e dificilmente vai existir uma forma mais econômica de lidar com isso do que ele (pelo menos eu não consigo imaginar nenhum. Se existir, me avise).\n\nEntretando, GetBuilder ainda é um gerenciador de estados \"mecânico\", você precisa chamar o `update()` assim como você faria com o `notifyListeners()` do `Provider`.\n\nHá outras situações onde a programação reativa é muito interessante, e não trabalhar com ela é a mesma coisa que reinventar a roda. Com isso em mente, GetX foi criado para prover tudo que há de mais moder e avançado num gerenciado de estado. Ele atualiza somente o que é necessário quando for necessário. Se por exemplo você tiver um erro que mande 300 alterações de estado simultaneamente, GetX vai filtrar e alterar a tela somente se o estado mudar de verdade.\n\nGetX ainda é mais econômico que qualquer outro gerenciador de estados reativo, mas consome um pouco mais de RAM do que o GetBuilder. Pensando nisso e mirando em minimizar o consumo de recursos que o Obx foi criado.\n\nAo contrário de GetX e GetBuilder, você não será capaz de inicializar o controller dentro do Obx, é só um Widget com um `StreamSubscription` que recebe eventos de mundança das childrens ou child, só isso. É mais econômico que o GetX, mas perde para o GetBuilder, que é nada mais que o esperado, já que é reativo. GetBuilder tem uma das formas mais simplística que existe, de guardar o hashcode de um Widget e seu StateSetter. Com Obs você não precisa escrever seu tipo de controller, e você pode ouvir mudanças de múltiplos controllers diferentes, mas eles precisam ser inicializados antes, tanto usando o forma demonstrada no exemplo no início desse README, ou usando a classe `Bindings`\n\nConcluindo, uma pessoa abriu um pedido para uma feature nova, como ele queria usar somente um tipo de variável reativa, e precisava inserir um Obx junto do GetBuilder para isso. Pensando nisso, `MixinBuilder` foi criado. Ele permite as duas formas de alterar estados: usando variáveis com `.obs`, ou a forma mecânica via `update()`\n\nPorém, desses 4 widgets, esse é o que consome mais recursos, já que usa os dois gerenciadores de estado combinados.\n\n* Nota: Para usar GetBuilder e MixinBuilder você precisa usar GetController. Para usar GetX ou Obx você precisa usar RxController.\n\n## Workers\n\nWorkers vai te dar suporte, ativando callbacks específicos quando um evento ocorrer.\n\n```dart\n/// Chamada toda vez que a variável for alterada\never(count1, (value) => print(\"novo valor: $value\"));\n\n/// Chamada apenas na primeira vez que a variável for alterada\nonce(count1, (value) => print(\"novo valor: $value (não vai mudar mais)\"));\n\n/// Anti DDos - Chamada toda vez que o usuário parar de digitar por 1 segundo, por exemplo.\ndebounce(count1, (value) => print(\"debouce $value\"), time: Duration(seconds: 1));\n\n/// Ignore todas as mudanças num período de 1 segundo.\ninterval(count1, (value) => print(\"interval $value\"), time: Duration(seconds: 1));\n```\n\n* **ever**\né chamado toda vez que a variável mudar de valor. É só isso.\n\n* **once**\né chamado somente na primeira vez que a variável mudar de valor.\n\n* **debounce**\nÉ muito útil em funções de pesquisa, onde você somente quer que a API seja chamada depois que o usuário terminar de digitar. Normalmente, se o usuário digitar \"Jonny\", será feita 5 requests na sua API, pelas letras 'J', 'o', 'n', 'n' e 'y'. Com o `debounce` isso não acontece, porque você tem a sua disposição uma função que só fazer a pesquisa na api quando o usuário parar de digitar. O `debounce` é bom para táticas anti-DDos, para funções de pesquisa em que cada letra digitada ativaria um request na API. Debounce vai esperar o usário parar de digitar o nome, para então fazer o request para API.\n\n* **interval**\nQuando se usa `debounce` , se o usuário fizer 1000 mudanças numa variável em 1 segundo, o `debounce` só computa a última mudança feita após a inatividade por um tempo estipulado (o padrão é 800 milisegundos). `interval` por outro lado vai ignorar todas as ações do usuário pelo período estipulado. Se o `interval` for de 1 segundo, então ele só conseguirá enviar 60 eventos por segundo. Se for 3 segundos de prazo, então o `interval` vai enviar 20 eventos por minuto (diferente do `debounce` que só enviaria o evento depois que o prazo estipulado acabar). Isso é recomendado para evitar abuso em funções que o usuário pode clicar rapidamente em algo para ter uma vantagem. Para exemplificar, imagine que o usuário pode ganhar moedas clicando num botão. Se ele clicar 300 vezes no botão em um minuto, ele vai ganhar 300 moedas. Usando o `interval`, você pode definir um prazo de 1 segundo por exemplo, e mesmo se ele clicasse 300 vezes em um minuto, ele ganharia apenas 60 moedas. Se fosse usado o `debounce`, o usuário ganharia apenas 1 moeda, porque só é executado quando o usuário para de clicar por um prazo estabelecido.\n\n- NOTA: Workers devem ser utilizados sempre na inicialização de um Controller ou Classe, dessa forma, ele deve estar sempre no onInit (recomendado), no Construtor de classe, ou no initState de um StatefulWidget (essa prática não é recomendada na maioria dos casos, mas não deve trazer efeitos colaterais)."
  },
  {
    "path": "documentation/ru_RU/dependency_management.md",
    "content": "# Управление зависимостями\n- [Управление зависимостями](#управление-зависимостями)\n  - [Методы создания экземпляров](#методы-создания-экземпляров)\n    - [Get.put()](#getput)\n    - [Get.lazyPut](#getlazyput)\n    - [Get.putAsync](#getputasync)\n    - [Get.create](#getcreate)\n  - [Применение методов/классов создания экземпляров](#применение-методовклассов-создания-экземпляров)\n  - [Различия между методами](#различия-между-методами)\n  - [Подвязки](#подвязки)\n    - [Класс Bindings](#класс-bindings)\n    - [BindingsBuilder](#bindingsbuilder)\n    - [SmartManagement](#smartmanagement)\n      - [Как поменять](#как-поменять)\n      - [SmartManagement.full](#smartmanagementfull)\n      - [SmartManagement.onlyBuilders](#smartmanagementonlybuilders)\n      - [SmartManagement.keepFactory](#smartmanagementkeepfactory)\n    - [Как подвязки работают под капотом](#как-подвязки-работают-под-капотом)\n  - [Примечания](#примечания)\n\nGet имеет простой и мощный менеджер зависимостей, позволяющий вам получить тот же класс, что и ваш Bloc или Controller, с помощью 1 строки кода, без Provider и inheritedWidget:\n\n```dart\nController controller = Get.put(Controller()); // Rather Controller controller = Controller();\n```\n\nВместо того, чтобы создавать экземпляр вашего класса в классе, который вы используете, вы создаёте его в экземпляре Get, что сделает его доступным во всем приложении.\nТаким образом Вы можете использовать свой контроллер (или Bloc)\n\n- Примечание: Если вы применяете менеджер состояний Get, обратите внимание на [Bindings](#bindings) api, упрощающего подключение вашего предсталения к контроллеру.\n- Примечаие²: Управление зависимостями Get отделено от других частей пакета, поэтому, если, например, ваше приложение уже использует другой менеджер состояний, вам не нужно его менять, вы можете использовать этот менеджер внедрения зависимостей без каких-либо проблем.\n\n## Методы создания экземпляров\nМетоды и настраиваемые параметры:\n\n### Get.put()\n\nСамый распространенный способ внедрения зависимости. Например, хорош для контроллеров ваших представлений.\n\n```dart\nGet.put<SomeClass>(SomeClass());\nGet.put<LoginController>(LoginController(), permanent: true);\nGet.put<ListItemController>(ListItemController, tag: \"some unique string\");\n```\n\nЭто все параметры, которые вы можете установить при использовании put:\n```dart\nGet.put<S>(\n  // mandatory: the class that you want to get to save, like a controller or anything\n  // note: \"S\" means that it can be a class of any type\n  S dependency\n\n  // optional: this is for when you want multiple classess that are of the same type\n  // since you normally get a class by using Get.find<Controller>(),\n  // you need to use tag to tell which instance you need\n  // must be unique string\n  String tag,\n\n  // optional: by default, get will dispose instances after they are not used anymore (example,\n  // the controller of a view that is closed), but you might need that the instance\n  // to be kept there throughout the entire app, like an instance of sharedPreferences or something\n  // so you use this\n  // defaults to false\n  bool permanent = false,\n\n  // optional: allows you after using an abstract class in a test, replace it with another one and follow the test.\n  // defaults to false\n  bool overrideAbstract = false,\n\n  // optional: allows you to create the dependency using function instead of the dependency itself.\n  // this one is not commonly used\n  InstanceBuilderCallback<S> builder,\n)\n```\n\n### Get.lazyPut\nМожно отложить загрузку зависимости, чтобы она создавалась только тогда, когда она используется. Очень полезно для вычислительных ресурсоёмких классов или если вы хотите создать экземпляры нескольких классов в одном месте (например, в классе Bindings), и вы знаете, что не собираетесь использовать этот класс в то время.\n\n```dart\n/// ApiMock will only be called when someone uses Get.find<ApiMock> for the first time\nGet.lazyPut<ApiMock>(() => ApiMock());\n\nGet.lazyPut<FirebaseAuth>(\n  () {\n    // ... some logic if needed\n    return FirebaseAuth();\n  },\n  tag: Math.random().toString(),\n  fenix: true\n)\n\nGet.lazyPut<Controller>( () => Controller() )\n```\n\nЭто все параметры, которые вы можете установить при использовании lazyPut:\n```dart\nGet.lazyPut<S>(\n  // mandatory: a method that will be executed when your class is called for the first time\n  InstanceBuilderCallback builder,\n  \n  // optional: same as Get.put(), it is used for when you want multiple different instance of a same class\n  // must be unique\n  String tag,\n\n  // optional: It is similar to \"permanent\", the difference is that the instance is discarded when\n  // is not being used, but when it's use is needed again, Get will recreate the instance\n  // just the same as \"SmartManagement.keepFactory\" in the bindings api\n  // defaults to false\n  bool fenix = false\n  \n)\n```\n\n### Get.putAsync\nЕсли вы хотите зарегистрировать асинхронный экземпляр, вы можете использовать `Get.putAsync`:\n\n```dart\nGet.putAsync<SharedPreferences>(() async {\n  final prefs = await SharedPreferences.getInstance();\n  await prefs.setInt('counter', 12345);\n  return prefs;\n});\n\nGet.putAsync<YourAsyncClass>( () async => await YourAsyncClass() )\n```\n\nЭто все параметры, которые вы можете установить при использовании putAsync:\n```dart\nGet.putAsync<S>(\n\n  // mandatory: an async method that will be executed to instantiate your class\n  AsyncInstanceBuilderCallback<S> builder,\n\n  // optional: same as Get.put(), it is used for when you want multiple different instance of a same class\n  // must be unique\n  String tag,\n\n  // optional: same as in Get.put(), used when you need to maintain that instance alive in the entire app\n  // defaults to false\n  bool permanent = false\n)\n```\n\n### Get.create\n\nЭто хитрый метод. Подробное объяснение того, что это такое, и различий между ними можно найти в разделе [Различия между методами](#различия-между-методами):\n\n```dart\nGet.Create<SomeClass>(() => SomeClass());\nGet.Create<LoginController>(() => LoginController());\n```\n\nЭто все параметры, которые вы можете установить при использовании create:\n\n```dart\nGet.create<S>(\n  // required: a function that returns a class that will be \"fabricated\" every\n  // time `Get.find()` is called\n  // Example: Get.create<YourClass>(() => YourClass())\n  FcBuilderFunc<S> builder,\n\n  // optional: just like Get.put(), but it is used when you need multiple instances\n  // of a of a same class\n  // Useful in case you have a list that each item need it's own controller\n  // needs to be a unique string. Just change from tag to name\n  String name,\n\n  // optional: just like int`Get.put()`, it is for when you need to keep the\n  // instance alive thoughout the entire app. The difference is in Get.create\n  // permanent is true by default\n  bool permanent = true\n```\n\n## Применение методов/классов создания экземпляров\n\nПредставьте, что вы прошли через множество маршрутов и вам нужны данные, которые остались в вашем контроллере. Вам понадобится менеджер состояний в сочетании с Provider или Get_it, верно? Только не с Get. Вам просто нужно попросить Get «найти» ваш контроллер, никаких дополнительных зависимостей вам не потребуется:\n\n```dart\nfinal controller = Get.find<Controller>();\n// OR\nController controller = Get.find();\n\n// Yes, it looks like Magic, Get will find your controller, and will deliver it to you.\n// You can have 1 million controllers instantiated, Get will always give you the right controller.\n```\n\nИ тогда вы сможете восстановить данные вашего контроллера, которые были там получены:\n\n```dart\nText(controller.textFromApi);\n```\n\nПоскольку возвращаемое значение является обычным классом, вы можете делать все, что захотите:\n```dart\nint count = Get.find<SharedPreferences>().getInt('counter');\nprint(count); // out: 12345\n```\n\nЧтобы удалить экземпляр Get:\n\n```dart\nGet.delete<Controller>(); //usually you don't need to do this because GetX already delete unused controllers\n```\n\n## Различия между методами\n\nСперва давайте рассмотрим параметр `fenix` метода Get.lazyPut и `permanent` других методов.\n\nФундаментальное различие между `permanent` и `fenix` заключается в том, как вы хотите хранить свои экземпляры.\n\nЗакрепляя это: по умолчанию GetX удаляет экземпляры, когда они не используются.\nЭто означает, что: если на экране 1 есть контроллер 1, а на экране 2 есть контроллер 2, и вы удаляете первый маршрут из стека (например, если вы используете `Get.off()` или `Get.offNamed()`), контроллер 1 теперь не используется, поэтому он будет стёрт.\n\nНо если вы используете `permanent: true`, тогда контроллер не будет потерян при этом переходе - что очень полезно для служб, которые вы хотите поддерживать на протяжении всего приложения.\n\n`fenix` предназначен для сервисов, о потере которых вы не беспокоитесь между сменами экрана, но когда вам нужен этот сервис, вы ожидаете, что он будет активен. По сути, он избавится от неиспользуемого контроллера/службы/класса, но когда он вам понадобится, он «воссоздает из пепла» новый экземпляр.\n\nИсходя из различий между методами:\n\n- Get.put и Get.putAsync следует одному и тому же порядку создания, с той разницей, что второй использует асинхронный метод: эти два метода создают и инициализируют экземпляр. Они вставляются непосредственно в память с использованием внутреннего метода `insert` с параметрами `permanent: false` и `isSingleton: true` (параметр isSingleton предназначен только для того, чтобы указать, следует ли использовать зависимость от `dependency` или она должна использовать зависимость от `FcBuilderFunc`). После этого вызывается `Get.find()`, который немедленно инициализирует экземпляры, находящиеся в памяти.\n\n- Get.create: Как следует из названия, он «создаст» вашу зависимость! Подобно `Get.put()`, он также вызывает внутренний метод `insert` для создания экземпляра. Но `permanent` становится true и `isSingleton` становится false (поскольку мы «создаем» нашу зависимость, она не может быть синглтоном, поэтому false). И поскольку `permanent: true`, мы по умолчанию не теряем его между экранами! Также, `Get.find()` не вызывается немедленно, он ожидает использования на экране для вызова. Он создан таким образом, чтобы использовать параметр `permanent`, `Get.create()` был создан с целью создания не общих экземпляров, но не удаляемых, как, например, кнопка в listView, где вам нужен уникальный экземпляр для этого списка - по этой причине Get.create необходимо использовать вместе с GetWidget.\n\n- Get.lazyPut: Как следует из названия, это ленивый процесс. Экземпляр создается, но он не вызывается для немедленного использования, он остается в ожидании вызова. В отличие от других методов, `insert` не вызывается здесь. Вместо этого экземпляр вставляется в другую часть памяти, часть, отвечающую за определение возможности воссоздания экземпляра, назовем это «фабрикой». Если мы хотим создать что-то, что будет использоваться позже, это не будет смешиваться с вещами, которые использовались сейчас. И здесь вступает в силу магия `fenix`: если вы решаете оставить `fenix: false`, и ваш `smartManagement` не является `keepFactory`, то, при использовании `Get.find`, экземпляр изменит место в памяти с «фабрики» на область памяти общего экземпляра. Сразу после этого по умолчанию удаляется с «фабрики». Теперь, если вы выберете `fenix: true`, экземпляр продолжит существовать в этой выделенной части, даже перейдя в общую область, для повторного вызова в будущем.\n\n## Подвязки\n\nВозможно, одной из главных особенностей этого пакета является возможность полной интеграции маршрутов, менеджера состояний и менеджера зависимостей.\nКогда маршрут удаляется из стека, все контроллеры, переменные и экземпляры связанных с ним объектов удаляются из памяти. Если вы используете потоки или таймеры, они закроются автоматически, и вам не о чем беспокоиться.\nВ версии 2.10 полностью реализован API привязок.\nТеперь вам больше не нужно использовать метод инициализации. Вам даже не нужно вводить контроллеры, если вы этого не хотите. Вы можете запустить свои контроллеры и серисы в соответствующем для этого месте.\nКласс Binding - это класс, который будет разделять внедрение зависимостей, при этом «привязывая» маршруты к диспетчеру состояний и диспетчеру зависимостей.\nЭтот класс позволяет Get узнать, какой экран отображается при использовании конкретного контроллера, а также узнать, где и как его удалить.\nКроме того, класс Binding позволит вам контролировать конфигурацию SmartManager. Вы можете настроить зависимости, которые будут упорядочены при удалении маршрута из стека, или когда виджет, который его использовал, выкладывается, или ни то, ни другое. На вас будет работать интеллектуальное управление зависимостями, но даже в этом случае вы можете настроить его по своему усмотрению.\n\n### Класс Bindings\n\n- Создайте класс и реализуйте Binding\n\n```dart\nclass HomeBinding implements Bindings {}\n```\n\nВаша IDE автоматически попросит вас переопределить метод «зависимостей», и вам просто нужно последовать этой просьбе, переопределить метод и вставить все классы, которые вы собираетесь использовать на этом маршруте:\n\n```dart\nclass HomeBinding implements Bindings {\n  @override\n  void dependencies() {\n    Get.lazyPut<HomeController>(() => HomeController());\n    Get.put<Service>(()=> Api());\n  }\n}\n\nclass DetailsBinding implements Bindings {\n  @override\n  void dependencies() {\n    Get.lazyPut<DetailsController>(() => DetailsController());\n  }\n}\n```\n\nТеперь вам просто нужно сообщить своему маршруту, что вы будете использовать эту привязку для установления связи между диспетчером маршрутов, зависимостями и состояниями.\n\n- Используя именованные маршруты:\n\n```dart\ngetPages: [\n  GetPage(\n    name: '/',\n    page: () => HomeView(),\n    binding: HomeBinding(),\n  ),\n  GetPage(\n    name: '/details',\n    page: () => DetailsView(),\n    binding: DetailsBinding(),\n  ),\n];\n```\n\n- Используя обычные маршруты:\n\n```dart\nGet.to(Home(), binding: HomeBinding());\nGet.to(DetailsView(), binding: DetailsBinding())\n```\n\nВам больше не нужно беспокоиться об управлении памятью вашего приложения, Get сделает это за вас.\n\nКласс Binding вызывается при вызове маршрута, вы можете создать \"initialBinding\" в GetMaterialApp, чтобы вставить все зависимости, которые будут созданы.\n\n```dart\nGetMaterialApp(\n  initialBinding: SampleBind(),\n  home: Home(),\n);\n```\n\n### BindingsBuilder\n\nПо умолчанию привязка создается путем создания класса, реализующего привязки.\nНо в качестве альтернативы вы можете использовать обратный вызов `BindingsBuilder`, чтобы просто использовать функцию для создания всего, что вы хотите.\n\nExample:\n\n```dart\ngetPages: [\n  GetPage(\n    name: '/',\n    page: () => HomeView(),\n    binding: BindingsBuilder(() {\n      Get.lazyPut<ControllerX>(() => ControllerX());\n      Get.put<Service>(()=> Api());\n    }),\n  ),\n  GetPage(\n    name: '/details',\n    page: () => DetailsView(),\n    binding: BindingsBuilder(() {\n      Get.lazyPut<DetailsController>(() => DetailsController());\n    }),\n  ),\n];\n```\n\nТаким образом, вы можете избежать создания одного класса привязки для каждого маршрута, что сделает это еще проще.\n\nОба способа работают идеально, и мы хотим, чтобы вы использовали то, что больше всего соответствует вашим вкусам.\n\n### SmartManagement\n\nGetX по умолчанию удаляет неиспользуемые контроллеры из памяти, даже если происходит сбой и виджет, который их использует, не удаляется должным образом.\nЭто то, что называется `полным` режимом управления зависимостями.\nНо если вы хотите поменять способ, которым GetX управляет удалением классов, у вас есть класс `SmartManagement`, в котором вы можете задавать другое поведение.\n\n#### Как поменять\n\nЕсли вы хотите поменять эту конфигурацию (что обычно не требуется), вот способ:\n\n```dart\nvoid main () {\n  runApp(\n    GetMaterialApp(\n      smartManagement: SmartManagement.onlyBuilders //here\n      home: Home(),\n    )\n  )\n}\n```\n\n#### SmartManagement.full\n\nЭто значение по умолчанию. Удаляет классы, которые не используются и не были постоянными. В большинстве случаев вы захотите оставить эту конфигурацию нетронутой. Если вы новичок в GetX, не меняйте это.\n\n#### SmartManagement.onlyBuilders\nС этой опцией будут удалены только контроллеры, запущенные в `init:` или загруженные в Binding с помощью `Get.lazyPut()`.\n\nЕсли вы используете `Get.put()` или `Get.putAsync()` или любой другой подход, SmartManagement не будет иметь разрешений на исключение этой зависимости.\n\nПри поведении по умолчанию даже виджеты, созданные с помощью Get.put, будут удалены, в отличие от SmartManagement.onlyBuilders.\n\n#### SmartManagement.keepFactory\n\nКак и SmartManagement.full, он удаляет зависимости, когда он больше не используется. Однако он сохранит свою фабрику, что означает, что он воссоздает зависимость, если вам снова понадобится этот экземпляр.\n\n### Как подвязки работают под капотом\nПривязки создают временные фабрики, которые создаются в тот момент, когда вы кликаете для перехода на другой экран, и будут уничтожены, как только произойдет анимация смены экрана.\nЭто происходит так быстро, что анализатор даже не сможет это зарегистрировать.\nКогда вы снова перейдете на этот экран, будет вызвана новая временная фабрика, поэтому это предпочтительнее, чем использование SmartManagement.keepFactory, но если вы не хотите создавать привязки или хотите сохранить все свои зависимости в одной привязке, это вам поможет.\nФабрики занимают мало памяти, они содержат не экземпляры, а функцию с «формой» того класса, который вам нужен.\nЭто имеет очень низкую стоимость памяти, но поскольку цель этой библиотеки - получить максимально возможную производительность с использованием минимальных ресурсов, Get по умолчанию удаляет даже фабрики. Используйте то, что вам удобнее.\n\n## Примечания\n\n- НЕ ИСПОЛЬЗУЙТЕ SmartManagement.keepFactory, если вы используете несколько привязок. Он был разработан для использования без привязок или с одной привязкой, связанной в initialBinding GetMaterialApp.\n\n- Использование привязок совершенно необязательно, если вы хотите, вы можете без проблем использовать `Get.put()` и `Get.find()` для классов, которые используют данный контроллер.\nОднако, если вы работаете со службами или любой другой абстракцией, я рекомендую использовать привязки для лучшей организации.\n"
  },
  {
    "path": "documentation/ru_RU/route_management.md",
    "content": "- [Управление маршрутами](#управление-маршрутами)\n  - [Как использовать](#как-использовать)\n  - [Навигация без именованных маршрутов](#навигация-без-именованных-маршрутов)\n  - [Навигация по именованным маршрутам](#навигация-по-именованным-маршрутам)\n    - [Отправить данные по именованному маршруту](#отправить-данные-по-именованному-маршруту)\n    - [Динамические url-ссылки](#динамические-url-ссылки)\n    - [Middleware](#middleware)\n  - [Навигация без контекста](#навигация-без-контекста)\n    - [SnackBars](#snackbars)\n    - [Dialogs](#dialogs)\n    - [BottomSheets](#bottomsheets)\n  - [Вложенная навигация](#вложенная-навигация)\n\n# Управление маршрутами\n\nЭто полное объяснение всего, что нужно Getx, когда речь идет об управлении маршрутами.\n\n## Как использовать\n\nДобавьте к вашему pubspec.yaml следующее:\n\n```yaml\ndependencies:\n  get:\n```\n\nЕсли вы собираетесь использовать маршруты/snackbars/dialogs/bottomSheets без контекста или использовать высокоуровневые API Get, вам нужно просто добавить «Get» перед вашим MaterialApp, превратив его в GetMaterialApp!\n\n```dart\nGetMaterialApp( // Before: MaterialApp(\n  home: MyHome(),\n)\n```\n\n## Навигация без именованных маршрутов\n\nДля навигации на новый экран:\n\n```dart\nGet.to(NextScreen());\n```\n\nЧтобы закрыть snackbars, диалог, bottomsheets, или все, что вы обычно закрывали с помощью Navigator.pop(context);\n\n```dart\nGet.back();\n```\n\nДля перехода к следующему экрану и отсутствия возможности вернуться к предыдущему экрану (для использования в SplashScreens, экранах входа и т.д.)\n\n```dart\nGet.off(NextScreen());\n```\n\nДля перехода к следующему экрану и отмены всех предыдущих маршрутов (полезно в корзинах для покупок, опросах и тестах)\n\n```dart\nGet.offAll(NextScreen());\n```\n\nЧтобы перейти к следующему маршруту и ​​получить или обновить данные, как только вы вернетесь с него:\n\n```dart\nvar data = await Get.to(Payment());\n```\n\nотправить данные на предыдущий экран:\n\n```dart\nGet.back(result: 'success');\n```\n\nИ использовать их:\n\nпример:\n\n```dart\nif(data == 'success') madeAnything();\n```\n\nНет желания учить наш синтаксис?\nПросто измените Navigator(верхний регистр) на navigator (нижний регистр), и вы получите все функции стандартной навигации без использования контекста.\nПример:\n\n```dart\n\n// Default Flutter navigator\nNavigator.of(context).push(\n  context,\n  MaterialPageRoute(\n    builder: (BuildContext context) {\n      return HomePage();\n    },\n  ),\n);\n\n// Get using Flutter syntax without needing context\nnavigator.push(\n  MaterialPageRoute(\n    builder: (_) {\n      return HomePage();\n    },\n  ),\n);\n\n// Get syntax (It is much better, but you have the right to disagree)\nGet.to(HomePage());\n\n\n```\n\n## Навигация по именованным маршрутам\n\n- Если вы предпочитаете перемещаться по именованным маршрутам, Get также поддерживает это.\n\nДля навигации на следующий экран\n\n```dart\nGet.toNamed(\"/NextScreen\");\n```\n\nДля навигации и удаления предыдущего экрана из дерева.\n\n```dart\nGet.offNamed(\"/NextScreen\");\n```\n\nДля навигации и удаления всех предыдущих экранов из дерева.\n\n```dart\nGet.offAllNamed(\"/NextScreen\");\n```\n\nДля определения маршрутов используйте GetMaterialApp:\n\n```dart\nvoid main() {\n  runApp(\n    GetMaterialApp(\n      initialRoute: '/',\n      getPages: [\n        GetPage(name: '/', page: () => MyHomePage()),\n        GetPage(name: '/second', page: () => Second()),\n        GetPage(\n          name: '/third',\n          page: () => Third(),\n          transition: Transition.zoom  \n        ),\n      ],\n    )\n  );\n}\n```\n\nДля обработки навигации по неопределенным маршрутам (ошибка 404) вы можете определить страницу unknownRoute в GetMaterialApp.\n\n```dart\nvoid main() {\n  runApp(\n    GetMaterialApp(\n      unknownRoute: GetPage(name: '/notfound', page: () => UnknownRoutePage()),\n      initialRoute: '/',\n      getPages: [\n        GetPage(name: '/', page: () => MyHomePage()),\n        GetPage(name: '/second', page: () => Second()),\n      ],\n    )\n  );\n}\n```\n\n### Отправить данные по именованному маршруту\n\nПросто отправьте то, что хотите в качестве аргументов. Get принимает здесь всё, что угодно, будь то String, Map, List или даже экземпляр класса.\n\n```dart\nGet.toNamed(\"/NextScreen\", arguments: 'Get is the best');\n```\n\nв вашем классе или контроллере:\n\n```dart\nprint(Get.arguments);\n//print out: Get is the best\n```\n\n### Динамические url-ссылки\n\nПолучите расширенные динамические url-адреса, как в Интернете. Веб-разработчики, вероятно, уже хотели эту функцию на Flutter, и, скорее всего, видели, что пакет обещает эту функцию и предоставляет совершенно другой синтаксис, чем url-адрес в Интернете, но Get также решает эту проблему.\n\n```dart\nGet.offAllNamed(\"/NextScreen?device=phone&id=354&name=Enzo\");\n```\n\nв вашем controller/bloc/stateful/stateless классе:\n\n```dart\nprint(Get.parameters['id']);\n// out: 354\nprint(Get.parameters['name']);\n// out: Enzo\n```\n\nВы также можете легко получить именованные параметры с помощью Get:\n\n```dart\nvoid main() {\n  runApp(\n    GetMaterialApp(\n      initialRoute: '/',\n      getPages: [\n      GetPage(\n        name: '/',\n        page: () => MyHomePage(),\n      ),\n      GetPage(\n        name: '/profile/',\n        page: () => MyProfile(),\n      ),\n       //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.\n       GetPage(\n        name: '/profile/:user',\n        page: () => UserProfile(),\n      ),\n      GetPage(\n        name: '/third',\n        page: () => Third(),\n        transition: Transition.cupertino  \n      ),\n     ],\n    )\n  );\n}\n```\n\nОтправьте данные по именованному маршруту\n\n```dart\nGet.toNamed(\"/profile/34954\");\n```\n\nНа втором экране возьмите данные по параметрам\n\n```dart\nprint(Get.parameters['user']);\n// out: 34954\n```\n\nили отправьте несколько таких параметров\n\n```dart\nGet.toNamed(\"/profile/34954?flag=true\");\n```\n\nНа втором экране взять данные по параметрам как обычно.\n\n```dart\nprint(Get.parameters['user']);\nprint(Get.parameters['flag']);\n// out: 34954 true\n```\n\n\n\nИ теперь все, что вам нужно сделать, это использовать Get.toNamed() для навигации по именованным маршрутам без какого-либо контекста (вы можете вызывать свои маршруты непосредственно из класса BLoC или контроллера), а когда ваше приложение будет скомпилировано в Интернете, ваше маршруты появятся в url <3\n\n### Middleware\n\nЕсли вы хотите прослушивать события Get для запуска действий, вы можете использовать для этого routingCallback\n\n```dart\nGetMaterialApp(\n  routingCallback: (routing) {\n    if(routing.current == '/second'){\n      openAds();\n    }\n  }\n)\n```\n\nЕсли вы не используете GetMaterialApp, вы можете использовать ручной API для подключения наблюдателя.\n\n```dart\nvoid main() {\n  runApp(\n    MaterialApp(\n      onGenerateRoute: Router.generateRoute,\n      initialRoute: \"/\",\n      navigatorKey: Get.key,\n      navigatorObservers: [\n        GetObserver(MiddleWare.observer), // HERE !!!\n      ],\n    ),\n  );\n}\n```\n\nСоздайте класс MiddleWare\n\n```dart\nclass MiddleWare {\n  static observer(Routing routing) {\n    /// You can listen in addition to the routes, the snackbars, dialogs and bottomsheets on each screen.\n    ///If you need to enter any of these 3 events directly here,\n    ///you must specify that the event is != Than you are trying to do.\n    if (routing.current == '/second' && !routing.isSnackbar) {\n      Get.snackbar(\"Hi\", \"You are on second route\");\n    } else if (routing.current =='/third'){\n      print('last route called');\n    }\n  }\n}\n```\n\nТеперь используйте Get в своем коде:\n\n```dart\nclass First extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        leading: IconButton(\n          icon: Icon(Icons.add),\n          onPressed: () {\n            Get.snackbar(\"hi\", \"i am a modern snackbar\");\n          },\n        ),\n        title: Text('First Route'),\n      ),\n      body: Center(\n        child: ElevatedButton(\n          child: Text('Open route'),\n          onPressed: () {\n            Get.toNamed(\"/second\");\n          },\n        ),\n      ),\n    );\n  }\n}\n\nclass Second extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        leading: IconButton(\n          icon: Icon(Icons.add),\n          onPressed: () {\n            Get.snackbar(\"hi\", \"i am a modern snackbar\");\n          },\n        ),\n        title: Text('second Route'),\n      ),\n      body: Center(\n        child: ElevatedButton(\n          child: Text('Open route'),\n          onPressed: () {\n            Get.toNamed(\"/third\");\n          },\n        ),\n      ),\n    );\n  }\n}\n\nclass Third extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: Text(\"Third Route\"),\n      ),\n      body: Center(\n        child: ElevatedButton(\n          onPressed: () {\n            Get.back();\n          },\n          child: Text('Go back!'),\n        ),\n      ),\n    );\n  }\n}\n```\n\n## Навигация без контекста\n\n### SnackBars\n\nЧтобы получить простой SnackBar с Flutter, вы должны получить контекст Scaffold, или вы должны использовать GlobalKey, прикрепленный к вашему Scaffold\n\n```dart\nfinal snackBar = SnackBar(\n  content: Text('Hi!'),\n  action: SnackBarAction(\n    label: 'I am a old and ugly snackbar :(',\n    onPressed: (){}\n  ),\n);\n// Find the Scaffold in the widget tree and use\n// it to show a SnackBar.\nScaffold.of(context).showSnackBar(snackBar);\n```\n\nРеализация в Get:\n\n```dart\nGet.snackbar('Hi', 'i am a modern snackbar');\n```\n\nС Get всё, что вам нужно сделать, это вызвать Get.snackbar из любого места кода или настроить его так, как вы хотите!\n\n```dart\nGet.snackbar(\n  \"Hey i'm a Get SnackBar!\", // title\n  \"It's unbelievable! I'm using SnackBar without context, without boilerplate, without Scaffold, it is something truly amazing!\", // message\n  icon: Icon(Icons.alarm),\n  shouldIconPulse: true,\n  onTap:(){},\n  barBlur: 20,\n  isDismissible: true,\n  duration: Duration(seconds: 3),\n);\n\n\n  ////////// ALL FEATURES //////////\n  //     Color colorText,\n  //     Duration duration,\n  //     SnackPosition snackPosition,\n  //     Widget titleText,\n  //     Widget messageText,\n  //     bool instantInit,\n  //     Widget icon,\n  //     bool shouldIconPulse,\n  //     double maxWidth,\n  //     EdgeInsets margin,\n  //     EdgeInsets padding,\n  //     double borderRadius,\n  //     Color borderColor,\n  //     double borderWidth,\n  //     Color backgroundColor,\n  //     Color leftBarIndicatorColor,\n  //     List<BoxShadow> boxShadows,\n  //     Gradient backgroundGradient,\n  //     TextButton mainButton,\n  //     OnTap onTap,\n  //     bool isDismissible,\n  //     bool showProgressIndicator,\n  //     AnimationController progressIndicatorController,\n  //     Color progressIndicatorBackgroundColor,\n  //     Animation<Color> progressIndicatorValueColor,\n  //     SnackStyle snackStyle,\n  //     Curve forwardAnimationCurve,\n  //     Curve reverseAnimationCurve,\n  //     Duration animationDuration,\n  //     double barBlur,\n  //     double overlayBlur,\n  //     Color overlayColor,\n  //     Form userInputForm\n  ///////////////////////////////////\n```\n\nЕсли вы предпочитаете традиционный snackbar, или хотите настроить его с нуля, вы можете использовать\n`Get.rawSnackbar();` который предоставляет RAW API, на котором был построен Get.snackbar.\n\n### Dialogs\n\nЧтобы открыть:\n\n```dart\nGet.dialog(YourDialogWidget());\n```\n\nЧтобы открыть диалог по умолчанию:\n\n```dart\nGet.defaultDialog(\n  onConfirm: () => print(\"Ok\"),\n  middleText: \"Dialog made in 3 lines of code\"\n);\n```\n\nВы также можете использовать Get.generalDialog вместо showGeneralDialog.\n\nДля всех других виджетов диалога Flutter, включая cupertino, вы можете использовать Get.overlayContext вместо контекста и открывать его в любом месте вашего кода.\nДля виджетов, которые не используют Overlay, вы можете использовать Get.context.\nЭти два контекста будут работать в 99% случаев для замены контекста вашего пользовательского интерфейса, за исключением случаев, когда наследуемый виджет используется без контекста навигации.\n\n### BottomSheets\n\nGet.bottomSheet похож на showModalBottomSheet, но не требует контекста.\n\n```dart\nGet.bottomSheet(\n  Container(\n    child: Wrap(\n      children: <Widget>[\n        ListTile(\n          leading: Icon(Icons.music_note),\n          title: Text('Music'),\n          onTap: () {}\n        ),\n        ListTile(\n          leading: Icon(Icons.videocam),\n          title: Text('Video'),\n          onTap: () {},\n        ),\n      ],\n    ),\n  )\n);\n```\n\n## Вложенная навигация\n\nGet сделал вложенную навигацию Flutter еще проще.\nВам не нужен контекст, и вы найдёте свой стек навигации по Id.\n\n- ПРИМЕЧАНИЕ: Создание параллельных стеков навигации может быть опасным. В идеале не используйте NestedNavigators или используйте их редко. Если этого требует ваш проект, продолжайте, но имейте в виду, что хранение нескольких стеков навигации в памяти может быть не лучшим решением для потребления оперативной памяти.\n\nСмотрите как это просто:\n\n```dart\nNavigator(\n  key: Get.nestedKey(1), // create a key by index\n  initialRoute: '/',\n  onGenerateRoute: (settings) {\n    if (settings.name == '/') {\n      return GetPageRoute(\n        page: () => Scaffold(\n          appBar: AppBar(\n            title: Text(\"Main\"),\n          ),\n          body: Center(\n            child: TextButton(\n              color: Colors.blue,\n              onPressed: () {\n                Get.toNamed('/second', id:1); // navigate by your nested route by index\n              },\n              child: Text(\"Go to second\"),\n            ),\n          ),\n        ),\n      );\n    } else if (settings.name == '/second') {\n      return GetPageRoute(\n        page: () => Center(\n          child: Scaffold(\n            appBar: AppBar(\n              title: Text(\"Main\"),\n            ),\n            body: Center(\n              child:  Text(\"second\")\n            ),\n          ),\n        ),\n      );\n    }\n  }\n),\n```\n"
  },
  {
    "path": "documentation/ru_RU/state_management.md",
    "content": "- [Управление состоянием](#управление-состоянием)\n  - [Реактивное управление состоянием](#реактивное-управление-состоянием)\n    - [Преимущества](#преимущества)\n    - [Объявление реактивной переменной](#объявление-реактивной-переменной)\n    - [Использование значений в представлении](#использование-значений-в-представлении)\n    - [Условия для перестраивания](#условия-для-перестраивания)\n    - [Где .obs может быть использован](#где-obs-может-быть-использован)\n    - [Примечание о списках](#примечание-о-списках)\n    - [Почему мне нужно использовать .value](#почему-мне-нужно-использовать-value)\n    - [Obx()](#obx)\n    - [Workers](#workers)\n  - [Обычное управление состоянием](#обычное-управление-состоянием)\n    - [Преимущества](#преимущества-1)\n    - [Использование](#использование)\n    - [Как обрабатываются контроллеры](#как-обрабатываются-контроллеры)\n    - [Вам больше не понадобятся StatefulWidgets](#вам-больше-не-понадобятся-statefulwidgets)\n    - [Почему это существует](#почему-это-существует)\n    - [Другие способы использования](#другие-способы-использования)\n    - [Уникальные идентификаторы](#уникальные-идентификаторы)\n  - [Смешивание двух менеджеров состояний](#смешивание-двух-менеджеров-состояний)\n  - [GetBuilder vs GetX vs Obx vs MixinBuilder](#getbuilder-vs-getx-vs-obx-vs-mixinbuilder)\n\n# Управление состоянием\n\nВ настоящее время для Flutter есть несколько менеджеров состояний. Однако большинство из них связано с использованием ChangeNotifier для обновления виджетов, и это плохой и очень плохой подход к производительности средних или больших приложений. Вы можете проверить в официальной документации Flutter, что [ChangeNotifier следует использовать с 1 или максимум 2 слушателями](https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html), что делает его практически непригодным для любого приложения среднего или большого размера.\n\nОстальные менеджеры состояний хороши, но есть свои нюансы:\n\n- BLoC безопасен и эффективен, но сложен для новичков, что удерживает людей от разработки с Flutter.\n- MobX проще, чем BLoC, реактивен, и я бы сказал, почти идеален, но вам нужно использовать генератор кода, который для больших приложений снижает производительность, таким образом вам нужно будет пить много кофе, прежде чем ваш код снова не будет готов после flutter clean (И это не вина MobX, а вина кодогенерации, которая очень медленная!).\n- Provider использует InheritedWidget для доставки слушателя в качестве способа решения проблемы, описанной выше, с помощью ChangeNotifier, что подразумевает, что любой доступ к классу ChangeNotifier должен находиться в дереве виджетов из-за контекста для доступа к Inherited.\n\nGet не лучше и не хуже, чем любой другой менеджер состояний, но вам следует проанализировать эти моменты, а также приведенные ниже пункты, чтобы выбрать между использованием Get в чистом виде (Vanilla) или его вместе с другим менеджером состояний. Определенно, Get - не враг любого другого менеджера состояний, потому что Get - это микрофреймворк, а не просто менеджер состояний, и его можно использовать отдельно или вместе с ними.\n\n## Реактивное управление состоянием\n\nРеактивное программирование может оттолкнуть многих людей, потому что считается сложным. GetX превращает реактивное программирование в нечто довольно простое:\n\n- Вам не нужно создавать StreamControllers.\n- Вам не нужно создавать StreamBuilder для каждой переменной.\n- Вам не нужно создавать класс для каждого состояния.\n- Вам не нужно создавать получение начального значения.\n\nРеактивное программирование с помощью Get так же просто, как использование setState.\n\nПредставим, что у вас есть переменная `name` и вы хотите, чтобы каждый раз, когда вы её изменяете, все виджеты, которые её используют, менялись автоматически.\n\nЭто ваша переменная:\n\n```dart\nvar name = 'Jonatas Borges';\n```\n\nЧтобы сделать его наблюдаемым, вам просто нужно добавить в конец «.obs»:\n\n```dart\nvar name = 'Jonatas Borges'.obs;\n```\n\nВот и всё. Это *так* просто.\n\nС этого момента мы могли бы называть эти - \".obs\" (ervables) переменные как _Rx_.\n\nЧто мы делали под капотом? Мы создали `Stream` из `String`ов, которому было присвоено начальное значение `\"Jonatas Borges\"`, мы уведомили все виджеты, которые используют `\"Jonatas Borges\"`, что они теперь «принадлежат» этой переменной, и когда значение _Rx_ изменится, они также должны будут измениться.\n\nЭто **волшебство GetX** возможно, благодаря возможностям Dart.\n\nНо, как мы знаем, виджет можно изменить только в том случае, если он находится внутри функции, потому что статические классы не имеют права «автоматически изменяться».\n\nВам нужно будет создать `StreamBuilder`, подписаться на эту переменную, чтобы отслеживать изменения, и создать «каскад» вложенных `StreamBuilder`, если вы хотите изменить несколько переменных в одной области, верно?\n\nНет, вам не нужен `StreamBuilder`, но насчёт статических классов вы правы.\n\nЧто ж, в представлении во Flutter, когда мы хотим изменить конкретный виджет, приходится писать много шаблоного кода.\nC **GetX** вы можете забыть о шаблонном коде. \n\n`StreamBuilder( … )`? `initialValue: …`? `builder: …`? Нет, вам просто нужно поместить эту переменную в виджет `Obx()`.\n\n```dart\nObx (() => Text (controller.name));\n```\n\n_Что нужно запомнить?_  Только `Obx(() =>`. \n\nВы просто передаёте этот виджет через стрелочную функцию в `Obx()` (\"Observer\" в _Rx_). \n\n`Obx` довольно умён и изменится только при изменении значения `controller.name`. \n\nЕсли `name` == `\"John\"`, и вы измените его на `\"John\"` (`name.value = \"John\"`), на экране ничего не изменится, так как это то же значение, что и раньше. `Obx` для экономии ресурсов просто проигнорирует новое значение, а не будет перестраивать виджет. **Разве это не потрясающе?**\n\n> Итак, что, если у меня есть 5 переменных _Rx_ (observable) в `Obx`?\n\nОн просто обновится, когда **любой** из них изменится. \n\n> И если у меня есть 30 переменных в классе, когда я обновлю одну, обновятся ли **все** переменные этого класса?\n\nНет, только **конкретный виджет**, который использует эту переменную _Rx_.\n\nИтак, **GetX** обновляет экран только тогда, когда переменная _Rx_ меняет свое значение.\n\n```\nfinal isOpen = false.obs;\n\n// NOTHING will happen... same value.\nvoid onButtonTap() => isOpen.value=false;\n```\n### Преимущества\n\n**GetX()** поможет вам, когда вам нужен **детальный** контроль над тем, что обновляется.\n\nЕсли вам не нужны уникальные идентификаторы, из-за того что все ваши переменные будут изменены при выполнении, используйте GetBuilder, потому что это простой модуль обновления состояния (как `setState()`), написанный всего в несколько строк кода.\nОн был сделан простым, чтобы иметь наименьшее влияние на CPU и просто выполнять единственную цель (восстановление состояния), тратя минимально возможные ресурсы.\n\nЕсли вам нужен **мощный** менеджер состояний, то вашим выбором будет **GetX**.\n\nОн не работает с переменными, а работает с потоками, все в нем - это `Streams` под капотом.\nВы можете использовать _rxDart_ вместе с ним, потому что все это `Streams`,\nвы можете прослушивать событие каждой «переменной _Rx_», потому что всё в нём - это `Streams`.\n\nЭто буквально подход _BLoC_, который проще, чем _MobX_, и без генераторов кода и тд.\nВы можете превратить что угодно в _\"Observable\"_ с помощью `.obs`.\n\n### Максимальная производительность:\n\nВ дополнение к интеллектуальному алгоритму минимальных перестроек, **GetX** использует компараторы, чтобы убедиться, что состояние изменилось.\n\nЕсли вы столкнетесь с ошибками в своем приложении и отправите дублирующее изменение состояния,\n**GetX** гарантирует, что оно не выйдет из строя.\n\nС **GetX** состояние изменяется только при изменении значения.\nВ этом основное отличие между **GetX** и применением _`computed` из MobX_.\nПри объединении двух __observables__, когда один из них изменяется; слушатель этого _observable_ также изменится.\n\nВ **GetX**, если вы объедините две переменные, `GetX()` (аналогично `Observer()`) будет перестраиваться только в том случае, если это подразумевает реальное изменение состояния.\n\n### Объявление реактивной переменной\n\nУ вас есть 3 способа превратить переменную в \"observable\".\n\n\n1 - Первый использует **`Rx{Type}`**.\n\n```dart\n// initial value is recommended, but not mandatory\nfinal name = RxString('');\nfinal isLogged = RxBool(false);\nfinal count = RxInt(0);\nfinal balance = RxDouble(0.0);\nfinal items = RxList<String>([]);\nfinal myMap = RxMap<String, int>({});\n```\n\n2 - Второй - использовать **`Rx`** и дженерики `Rx<Type>`\n\n```dart\nfinal name = Rx<String>('');\nfinal isLogged = Rx<Bool>(false);\nfinal count = Rx<Int>(0);\nfinal balance = Rx<Double>(0.0);\nfinal number = Rx<Num>(0)\nfinal items = Rx<List<String>>([]);\nfinal myMap = Rx<Map<String, int>>({});\n\n// Custom classes - it can be any class, literally\nfinal user = Rx<User>();\n```\n\n3 - Третий, более практичный, простой и предпочтительный подход, просто добавьте **`.obs`** в качестве свойства вашего значения:\n\n```dart\nfinal name = ''.obs;\nfinal isLogged = false.obs;\nfinal count = 0.obs;\nfinal balance = 0.0.obs;\nfinal number = 0.obs;\nfinal items = <String>[].obs;\nfinal myMap = <String, int>{}.obs;\n\n// Custom classes - it can be any class, literally\nfinal user = User().obs;\n```\n\n##### Реактивные состояния - это просто.\n\nКак мы знаем, _Dart_ сейчас движется в сторону _null safety_.\nЧтобы быть готовым, с этого момента вы всегда должны начинать свои переменные _Rx_ с **начальным значением**.\n\n> Преобразование переменной в _observable_ + _начальное значение_ c **GetX** - самый простой и практичный подход.\n\nВы буквально добавите \"`.obs`\" в конец своей переменной и **всё**, вы сделали её observable,\nи её `.value`, будет начальным значением.\n\n\n### Использование значений в представлении\n\n```dart\n// controller file\nfinal count1 = 0.obs;\nfinal count2 = 0.obs;\nint get sum => count1.value + count2.value;\n```\n\n```dart\n// view file\nGetX<Controller>(\n  builder: (controller) {\n    print(\"count 1 rebuild\");\n    return Text('${controller.count1.value}');\n  },\n),\nGetX<Controller>(\n  builder: (controller) {\n    print(\"count 2 rebuild\");\n    return Text('${controller.count2.value}');\n  },\n),\nGetX<Controller>(\n  builder: (controller) {\n    print(\"count 3 rebuild\");\n    return Text('${controller.sum}');\n  },\n),\n```\n\nЕсли мы увеличим `count1.value++`, он выведет:\n- `count 1 rebuild` \n- `count 3 rebuild`\n\nпоскольку `count1` имеет значение `1`, а `1 + 0 = 1`, изменяет геттер `sum`.\n\nЕсли мы изменим `count2.value++`, он выведет:\n- `count 2 rebuild` \n- `count 3 rebuild`\n\nтак как `count2.value` изменился, и теперь `sum` равен `2`.\n\n- Примечание: По умолчанию самое первое событие перестраивает виджет, даже если это то же значение.\n Такое поведение существует из-за Boolean переменных.\n\nПредставьте, что вы сделали это:\n\n```dart\nvar isLogged = false.obs;\n```\n\nА затем вы проверили, вошел ли пользователь в систему, чтобы вызвать событие в `ever`.\n\n```dart\n@override\nonInit(){\n  ever(isLogged, fireRoute);\n  isLogged.value = await Preferences.hasToken();\n}\n\nfireRoute(logged) {\n  if (logged) {\n   Get.off(Home());\n  } else {\n   Get.off(Login());\n  }\n}\n```\n\nЕсли `hasToken` был `false`, `isLogged` не изменится, поэтому `ever()` никогде не будет вызван.\nЧтобы избежать такого поведения, первое изменение _observable_ всегда будет запускать событие, даже если оно содержит то же самое `.value`.\n\nВы можете убран данное поведение, если хотите, используя:\n`isLogged.firstRebuild = false;`\n\n### Условия для перестраивания\n\nКроме того, Get обеспечивает усовершенствованный контроль состояния. Вы можете обусловить событие (например, добавление объекта в список) определенным условием.\n\n```dart\n// First parameter: condition, must return true of false\n// Second parameter: the new value to aplly if the condition is true\nlist.addIf(item < limit, item);\n```\n\nБез украшений, без генератора кода, без сложностей :smile:\n\nВы ведь знаете счётчик Flutter? Ваш класс контроллера может выглядеть так:\n\n```dart\nclass CountController extends GetxController {\n  final count = 0.obs;\n}\n```\n\nС простым:\n\n```dart\ncontroller.count.value++\n```\n\nВы можете обновить переменную счетчика в своем пользовательском интерфейсе, независимо от того, где она хранится.\n\n### Где .obs может быть использован\n\nВы можете преобразовать что угодно в obs. Вот два способа сделать это:\n\n* Вы можете преобразовать значения вашего класса в obs\n```dart\nclass RxUser {\n  final name = \"Camila\".obs;\n  final age = 18.obs;\n}\n```\n\n* или вы можете преобразовать весь класс в observable\n```dart\nclass User {\n  User({String name, int age});\n  var name;\n  var age;\n}\n\n// when instantianting:\nfinal user = User(name: \"Camila\", age: 18).obs;\n```\n\n### Примечание о списках\n\nСписки полностью наблюдаемы, как и объекты внутри них. Таким образом, если вы добавите значение в список, он автоматически перестроит виджеты, которые его используют.\n\nВам также не нужно использовать \".value\" со списками, замечательный API-интерфейс Dart позволяет нам избежать этого.\nК сожалению, примитивные типы, такие как String и int, не могут быть расширены, что делает использование .value обязательным, но это не будет проблемой, если вы работаете с геттерами и сеттерами для них.\n\n```dart\n// On the controller\nfinal String title = 'User Info:'.obs\nfinal list = List<User>().obs;\n\n// on the view\nText(controller.title.value), // String need to have .value in front of it\nListView.builder (\n  itemCount: controller.list.length // lists don't need it\n)\n```\n\nКогда вы делаете свои собственные классы наблюдаемыми, есть другой способ их обновить:\n\n```dart\n// on the model file\n// we are going to make the entire class observable instead of each attribute\nclass User() {\n  User({this.name = '', this.age = 0});\n  String name;\n  int age;\n}\n\n\n// on the controller file\nfinal user = User().obs;\n// when you need to update the user variable:\nuser.update( (user) { // this parameter is the class itself that you want to update\nuser.name = 'Jonny';\nuser.age = 18;\n});\n// an alternative way of update the user variable:\nuser(User(name: 'João', age: 35));\n\n// on view:\nObx(()=> Text(\"Name ${user.value.name}: Age: ${user.value.age}\"))\n// you can also access the model values without the .value:\nuser().name; // notice that is the user variable, not the class (variable has lowercase u)\n```\n\nВам не нужно работать с наборами, если вы этого не хотите, вы можете использовать API \"assign\" и \"assignAll\".\nAPI \"assign\" очистит ваш список и добавит один объект, который вы хотите начать там.\nAPI \"assignAll\" очистит существующий список и добавит любые повторяемые объекты, которые вы в него вставляете.\n\n### Почему мне нужно использовать .value\n\nМы могли бы убрать обязательство использовать 'value' для `String` и `int` с помощью простого оформления и генератора кода, но цель этой библиотеки как раз и состоит в том, чтобы избежать внешних зависимостей. Мы хотим предложить среду, готовую для программирования, включающую в себя самое необходимое (управление маршрутами, зависимостями и состояниями) простым, легким и производительным способом без необходимости во внешнем пакете.\n\nВы можете буквально добавить 3 буквы в свой pubspec (get), двоеточие и начать программировать. Все решения, включенные по умолчанию, от управления маршрутами до управления состоянием, нацелены на простоту, продуктивность и производительность.\n\nОбщий вес этой библиотеки меньше, чем у одного менеджера состояний, хотя это полное решение, и это то, что вы должны понимать.\n\nЕсли вас беспокоит `.value`, и вам нравится генератор кода, MobX - отличная альтернатива, и вы можете использовать его вместе с Get. Для тех, кто хочет добавить одну зависимость в pubspec и начать программировать, не беспокоясь ни о совместимости версий пакетов, ни об ошибках обновления состояния исходящих от менеджеров состояний или зависимостей и не хочет беспокоиться о доступности контроллеров, а «просто программирование», Get идеален.\n\nЕсли у вас нет проблем с MobX или BLoC, вы можете просто использовать Get для маршрутов и забыть о том, что у него есть менеджер состояний. Простой и реактивный менеджеры состояний Get появились из-за то, что в моей компании был проект с более чем 90 контроллерами, а генератору кода после flutter clean требовалось более 30 минут для выполнения своих задач на достаточно хорошей машине. Если у вас 5, 10, 15 контроллеров, то вам подойдёт любой менеджер состояний. Если у вас абсурдно большой проект и генератор кода является для вас проблемой, то решение прямо перед вами.\n\nОчевидно, что если кто-то хочет внести свой вклад в проект и создать генератор кода или что-то подобное, я укажу об этом в readme в качестве альтернативы. Моя потребность не в востребованности для всех разработчиков, я лишь говорю, что есть хорошие решения, которые уже делают это, например, MobX.\n\n### Obx()\n\nBindings в Get необязательны. Вы можете использовать виджет Obx вместо GetX, который получает только анонимную функцию, создающую виджет.\nОчевидно, что если вы не используете тип, вам потребуется экземпляр вашего контроллера для использования переменных или использовать `Get.find<Controller>()`.value или Controller.to.value для получения значения.\n\n### Workers\n\nWorkers помогут вам, инициируя определенные обратные вызовы при возникновении события.\n\n```dart\n/// Called every time `count1` changes.\never(count1, (_) => print(\"$_ has been changed\"));\n\n/// Called only first time the variable $_ is changed\nonce(count1, (_) => print(\"$_ was changed once\"));\n\n/// Anti DDos - Called every time the user stops typing for 1 second, for example.\ndebounce(count1, (_) => print(\"debouce$_\"), time: Duration(seconds: 1));\n\n/// Ignore all changes within 1 second.\ninterval(count1, (_) => print(\"interval $_\"), time: Duration(seconds: 1));\n```\nУ всех workers (кроме `debounce`) есть именованный параметр `condition`, которое может быть `bool` или обратным вызовом возвращающим `bool`.\nЭтот `condition` определяет, когда выполняется функция обратного вызова.\n\nВсе workers возвращают экземпляр `Worker`, который можно использовать для отмены (с помощью метода `dispose()`) worker.\n \n- **`ever`**\n вызывается каждый раз, когда переменная _Rx_ выдает новое значение.\n\n- **`everAll`**\n как `ever`, но он принимает `List` значений _Rx_ вызываемый каждый раз, когда его переменная изменяется. Вот и всё.\n\n\n- **`once`**\n'once' вызывается только при первом изменении переменной.\n\n- **`debounce`**\n'debounce' очень полезен в функциях поиска, где вы хотите, чтобы API вызывался только тогда, когда пользователь заканчивает ввод. Если пользователь вводит \"Jonny\", у вас будет 5 поисковых запросов в API по буквам J, o, n, n и y. С Get этого не происходит, потому что у вас будет \"debounce\" Worker, который будет запускаться только в конце набора.\n\n- **`interval`**\n'interval' отличается от `debouce`. В `debouce`, если пользователь внесёт 1000 изменений в переменную в течение 1 секунды, он отправит только последнее после установленного таймера (по умолчанию 800 миллисекунд). Вместо этого Interval будет игнорировать все действия пользователя в течение указанного периода. Если вы отправляете события в течение 1 минуты, 1000 в секунду, debounce отправит вам только последнее, когда пользователь прекратит стрелять событиями. Interval будет доставлять события каждую секунду, а если установлен на 3 секунды, то он будет доставлять 20 событий в эту минуту. Это рекомендуется во избежание злоупотреблений в функциях, где пользователь может быстро щелкнуть что-либо и получить некоторое преимущество (представьте, что пользователь может зарабатывать монеты, щелкая что-либо, если он щелкнет 300 раз за ту же минуту, у него будет 300 монет, используя интервал, вы можете установить временной интервал на 3 секунды, и даже если щелкнуть 300 или тысячу раз, максимум, который он получит за 1 минуту, составит 20 монет, щелкнув 300 или 1 миллион раз). Debounce подходит для защиты от DDos, для таких функций, как поиск, где каждое изменение onChange будет вызывать запрос к вашему API. Debounce будет ждать, пока пользователь перестанет вводить имя, чтобы сделать запрос. Если бы он использовался в вышеупомянутом сценарии с монетами, пользователь накликал бы только 1 монету, потому что он выполняется только тогда, когда пользователь \"делает паузу\" на установленное время.\n\n- ПРИМЕЧАНИЕ: должны всегда использоваться при запуске контроллера или класса, поэтому он всегда должен быть в onInit (рекомендуется), в конструкторе класса или в initState StatefulWidget (в большинстве случаев эта практика не рекомендуется, но не должна иметь побочных эффектов).\n\n## Обычное управление состоянием\n\nGet имеет чрезвычайно легкий и простой менеджер состояний, который не использует ChangeNotifier, удовлетворит потребности, особенно для тех, кто плохо знаком с Flutter, и не вызовет проблем для больших приложений.\n\nGetBuilder нацелен именно на контроль нескольких состояний. Представьте, что вы добавили 30 продуктов в корзину, вы нажимаете удалить один, одновременно с этим обновляется список, обновляется цена, а значок в корзине покупок обновляется до меньшего числа. Такой подход делает GetBuilder убийственным, потому что он группирует состояния и изменяет их все сразу без какой-либо \"вычислительной логики\" для этого. GetBuilder был создан с учётом такого рода ситуаций, поскольку для временного изменения состояния вы можете использовать setState, и для этого вам не понадобится менеджер состояний.\n\nТаким образом, если вам нужен отдельный контроллер, вы можете назначить для него идентификаторы или использовать GetX. Это зависит от вас, помните, что чем больше у вас «индивидуальных» виджетов, тем больше ресурсов будет забирать GetX, в то время как производительность GetBuilder должна быть выше при многократном изменении состояния.\n\n### Преимущества\n\n1. Обновляйте только необходимые виджеты.\n\n2. Не используйте changeNotifier, это менеджер состояний, который использует меньше памяти (около 0 МБ).\n\n3. Забудьте о StatefulWidget! С Get он больше не понадобится. С другими менеджерами состояний вам, вероятно, придется использовать StatefulWidget, чтобы получить экземпляр вашего Provider, BLoC, MobX Controller и т.д. Но задумывались ли вы когда-нибудь о том, что ваш AppBar, Scaffold и большинство виджетов в вашем классе не имеют состояния и по сути являются Stateless? Так зачем хранить состояние всего класса, если можно хранить только состояние виджета, которые истинно Stateful? Get решает и эту проблему. Создавайте классы Stateless, всё делайте stateless. Если вам нужно обновить один компонент, просто оберните его GetBuilder.\n\n4. Организуйте свой проект по-настоящему! Контроллеры не должны быть в вашем пользовательском интерфейсе, поместите ваш TextEditController или любой контроллер, который вы используете, в свой класс Controller.\n\n5. Вам нужно инициировать событие для обновления виджета, как только он будет отрисован? GetBuilder имеет свойство initState, как и StatefulWidget, и вы можете вызывать события вашего контроллера прямо из него.\n\n6. Вам необходимо инициировать такие действия как закрытия потоков, таймеров и т.д.? GetBuilder также имеет свойство dispose, с помощью которого вы можете вызывать события, как только этот виджет будет уничтожен.\n\n7. Используйте потоки только при необходимости. Вы можете использовать свои StreamControllers внутри своего контроллера в обычном режиме, а также использовать StreamBuilder как обычно, но помните, что поток разумно потребляет память и реактивное программирование - это прекрасно, но вы не должны злоупотреблять этим. 30 потоков, открытых одновременно, может быть хуже, чем changeNotifier (а changeNotifier - очень плохо).\n\n8. Обновляйте виджеты, не тратя на это оперативную память. Get сохраняет только идентификатор создателя GetBuilder и обновляет этот GetBuilder при необходимости. Потребление памяти для хранения идентификатора get в памяти очень низкое даже для тысяч GetBuilders. Когда вы создаете новый GetBuilder, вы фактически передаёте состояние GetBuilder, у которого есть идентификатор создателя. Новое состояние не создается для каждого GetBuilder, что экономит МНОГО ОЗУ для больших приложений. В основном ваше приложение будет полностью Stateless, и несколько виджетов, которые Stateful (при помощи GetBuilder), будут иметь общее состояние, и поэтому обновление обного обновит их всех. Состояние всего одно.\n\n9. Get - всеведущий и в большинстве случаев точно знает, в какое время нужно извлечь контроллер из памяти. Вам не следует беспокоиться о том, когда утилизировать контроллер, Get знает, когда это сделать.\n\n### Использование\n\n```dart\n// Create controller class and extends GetxController\nclass Controller extends GetxController {\n  int counter = 0;\n  void increment() {\n    counter++;\n    update(); // use update() to update counter variable on UI when increment be called\n  }\n}\n// On your Stateless/Stateful class, use GetBuilder to update Text when increment be called\nGetBuilder<Controller>(\n  init: Controller(), // INIT IT ONLY THE FIRST TIME\n  builder: (_) => Text(\n    '${_.counter}',\n  ),\n)\n//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.\n```\n\n**Готово!**\n\n- Вы уже узнали, как управлять состояниями с помощью Get.\n\n- Примечание: Возможно, вам нужна более крупная организация и не использовать свойство init. Для этого вы можете создать класс и расширить класс Bindings, указав в нем контроллеры, которые будут созданы в рамках этого маршрута. Контроллеры не будут создаваться в это время, наоборот, это просто инструкция, так что при первом использовании контроллера Get будет знать, где его искать. Get останется lazyLoad и продолжит удалять контроллеры, когда они больше не нужны. Смотрите пример в pub.dev, чтобы увидеть, как это работает.\n\nЕсли вы перемещаетесь по многим маршрутам и вам нужны данные, которые были в вашем ранее используемом контроллере, вам просто нужно использовать снова GetBuilder (без инициализации):\n\n```dart\nclass OtherClass extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      body: Center(\n        child: GetBuilder<Controller>(\n          builder: (s) => Text('${s.counter}'),\n        ),\n      ),\n    );\n  }\n\n```\n\nЕсли вам нужно использовать свой контроллер во многих других местах и ​​за пределами GetBuilder, просто создайте get в своем контроллере и легко его получите. (или используйте `Get.find<Controller>()`)\n\n```dart\nclass Controller extends GetxController {\n\n  /// You do not need that. I recommend using it just for ease of syntax.\n  /// with static method: Controller.to.increment();\n  /// with no static method: Get.find<Controller>().increment();\n  /// 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.\n  static Controller get to => Get.find(); // add this line\n\n  int counter = 0;\n  void increment() {\n    counter++;\n    update();\n  }\n}\n```\n\nИ тогда вы можете напрямую получить доступ к своему контроллеру:\n\n```dart\nFloatingActionButton(\n  onPressed: () {\n    Controller.to.increment(),\n  } // This is incredibly simple!\n  child: Text(\"${Controller.to.counter}\"),\n),\n```\n\nКогда вы нажимаете FloatingActionButton, все виджеты, которые прослушивают переменную 'counter', будут обновлены автоматически.\n\n### Как обрабатываются контроллеры\n\nДопустим, у нас есть это:\n\n`Class a => Class B (has controller X) => Class C (has controller X)`\n\nВ классе A контроллер ещё не находится в памяти, потому что вы его ещё не использовали (Get is lazyLoad). В классе B вы использовали контроллер, и он вошёл в память. В классе C вы использовали тот же контроллер, что и в классе B, Get будет разделять состояние контроллера B с контроллером C, и тот же контроллер всё ещё находится в памяти. Если вы закроете экран C и экран B, Get автоматически извлечёт контроллер X из памяти и освободит ресурсы, поскольку класс A не использует контроллер. Если вы снова перейдете к B, контроллер X снова войдет в память, если вместо перехода к классу C вы снова вернётесь к классу A, Get таким же образом выведет контроллер из памяти. Если класс C не использовал контроллер, а вы вынули класс B из памяти, ни один класс не будет использовать контроллер X, и, соответственно, он будет удален. Единственное исключение, которое может случиться с Get, - это если вы неожиданно удалите B из маршрута и попытаетесь использовать контроллер в C. В этом случае идентификатор создателя контроллера, который был в B, был удален, и Get был запрограммирован на удаление его из памяти каждого контроллера, у которого нет идентификатора создателя. Если вы намереваетесь сделать это, добавьте флаг \"autoRemove: false\" в GetBuilder класса B GetBuilder и используйте adoptID = true в GetBuilder класса C.\n\n### Вам больше не понадобятся StatefulWidgets\n\nИспользование StatefulWidgets означает ненужное сохранение состояния всех экранов, даже если вам нужно минимально перестроить виджет, вы встроите его в Consumer/Observer/BlocProvider/GetBuilder/GetX/Obx, которые будет ещё одним StatefulWidget.\nКласс StatefulWidget - это класс большего размера, чем StatelessWidget, который будет выделять больше оперативной памяти, и это может не иметь существенного значения между одним или двумя классами, но, безусловно, будет иметь место, когда у вас их 100!\nЕсли вам не нужно использовать миксин, например TickerProviderStateMixin, использовать StatefulWidget с Get совершенно не нужно.\n\nВы можете вызывать все методы StatefulWidget прямо из GetBuilder.\nНапример, если вам нужно вызвать метод initState() или dispose(), вы можете вызвать их напрямую;\n\n```dart\nGetBuilder<Controller>(\n  initState: (_) => Controller.to.fetchApi(),\n  dispose: (_) => Controller.to.closeStreams(),\n  builder: (s) => Text('${s.username}'),\n),\n```\n\nГораздо лучший подход, чем этот, - использовать методы onInit() и onClose() непосредственно из вашего контроллера.\n\n```dart\n@override\nvoid onInit() {\n  fetchApi();\n  super.onInit();\n}\n```\n\n- ПРИМЕЧАНИЕ: Если вы хотите запустить метод в момент первого вызова контроллера, вам НЕ НУЖНО использовать для этого конструкторы, на самом деле, используя ориентированный на производительность пакет, такой как Get, это граничит с плохой практикой, потому что отклоняется от логики, в которой контроллеры создаются или выделяются (если вы создаете экземпляр этого контроллера, конструктор будет вызываться немедленно, вы будете заполнять контроллер ещё до того, как он будет использован, вы выделяете память, не используя её , это определенно вредит принципам этой библиотеки).\nМетоды onInit(); и onClose(); были созданы для этого, они будут вызываться при создании Контроллера или использоваться в первый раз, в зависимости от того, используете вы Get.lazyPut или нет.\nЕсли вы хотите, например, вызвать ваш API для заполнения данных, вы можете забыть о старомодном методе initState/dispose, просто начните свой вызов api в onInit, и если вам нужно выполнить любую команду как закрытие потоков, используйте для этого onClose().\n\n### Почему это существует\n\nЦель этого пакета - предоставить вам законченное решение для навигации по маршрутам, управления зависимостями и состояниями с использованием минимально возможных зависимостей с высокой степенью разделения.\nGet включает в себя все высокоуровневые и низкоуровневые API-интерфейсы Flutter, чтобы гарантировать, что вы работаете с наименьшими взаимозависимостями.\nМы централизуем всё в одном пакете, чтобы гарантировать, что у вас нет никакой взаимозависимости в вашем проекте.\nТаким образом, вы можете поместить в свое представление только виджеты и оставить часть своей команды, которая работает с бизнес-логикой, свободной, чтобы работать с бизнес-логикой независимо от какого-либо элемента представления.\nЭто обеспечивает гораздо более чистую рабочую среду, так что часть вашей команды работает только с виджетами, не беспокоясь об отправке данных на ваш контроллер, а часть вашей команды работает только с бизнес-логикой, независимо от какого-либо элемента представления.\n\nИтак, чтобы упростить это: вам не нужно вызывать методы в initState и отправлять их по параметрам на ваш контроллер или использовать для этого конструктор вашего контроллера, у вас есть метод onInit (), который вызывается в нужное время, чтобы вы могли начать ваши сервисы.\nВам не нужно вызывать устройство, у вас есть метод onClose(), который будет вызываться именно в тот момент, когда ваш контроллер больше не нужен и будет удален из памяти. Таким образом, оставьте представления только для виджетов, воздерживаясь от какой-либо бизнес-логики.\n\nНе вызывайте метод удаления внутри GetxController, он ничего не сделает, помните, что контроллер не является виджетом, его не следует \"удалять\", и он будет автоматически и разумно удалён из памяти с помощью Get.\nЕсли вы использовали какой-либо поток и хотите закрыть его, просто вставьте его в метод close. Пример:\n\n```dart\nclass Controller extends GetxController {\n  StreamController<User> user = StreamController<User>();\n  StreamController<String> name = StreamController<String>();\n\n  /// close stream = onClose method, not dispose.\n  @override\n  void onClose() {\n    user.close();\n    name.close();\n    super.onClose();\n  }\n}\n```\n\nЖизненный цикл контроллера:\n\n- onInit() когда он создается.\n- onClose() когда он закрывается для внесения каких-либо изменений при подготовке к удалению.\n- удалено: у вас нет доступа к этому API, потому что он буквально удаляет контроллер из памяти. Он буквально удаляется, не оставляя следов.\n\n### Другие способы использования\n\nВы можете использовать экземпляр контроллера непосредственно со значением GetBuilder:\n\n```dart\nGetBuilder<Controller>(\n  init: Controller(),\n  builder: (value) => Text(\n    '${value.counter}', //here\n  ),\n),\n```\n\nВам также может понадобиться экземпляр вашего контроллера вне GetBuilder, и вы можете использовать эти подходы для достижения этой цели:\n\n```dart\nclass Controller extends GetxController {\n  static Controller get to => Get.find();\n[...]\n}\n// on you view:\nGetBuilder<Controller>(  \n  init: Controller(), // use it only first time on each controller\n  builder: (_) => Text(\n    '${Controller.to.counter}', //here\n  )\n),\n```\n\nили\n\n```dart\nclass Controller extends GetxController {\n // static Controller get to => Get.find(); // with no static get\n[...]\n}\n// on stateful/stateless class\nGetBuilder<Controller>(  \n  init: Controller(), // use it only first time on each controller\n  builder: (_) => Text(\n    '${Get.find<Controller>().counter}', //here\n  ),\n),\n```\n\n- Для этого можно использовать \"неканоничные\" подходы. Если вы используете какой-либо другой менеджер зависимостей, например get_it, modular и т.д., и просто хотите доставить экземпляр контроллера, вы можете сделать это:\n\n```dart\nController controller = Controller();\n[...]\nGetBuilder<Controller>(\n  init: controller, //here\n  builder: (_) => Text(\n    '${controller.counter}', // here\n  ),\n),\n\n```\n\n### Уникальные идентификаторы\n\nЕсли вы хотите уточнить элемент управления обновлением виджета с помощью GetBuilder, вы можете назначить им уникальные идентификаторы:\n\n```dart\nGetBuilder<Controller>(\n  id: 'text'\n  init: Controller(), // use it only first time on each controller\n  builder: (_) => Text(\n    '${Get.find<Controller>().counter}', //here\n  ),\n),\n```\n\nИ обновите это следующим образом:\n\n```dart\nupdate(['text']);\n```\n\nТакже можно наложить условия на обновление:\n\n```dart\nupdate(['text'], counter < 10);\n```\n\nGetX делает это автоматически и восстанавливает только виджет, который использует точную переменную, которая была изменена, если вы измените переменную на ту же самую, что и предыдущая, и это не означает изменения состояния, GetX не будет перестраивать виджет для экономии памяти и CPU (На экране отображается 3, и вы снова меняете переменную на 3. В большинстве менеджеров состояний это вызовет новую перестройку, но с GetX виджет будет перестраиваться снова только в том случае, если на самом деле его состояние изменилось).\n\n## Смешивание двух менеджеров состояний\n\nНекоторые открыли запрос, так как они хотели использовать только один тип реактивной переменной и другой механизм, и для этого нужно было вставить Obx в GetBuilder.\nПодумав об этом, был создан MixinBuilder.\nОн позволяет как реактивные изменения путем изменения переменных \".obs\", так и механические обновления через update().\nОднако из 4 виджетов он - тот, который потребляет больше всего ресурсов, поскольку помимо подписки на получение событий изменений от своих дочерних элементов, он подписывается на метод обновления своего контроллера.\n\nРасширение GetxController важно, поскольку у них есть жизненные циклы, и они могут \"запускать\" и \"завершать\" события в своих методах onInit() и onClose().\nВы можете использовать для этого любой класс, но я настоятельно рекомендую вам использовать класс GetxController для размещения ваших переменных, независимо от того, наблюдаемы они или нет.\n\n\n## GetBuilder vs GetX vs Obx vs MixinBuilder\n\nЗа десять лет работы с программированием я смог извлечь несколько ценных уроков.\n\nМой первый контакт с реактивным программированием был таким: \"Вау, это невероятно\", и на самом деле реактивное программирование невероятно.\nОднако он подходит не для всех ситуаций. Часто всё, что вам нужно, - это изменить состояние 2 или 3 виджетов одновременно или кратковременное изменение состояния, и в этом случае реактивный подход неплох, но не подходит.\n\nРеактивное программирование требует более высокого потребления оперативной памяти, что может быть компенсировано отдельным рабочим процессом, который гарантирует, что только один виджет будет перестроен и при необходимости, но создание списка из 80 объектов, каждый с несколькими потоками, не является хорошей идеей.\nОткройте dart inspect и проверьте, сколько потребляет StreamBuilder, и вы поймёте, что я пытаюсь вам сказать.\n\nИмея это в виду, я создал простой менеджер состояний. Это просто, и это именно то, что вы должны от него требовать: обновление состояния в блоках простым и наиболее экономичным способом.\n\nGetBuilder очень экономичен в оперативной памяти, и вряд ли существует более экономичный подход, чем он (по крайней мере, я не могу представить его, если он существует, сообщите нам).\n\nОднако GetBuilder по-прежнему является механическим менеджером состояний, вам нужно вызвать update() так же, как вам нужно было бы вызвать notifyListeners() провайдера.\n\nБывают и другие ситуации, когда реактивное программирование действительно интересно, и не работать с ним - все равно, что изобретать колесо.\nИмея это в виду, GetX был создан, чтобы предоставить всё самое современное и продвинутое в менеджере состояний.\nОн обновляет только то, что необходимо, и при необходимости, если у вас есть ошибка и вы отправляете 300 изменений состояния одновременно, GetX будет фильтровать и обновлять экран только в том случае, если состояние действительно изменяется.\n\nGetX по-прежнему более экономичен, чем любой другой менеджер реактивного состояния, но он потребляет немного больше оперативной памяти, чем GetBuilder.\nДумая об этом и стремясь максимизировать потребление ресурсов, Obx был создан.\nВ отличие от GetX и GetBuilder, вы не сможете инициализировать контроллер внутри Obx, это просто виджет с StreamSubscription, который получает события изменения от ваших детей, вот и всё.\nОн более экономичен, чем GetX, но проигрывает GetBuilder, что и следовало ожидать, поскольку он является реактивным, а GetBuilder имеет самый упрощенный подход к хранению хэш-кода виджета и его StateSetter.\nС Obx вам не нужно писать свой тип контроллера, и вы можете услышать изменение от нескольких разных контроллеров, но его необходимо инициализировать перед этим, используя примерный подход в начале этого файла readme или используя класс Bindings.\n"
  },
  {
    "path": "documentation/tr_TR/dependency_management.md",
    "content": "# Dependency Management\n- [Dependency Management](#dependency-management)\n  - [Örnek Metodlar](#örnek-metodlar)\n    - [Get.put()](#getput)\n    - [Get.lazyPut](#getlazyput)\n    - [Get.putAsync](#getputasync)\n    - [Get.create](#getcreate)\n  - [Metodların/Sınıfların örneklerinin kullanılması](#metodların/sınıfların-örneklerinin-kullanılması)\n  - [Alternatif bir instance tanımlama](#alternatif-bir-instance-tanımlama)\n  - [Metodlar arasındaki farklılıklar](#metodlar-arasındaki-farklılıklar)\n  - [Bindings](#bindings)\n    - [Bindings class](#bindings-class)\n    - [BindingsBuilder](#bindingsbuilder)\n    - [SmartManagement](#smartmanagement)\n      - [Nasıl değiştirilir?](#nasıl-değiştirilir)\n      - [SmartManagement.full](#smartmanagementfull)\n      - [SmartManagement.onlyBuilder](#smartmanagementonlybuilder)\n      - [SmartManagement.keepFactory](#smartmanagementkeepfactory)\n    - [Nasıl bindings yapılır?](#nasıl-bindings-yapılır)\n  - [Notlar](#notlar)\n\nGet, yalnızca 1 satır kodla, Provider context'i olmadan, inheritedWidget olmadan Bloc veya Controller ile aynı sınıfı almanızı sağlayan basit ve güçlü bir dependency manager'a (bağımlılık yöneticisine) sahiptir:\n\n```dart\nController controller = Get.put(Controller()); // Rather Controller controller = Controller();\n```\n\nSınıfınızı kullandığınız sınıf içinde somutlaştırmak yerine, onu uygulamanız genelinde kullanılabilir hale getirecek olan Get örneğinde somutlaştırıyorsunuz.\nBöylece denetleyicinizi (veya Bloc sınıfını) normal şekilde kullanabilirsiniz.\n\n- Not: Get's State Manager kullanıyorsanız, view'e controller'ı bağlamayı kolaylaştıracak olan [Bindings](#bindings) API'sine daha fazla dikkat edin.\n- Not²: Get dependency management (bağımlılık yönetimi) paketin diğer bölümlerinden ayrılmıştır, bu nedenle örneğin uygulamanız zaten bir state manager (durum yöneticisi) kullanıyorsa (herhangi biri, önemli değil), bunu değiştirmeniz gerekmez,  dependency injection (bağımlılık enjeksiyonunu) kullanabilirsiniz.\n\n## Örnek metodlar\nMetodlar ve configurable parameters (yapılandırılabilir parametreleri) şunlardır:\n\n### Get.put()\n\nDependency (bağımlılık) eklemenin en yaygın yolu. Örneğin;\n\n```dart\nGet.put<SomeClass>(SomeClass());\nGet.put<LoginController>(LoginController(), permanent: true);\nGet.put<ListItemController>(ListItemController, tag: \"some unique string\");\n```\n\nPut kullanırken ayarlayabileceğiniz tüm seçenekler şunlardır:\n```dart\nGet.put<S>(\n  // Zorunlu: Controller veya herhangi bir şey gibi kaydetmek istediğiniz sınıf\n  // not: \"S\", herhangi bir türde bir sınıf olabileceği anlamına gelir\n  S dependency\n\n  // isteğe bağlı: bu, aynı türden birden çok sınıf içindir\n  // normalde Get.find<Controller>() kullanarak bir sınıf aldığınız için,\n  // hangi örneğe ihtiyacınız olduğunu söylemek için \"tag\" kullanmanız gerekir\n  // benzersiz dize olmalıdır\n  String tag,\n\n  // isteğe bağlı: varsayılan olarak, get artık kullanılmadıktan sonra örnekleri elden çıkarır (örneğin,\n  // gizli bir view'in controller'ı), ancak instance'a ihtiyacınız olabilir\n  // tüm uygulama boyunca orada tutulacak, Shared Preferences örneği veya başka bir şey gibi\n  // yani bunu kullanıyorsun\n  // varsayılan olarak false\n  bool permanent = false,\n\n  // isteğe bağlı: bir testte abstract(soyut) bir sınıf kullandıktan sonra, onu başka bir sınıfla değiştirmenize ve testi takip etmenize olanak tanır.\n  // varsayılan olarak false\n  bool overrideAbstract = false,\n\n  // optional: allows you to create the dependency using function instead of the dependency itself.\n  //isteğe bağlı: dependency'nin(bağımlılığın) kendisi yerine fonksiyonu kullanarak dependency(bağımlılık) oluşturmanıza olanak tanır.\n  //bu yaygın olarak kullanılmaz\n  InstanceBuilderCallback<S> builder,\n)\n```\n\n### Get.lazyPut\nBir bağımlılığı lazyLoad ile yalnızca kullanıldığında somutlaştırılacak şekilde yüklemek mümkündür. Hesaplamalı expensive sınıflar için veya birkaç sınıfı tek bir yerde başlatmak istiyorsanız (Bindings sınıfında olduğu gibi) çok kullanışlıdır ve o zaman o sınıfı kullanmayacağınızı bilirsiniz.\n\n```dart\n/// ApiMock yalnızca Get.find<ApiMock>'u ilk kez kullandığında çağrılacak\nGet.lazyPut<ApiMock>(() => ApiMock());\n\nGet.lazyPut<FirebaseAuth>(\n  () {\n    // ... gerekirse biraz mantık\n    return FirebaseAuth();\n  },\n  tag: Math.random().toString(),\n  fenix: true\n)\n\nGet.lazyPut<Controller>( () => Controller() )\n```\n\nlazyPut'u kullanırken ayarlayabileceğiniz tüm seçenekler şunlardır:\n```dart\nGet.lazyPut<S>(\n  // zorunlu: sınıfınız ilk kez çağrıldığında yürütülecek bir yöntem\n  InstanceBuilderCallback builder,\n  \n  // isteğe bağlı: Get.put() ile aynı, aynı sınıfın birden çok farklı örneğini istediğinizde kullanılır\n  // unique olmalı\n  String tag,\n\n  // isteğe bağlı: \"Kalıcı\" ile benzerdir, aradaki fark, instance şu durumlarda atılmasıdır.\n  // kullanılmıyor, ancak tekrar kullanılması gerektiğinde Get, instance yeniden oluşturacak\n  //bindings api'sindeki \"SmartManagement.keepFactory\" ile aynı\n  // varsayılan olarak false\n  bool fenix = false\n  \n)\n```\n\n### Get.putAsync\nEşzamansız bir instance kaydetmek istiyorsanız, `Get.putAsync` kullanabilirsiniz:\n\n```dart\nGet.putAsync<SharedPreferences>(() async {\n  final prefs = await SharedPreferences.getInstance();\n  await prefs.setInt('counter', 12345);\n  return prefs;\n});\n\nGet.putAsync<YourAsyncClass>( () async => await YourAsyncClass() )\n```\n\nputAsync kullanırken ayarlayabileceğiniz tüm seçenekler şunlardır:\n```dart\nGet.putAsync<S>(\n\n  // zorunlu: sınıfınızın instance'ını oluşturmak için yürütülecek bir asenkron metod\n  AsyncInstanceBuilderCallback<S> builder,\n\n  //isteğe bağlı: Get.put() ile aynı, aynı sınıfın birden çok farklı örneğini istediğinizde kullanılır\n  // unique olmalı\n  String tag,\n\n  // isteğe bağlı: Get.put() ile aynı, bu instance tüm uygulamada canlı tutmanız gerektiğinde kullanılır\n  // varsayılan olarak false\n  bool permanent = false\n)\n```\n\n### Get.create\n\nBu zor. Bunun ne olduğuna ve diğeri arasındaki farklara ilişkin ayrıntılı bir açıklama, [Differences between methods:](#differences-between-methods) bölümünde bulunabilir.\n\n```dart\nGet.Create<SomeClass>(() => SomeClass());\nGet.Create<LoginController>(() => LoginController());\n```\n\nOluştururken ayarlayabileceğiniz tüm seçenekler şunlardır:\n\n```dart\nGet.create<S>(\n  // gerekli: her seferinde \"fabrikasyon\" olacak bir sınıf döndüren bir işlev\n  // `Get.find()` çağrılır\n  // Örnek: Get.create<YourClass>(() => YourClass())\n  FcBuilderFunc<S> builder,\n\n  // isteğe bağlı: tıpkı Get.put() gibi, ancak birden çok örneğe ihtiyacınız olduğunda kullanılır\n  // aynı sınıftan bir\n  // Her öğenin kendi denetleyicisine ihtiyaç duyduğu bir listeniz varsa kullanışlıdır\n  // benzersiz bir dize olması gerekir.\n  String name,\n\n  // isteğe bağlı: tıpkı int`Get.put()` gibi,\n  // tüm uygulama boyunca canlı örnek. Fark Get.create'de\n  // kalıcı, varsayılan olarak doğrudur\n  bool permanent = true\n```\n\n## Metodların/Sınıfların örneklerinin kullanılması\n\nÇok sayıda rotada gezindiğinizi ve kontrol cihazınızda geride bırakılan bir veriye ihtiyacınız olduğunu hayal edin, Sağlayıcı veya Get_it ile birleştirilmiş bir durum yöneticisine ihtiyacınız olacak, değil mi? Get ile değil. Controller için \"find\" seçeneğini sormanız yeterlidir, herhangi bir ek bağımlılığa ihtiyacınız yoktur:\n\n```dart\nfinal controller = Get.find<Controller>();\n// veya\nController controller = Get.find();\n\n// Evet, sihir gibi görünüyor, Controller'ı(Denetleyicinizi) bulacak ve size teslim edecek.\n// Instance edilmiş 1 milyon controller'a sahip olabilirsiniz, Get size her zaman doğru controller'ı verecektir.\n```\n\nVe sonra orada elde edilen controller ile verilerinizi kurtarabileceksiniz:\n\n```dart\nText(controller.textFromApi);\n```\n\nDöndürülen değer normal bir sınıf olduğundan, istediğiniz her şeyi yapabilirsiniz:\n```dart\nint count = Get.find<SharedPreferences>().getInt('counter');\nprint(count); // out: 12345\n```\n\nGet örneğini kaldırmak için:\n\n```dart\nGet.delete<Controller>(); //genellikle bunu yapmanız gerekmez çünkü GetX kullanılmayan controller'ları(denetleyicileri) zaten siler\n```\n\n## Alternatif bir instance tanımlama\n\nŞu anda eklenen bir örnek, `replace` veya `lazyReplace` yöntemi kullanılarak benzer veya genişletilmiş bir sınıf örneğiyle değiştirilebilir. Bu daha sonra özgün sınıf kullanılarak alınabilir.\n\n```dart\nabstract class BaseClass {}\nclass ParentClass extends BaseClass {}\n\nclass ChildClass extends ParentClass {\n  bool isChild = true;\n}\n\n\nGet.put<BaseClass>(ParentClass());\n\nGet.replace<BaseClass>(ChildClass());\n\nfinal instance = Get.find<BaseClass>();\nprint(instance is ChildClass); //true\n\n\nclass OtherClass extends BaseClass {}\nGet.lazyReplace<BaseClass>(() => OtherClass());\n\nfinal instance = Get.find<BaseClass>();\nprint(instance is ChildClass); // false\nprint(instance is OtherClass); //true\n```\n\n## Metodlar arasındaki farklılıklar \n\nİlk olarak Get.lazyPut'un `fenix`i ve diğer yöntemlerin `permanent`'larından bahsedelim.\n\n`permanent` ve `fenix` arasındaki temel fark, örneklerinizi nasıl depolamak istediğinizdir.\n\nGüçlendirme: Varsayılan olarak GetX, kullanımda değilken örnekleri siler.\nBunun anlamı: Ekran 1'de controller 1 varsa ve ekran 2'de controller 2 varsa ve ilk rotayı stackten kaldırırsanız (`Get.off()` veya `Get.offNamed()` kullanıyorsanız) controller(denetleyici) 1 kaybolur kullanımı silinecektir.\n\nAncak `permanent:true` kullanmayı tercih etmek istiyorsanız, bu geçişte controller kaybolmaz - bu, tüm uygulama boyunca canlı tutmak istediğiniz hizmetler için çok yararlıdır.\n\n`fenix`ise ekran değişiklikleri arasında kaybetme endişesi duymadığınız ancak o hizmete ihtiyaç duyduğunuzda canlı olmasını beklediğiniz hizmetler içindir. Temel olarak, kullanılmayan controller/service/class elden çıkaracak, ancak ihtiyacınız olduğunda yeni bir örneği \"küllerden yeniden yaratacaktır\".\n\nMetodlar arasındaki farklarla devam edelim:\n\n- Get.put ve Get.putAsync, ikincisinin eşzamansız bir yöntem kullanması farkıyla aynı oluşturma sırasını takip eder: bu iki yöntem, örneği oluşturur ve başlatır. Bu, `permanent: false` ve `isSingleton: true` parametreleriyle `insert` dahili yöntemi kullanılarak doğrudan belleğe eklenir (bu isSingleton parametresinin tek amacı, \"bağımlılık\" bağımlılığını kullanıp kullanmayacağını söylemektir. veya `FcBuilderFunc` bağımlılığını kullanacaksa). Bundan sonra, bellekteki örnekleri hemen başlatan `Get.find()` çağrılır.\n\n\n- Get.create: Adından da anlaşılacağı gibi, dependency'i (bağımlılığı) \"create(oluşturacak)\"! `Get.put()`a benzer şekilde, örneklemeye `insert` dahili yöntemini de çağırır. Ancak `permanent` doğru oldu ve`isSingleton` yanlış oldu (bağımlılığımızı \"creating\", bunun tek bir örnek olmasının bir yolu yok, bu yüzden yanlış). Ve `permanent: true` olduğu için, varsayılan olarak ekranlar arasında kaybetmeme avantajına sahibiz! Ayrıca `Get.find()` hemen çağrılmaz, çağrılacak ekranda kullanılmayı bekler. `permanent` parametresini kullanmak için bu şekilde yaratılmıştır, o zamandan beri, fark edilmeye değer `Get.create()`, örneğin bir bu liste için benzersiz bir örnek istiyorsanız - bu nedenle Get.create GetWidget ile birlikte kullanılmalıdır.\n\n- Get.lazyPut: Adından da anlaşılacağı gibi tembel bir işlemdir. Örnek yaratılır, ancak hemen kullanılmak üzere çağrılmaz, çağrılmayı bekler. Diğer yöntemlerin aksine burada `insert` denilmez. Bunun yerine, instance hafızanın başka bir bölümüne, örneğin yeniden oluşturulup oluşturulamayacağını söylemekle sorumlu bir kısma eklenir, buna \"factory\" diyelim. Daha sonra kullanılmak üzere bir şey yaratmak istersek, şu anda kullanılanlarla karıştırılmayacak. Ve işte burada `fenix` sihirleri devreye giriyor: `fenix: false` bırakmayı seçerseniz ve `smartManagement`ınız `keepFactory` değilse, o zaman `Get.find` kullanılırken örnek bellekteki yeri değiştirecektir. \"factory\"den ortak örnek bellek alanına. Bundan hemen sonra, varsayılan olarak \"factory\"den kaldırılır. Şimdi, `fenix: true` seçeneğini seçerseniz, örnek bu özel bölümde var olmaya devam eder, hatta gelecekte tekrar çağrılmak üzere ortak alana gider.\n\n## Bindings\n\nBu paketin en büyük farklılıklarından biri, belki de route'ların, state manager'in(durum yöneticisinin) ve dependency manager(bağımlılık yöneticisinin) tam entegrasyonu olasılığıdır.\nStackten bir rota kaldırıldığında, onunla ilgili tüm controller'lar, değişkenler ve nesne örnekleri bellekten kaldırılır. Streams(Akışlar) veya timers(zamanlayıcılar) kullanıyorsanız, bunlar otomatik olarak kapatılır ve bunların hiçbiri için endişelenmenize gerek yoktur.\n2.10 sürümünde Bindings API'sini tamamen uygulayın.\nArtık init metodunu kullanmanıza gerek yok. İstemiyorsanız controller yazmanız bile gerekmez. Bunun için uygun yerde controller ve servislerinizi başlatabilirsiniz.\nBinding sınıfı, state manager(durum yöneticisine) ve dependency manager(bağımlılık yöneticisine) giden rotaları \"binding\" ederken, dependency injection(bağımlılık enjeksiyonunu) ayıracak bir sınıftır.\nBu, belirli bir controller(denetleyici) kullanıldığında hangi ekranın görüntülenmekte olduğunu ve bunun nerede ve nasıl imha edileceğini bilmenizi sağlar.\nAyrıca Binding sınıfı, SmartManager yapılandırma kontrolüne sahip olmanızı sağlar. Stackten bir rota kaldırılırken veya onu kullanan pencere öğesi düzenlendiğinde veya hiçbirini yapmadığında düzenlenecek bağımlılıkları yapılandırabilirsiniz. Sizin için çalışan intelligent dependency management(akıllı bağımlılık yönetimine) sahip olacaksınız, ancak buna rağmen istediğiniz gibi yapılandırabilirsiniz.\n\n### Bindings class\n\n- Bir sınıf oluşturun ve Binding'i uygulayın\n\n```dart\nclass HomeBinding implements Bindings {}\n```\n\nIDE'niz otomatik olarak sizden \"dependencies(bağımlılıklar)\" metodunu geçersiz kılmanızı isteyecektir ve sadece lambaya tıklamanız, metodu geçersiz kılmanız ve o rotada kullanacağınız tüm sınıfları eklemeniz yeterlidir:\n\n```dart\nclass HomeBinding implements Bindings {\n  @override\n  void dependencies() {\n    Get.lazyPut<HomeController>(() => HomeController());\n    Get.put<Service>(()=> Api());\n  }\n}\n\nclass DetailsBinding implements Bindings {\n  @override\n  void dependencies() {\n    Get.lazyPut<DetailsController>(() => DetailsController());\n  }\n}\n```\n\nŞimdi sadece rotanızı, route manager(rota yöneticisi), dependencies(bağımlılıklar) ve states(durumlar) arasında bağlantı kurmak için bu binding'i kullanacağınızı bildirmeniz gerekiyor.\n\n- Adlandırılmış yolları kullanma:\n\n```dart\ngetPages: [\n  GetPage(\n    name: '/',\n    page: () => HomeView(),\n    binding: HomeBinding(),\n  ),\n  GetPage(\n    name: '/details',\n    page: () => DetailsView(),\n    binding: DetailsBinding(),\n  ),\n];\n```\n\n- Normal yolları kullanma:\n\n```dart\nGet.to(Home(), binding: HomeBinding());\nGet.to(DetailsView(), binding: DetailsBinding())\n```\n\nOrada, artık uygulamanızın bellek yönetimi konusunda endişelenmenize gerek yok, Get bunu sizin için yapacak.\n\nBir rota çağrıldığında Binding sınıfı çağrılır, oluşturulacak tüm bağımlılıkları eklemek için GetMaterialApp'ınızda bir \"initialBinding\" oluşturabilirsiniz.\n\n```dart\nGetMaterialApp(\n  initialBinding: SampleBind(),\n  home: Home(),\n);\n```\n\n### BindingsBuilder\n\nBinding oluşturmanın varsayılan yolu, Binding'leri uygulayan bir sınıf oluşturmaktır.\nAncak alternatif olarak, istediğiniz her şeyi somutlaştırmak için bir işlevi kullanabilmeniz için `BindingsBuilder` callback kullanabilirsiniz.\n\nÖrnek:\n\n```dart\ngetPages: [\n  GetPage(\n    name: '/',\n    page: () => HomeView(),\n    binding: BindingsBuilder(() {\n      Get.lazyPut<ControllerX>(() => ControllerX());\n      Get.put<Service>(()=> Api());\n    }),\n  ),\n  GetPage(\n    name: '/details',\n    page: () => DetailsView(),\n    binding: BindingsBuilder(() {\n      Get.lazyPut<DetailsController>(() => DetailsController());\n    }),\n  ),\n];\n```\n\nBu şekilde, her rota için bir Binding sınıfı oluşturmaktan kaçınarak bunu daha da basitleştirebilirsiniz.\n\nHer iki şekilde de gayet iyi çalışıyor ve zevkinize en uygun olanı kullanmanızı istiyoruz.\n\n### SmartManagement\n\nGetX, bir hata oluşsa ve onu kullanan bir pencere öğesi düzgün şekilde atılmamış olsa bile, varsayılan olarak kullanılmayan controller(denetleyicileri) bellekten atar.\nBu, `full` dependency management(bağımlılık yönetimi) modu olarak adlandırılan şeydir.\nAncak GetX'in sınıfların imhasını kontrol etme şeklini değiştirmek istiyorsanız, farklı davranışlar ayarlayabileceğiniz `SmartManagement` sınıfınız var.\n\n#### Nasıl değiştirilir?\n\nBu yapılandırmayı (genellikle ihtiyacınız olmayan) şekilde değiştirmek istiyorsanız:\n\n```dart\nvoid main () {\n  runApp(\n    GetMaterialApp(\n      smartManagement: SmartManagement.onlyBuilder //burada\n      home: Home(),\n    )\n  )\n}\n```\n\n#### SmartManagement.full\n\nVarsayılan olanıdır. Kullanılmayan ve kalıcı olarak ayarlanmamış sınıfları dispose edin. Çoğu durumda, bu yapılandırmayı el değmeden tutmak isteyeceksiniz. Eğer Get için yeniyseniz, bunu değiştirmeyin.\n\n#### SmartManagement.onlyBuilder\nBu seçenekle, yalnızca `init:` ile başlatılan veya `Get.lazyPut()` ile bir Binding'e yüklenen controller(denetleyiciler) dispose edilecektir.\n\n`Get.put()` veya `Get.putAsync()` veya başka bir yaklaşım kullanırsanız, SmartManagement bu bağımlılığı dışlamak için izinlere sahip olmayacaktır.\n\nVarsayılan davranışla, SmartManagement.onlyBuilder'ın aksine \"Get.put\" ile örneklenen widget'lar bile kaldırılacaktır.\n\n#### SmartManagement.keepFactory\n\nSmartManagement.full gibi, artık kullanılmadığında bağımlılıklarını kaldıracaktır. Ancak, factory'leri koruyacak, yani bu örneğe tekrar ihtiyacınız olursa dependency(bağımlılığı) yeniden yaratacaktır.\n\n### Nasıl bindings yapılır?\nBindings, başka bir ekrana gitmek için tıkladığınız anda oluşturulan geçici factory'ler oluşturur ve ekran değişirken animasyon gerçekleşir gerçekleşmez yok edilir.\nBu o kadar hızlı gerçekleşir ki analyzer onu kaydedemez bile.\nBu ekrana tekrar gittiğinizde, yeni bir geçici factory çağrılır, bu nedenle SmartManagement.keepFactory kullanmak yerine bu tercih edilir, ancak Bindings oluşturmak istemiyorsanız veya tüm bağımlılıklarınızı aynı Binding üzerinde tutmak istiyorsanız, mutlaka size yardımcı olacaktır.\nFactory'ler çok az bellek kaplarlar, örnekleri tutmazlar, ancak istediğiniz sınıfın \"shape\" olan bir fonksiyona sahiptirler.\nBunun bellekte maliyeti çok düşüktür, ancak bu kitaplığın amacı, minimum kaynakları kullanarak mümkün olan maksimum performansı elde etmek olduğundan, Get factory bile varsayılan olarak kaldırır.\nHangisi sizin için daha uygunsa onu kullanın.\n\n## Notlar\n\n- Birden çok Bindings kullanıyorsanız SmartManagement.keepFactory KULLANMAYIN. Bindings olmadan veya GetMaterialApp'in initialBinding'inde bağlantılı tek bir Binding ile kullanılmak üzere tasarlanmıştır.\n\n- Bindings kullanmak tamamen isteğe bağlıdır, isterseniz belirli bir controller(denetleyiciyi) kullanan sınıflarda `Get.put()` ve `Get.find()` kullanabilirsiniz.\nAncak, Services veya başka bir abstract class ile çalışıyorsanız, daha iyi bir organizasyon için Bindings'i kullanmanızı öneririm.\n"
  },
  {
    "path": "documentation/tr_TR/route_management.md",
    "content": "- [Rota Yönetimi (Route Management)](#route-management)\n  - [Nasıl kullanılır?](#nasıl-kullanılır)\n  - [Adlandırılmış rotalar olmadan navigasyon](#adlandırılmış-rotalar-olmadan-navigasyon)\n  - [Adlandırılmış rotalarla navigasyon](#adlandırılmış-rotalarla-navigasyon)\n    - [Verileri adlandırılmış rotalara gönder](#verileri-adlandırılmış-rotalara-gönder)\n    - [Dinamik URL bağlantıları](#dinamik-url-bağlantıları)\n    - [Middleware](#middleware)\n  - [Context olmadan Navigasyon](#context-olmadan-navigasyon)\n    - [SnackBars](#snackbars)\n    - [Dialogs](#dialogs)\n    - [BottomSheets](#bottomsheets)\n  - [Nested Navigasyon](#nested-navigasyon)\n\n# Route Management\n\nKonu rota yönetimi olduğunda Getx için gereken her şeyin tam açıklaması budur.\n\n## Nasıl kullanılır?\n\nBunu pubspec.yaml dosyanıza ekleyin:\n\n```yaml\ndependencies:\n  get:\n```\n\nContext olmadan routes/snackbars/dialogs/bottomsheets kullanacaksanız veya üst düzey Get API'lerini kullanacaksanız, `MaterialApp`'ınızdan önce `Get` eklemeniz, `GetMaterialApp`'a dönüştürmeniz ve keyfini çıkarmanız yeterlidir!\n\n```dart\nGetMaterialApp( // Öncesi: MaterialApp(\n  home: MyHome(),\n)\n```\n\n## Adlandırılmış rotalar olmadan navigasyon\n\nYeni bir ekrana gitmek için:\n\n```dart\nGet.to(NextScreen());\n```\n\nSnackbar'ları, Dialog'ları, Bottomsheet'leri veya normalde kapatacağınız herhangi bir şeyi kapatmak için `Navigator.pop(context);`\n\n```dart\nGet.back();\n```\n\nBir sonraki ekrana gittikten sonra önceki ekrana geri dönme seçeneğinin olmaması için (SplashScreens, Login ekranlarında vb. kullanım için)\n\n```dart\nGet.off(NextScreen());\n```\n\nBir sonraki ekrana gittikten sonra önceki tüm rotaları iptal etmek için (Alışveriş sepetlerinde, Anketlerde ve Testlerde kullanışlıdır)\n\n```dart\nGet.offAll(NextScreen());\n```\n\nBir sonraki rotaya gitmek ve geri döner dönmez verileri almak veya güncellemek için:\n\n```dart\nvar data = await Get.to(Payment());\n```\n\ndiğer ekrandan önceki rota için bir veri gönderin:\n\n```dart\nGet.back(result: 'success');\n```\n\nVe kullanın:\n\nÖrn:\n\n```dart\nif(data == 'success') madeAnything();\n```\n\nSözdizimimizi öğrenmek istemiyor musun? Navigator'ı (büyük harf) navigator (küçük harf) olarak değiştirin ve bağlam(context) kullanmak zorunda kalmadan standart navigasyonun tüm işlevlerine sahip olacaksınız.\nÖrnek:\n\n```dart\n\n// Varsayılan Flutter Navigator\nNavigator.of(context).push(\n  context,\n  MaterialPageRoute(\n    builder: (BuildContext context) {\n      return HomePage();\n    },\n  ),\n);\n\n// Bağlama(context) ihtiyaç duymadan Flutter sözdizimini(syntax) kullanın\nnavigator.push(\n  MaterialPageRoute(\n    builder: (_) {\n      return HomePage();\n    },\n  ),\n);\n\n// Get syntax (Bu kullanım çok daha iyidir. Tabiki siz karşı çıkma hakkına sahipsiniz.)\nGet.to(HomePage());\n\n\n```\n\n### Adlandırılmış Rotalarla Navigasyon\n\n- NamedRoutes ile gezinmeyi tercih ederseniz, Get de bunu destekler.\n\nnextScreen'e gitmek için\n\n```dart\nGet.toNamed(\"/NextScreen\");\n```\n\nAğaçta ve önceki ekranda gezinmek için.\n\n```dart\nGet.offNamed(\"/NextScreen\");\n```\n\nAğaçta gezinmek ve önceki tüm ekranları kaldırmak için\n\n```dart\nGet.offAllNamed(\"/NextScreen\");\n```\n\nRotaları tanımlamak için `GetMaterialApp`'i kullanın:\n\n```dart\nvoid main() {\n  runApp(\n    GetMaterialApp(\n      initialRoute: '/',\n      getPages: [\n        GetPage(name: '/', page: () => MyHomePage()),\n        GetPage(name: '/second', page: () => Second()),\n        GetPage(\n          name: '/third',\n          page: () => Third(),\n          transition: Transition.zoom  \n        ),\n      ],\n    )\n  );\n}\n```\n\nTanımsız rotalara navigasyonu yönetmek için (404 hatası), `GetMaterialApp`'de bir `unknownRoute` sayfası tanımlayabilirsiniz.\n\n```dart\nvoid main() {\n  runApp(\n    GetMaterialApp(\n      unknownRoute: GetPage(name: '/notfound', page: () => UnknownRoutePage()),\n      initialRoute: '/',\n      getPages: [\n        GetPage(name: '/', page: () => MyHomePage()),\n        GetPage(name: '/second', page: () => Second()),\n      ],\n    )\n  );\n}\n```\n\n### Verileri adlandırılmış Rotalara gönder\n\n\nSadece argümanlar için istediğinizi gönderin. Get, burada bir String, Map, List veya hatta bir Class örneği olsun, her şeyi kabul eder.\n\n```dart\nGet.toNamed(\"/NextScreen\", arguments: 'Get is the best');\n```\n\nsınıfınızda(class) veya denetleyicinizde(controller):\n\n```dart\nprint(Get.arguments);\n//print out: Get is the best\n```\n\n### Dinamik URL bağlantıları\n\nWeb'deki gibi gelişmiş dinamik url'ler sunun. Web geliştiricileri muhtemelen bu özelliği Flutter'da istemişlerdir ve büyük olasılıkla bir paketin bu özelliği vaat ettiğini ve bir URL'nin web'de bulunacağından tamamen farklı bir sözdizimi sunduğunu görmüşlerdir, ancak Get bunu da çözmektedir.\n\n```dart\nGet.offAllNamed(\"/NextScreen?device=phone&id=354&name=Enzo\");\n```\n\ncontroller/bloc/stateful/stateless Sınıfınıza:\n\n```dart\nprint(Get.parameters['id']);\n// out: 354\nprint(Get.parameters['name']);\n// out: Enzo\n```\n\nAyrıca Get ile Adlandırılmış Parametreleri kolayca alabilirsiniz:\n\n```dart\nvoid main() {\n  runApp(\n    GetMaterialApp(\n      initialRoute: '/',\n      getPages: [\n      GetPage(\n        name: '/',\n        page: () => MyHomePage(),\n      ),\n      GetPage(\n        name: '/profile/',\n        page: () => MyProfile(),\n      ),\n       //Argümanlı rotalar için farklı bir sayfa ve argümansız başka bir sayfa tanımlayabilirsiniz, ancak bunun için yukarıdaki gibi argüman almayacak olan rotada '/' eğik çizgisini kullanmanız gerekir.\n       GetPage(\n        name: '/profile/:user',\n        page: () => UserProfile(),\n      ),\n      GetPage(\n        name: '/third',\n        page: () => Third(),\n        transition: Transition.cupertino  \n      ),\n     ],\n    )\n  );\n}\n```\n\nRota adına veri gönder\n\n```dart\nGet.toNamed(\"/profile/34954\");\n```\n\nİkinci ekranda verileri parametreye göre alın\n\n```dart\nprint(Get.parameters['user']);\n// out: 34954\n```\n\nveya bunun gibi birden çok parametre gönderin\n\n```dart\nGet.toNamed(\"/profile/34954?flag=true&country=italy\");\n```\nveya\n```dart\nvar parameters = <String, String>{\"flag\": \"true\",\"country\": \"italy\",};\nGet.toNamed(\"/profile/34954\", parameters: parameters);\n```\n\nİkinci ekranda, verileri genellikle olduğu gibi parametrelere göre alın\n\n```dart\nprint(Get.parameters['user']);\nprint(Get.parameters['flag']);\nprint(Get.parameters['country']);\n// out: 34954 true italy\n```\n\n\n\nVe şimdi tek yapmanız gereken, herhangi bir bağlam(context) olmaksızın adlandırılmış rotalarınızda gezinmek için Get.toNamed()'i kullanmaktır (rotalarınızı doğrudan BLoC veya Controller sınıfınızdan çağırabilirsiniz) ve uygulamanız web'de derlendiğinde, rotalar url'de görünecek <3\n\n### Middleware\n\nEylemleri tetiklemek için olayları almak dinlemek istiyorsanız routingCallback'i kullanabilirsiniz.\n\n```dart\nGetMaterialApp(\n  routingCallback: (routing) {\n    if(routing.current == '/second'){\n      openAds();\n    }\n  }\n)\n```\n\nGetMaterialApp kullanmıyorsanız, Middleware gözlemcisini(observer) eklemek için manuel API'yi kullanabilirsiniz.\n\n```dart\nvoid main() {\n  runApp(\n    MaterialApp(\n      onGenerateRoute: Router.generateRoute,\n      initialRoute: \"/\",\n      navigatorKey: Get.key,\n      navigatorObservers: [\n        GetObserver(MiddleWare.observer), // Burası !!!\n      ],\n    ),\n  );\n}\n```\n\nBir MiddleWare sınıfı oluşturun\n\n```dart\nclass MiddleWare {\n  static observer(Routing routing) {\n    /// Her ekranda rotalar, snackbarlar, diyaloglar ve bottomsheetleri ek olarak dinleyebilirsiniz.\n    ///Bu 3 olaydan herhangi birini doğrudan buraya girmeniz gerekiyorsa,\n    ///Yapmaya çalıştığınızdan daha fazla olayın olduğunu != kullanarak belirtmelisiniz.\n    if (routing.current == '/second' && !routing.isSnackbar) {\n      Get.snackbar(\"Hi\", \"You are on second route\");\n    } else if (routing.current =='/third'){\n      print('last route called');\n    }\n  }\n}\n```\n\nŞimdi, Get on kodunu kullanın:\n\n```dart\nclass First extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        leading: IconButton(\n          icon: Icon(Icons.add),\n          onPressed: () {\n            Get.snackbar(\"hi\", \"i am a modern snackbar\");\n          },\n        ),\n        title: Text('First Route'),\n      ),\n      body: Center(\n        child: ElevatedButton(\n          child: Text('Open route'),\n          onPressed: () {\n            Get.toNamed(\"/second\");\n          },\n        ),\n      ),\n    );\n  }\n}\n\nclass Second extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        leading: IconButton(\n          icon: Icon(Icons.add),\n          onPressed: () {\n            Get.snackbar(\"hi\", \"i am a modern snackbar\");\n          },\n        ),\n        title: Text('second Route'),\n      ),\n      body: Center(\n        child: ElevatedButton(\n          child: Text('Open route'),\n          onPressed: () {\n            Get.toNamed(\"/third\");\n          },\n        ),\n      ),\n    );\n  }\n}\n\nclass Third extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: Text(\"Third Route\"),\n      ),\n      body: Center(\n        child: ElevatedButton(\n          onPressed: () {\n            Get.back();\n          },\n          child: Text('Go back!'),\n        ),\n      ),\n    );\n  }\n}\n```\n\n## Context olmadan Navigasyon\n\n### SnackBars\n\nFlutter ile basit bir SnackBar'a sahip olmak için Scaffold bağlamını(context) almalısınız veya Scaffold'unuza bağlı bir GlobalKey kullanmalısınız.\n\n```dart\nfinal snackBar = SnackBar(\n  content: Text('Hi!'),\n  action: SnackBarAction(\n    label: 'I am a old and ugly snackbar :(',\n    onPressed: (){}\n  ),\n);\n// Widget ağacında Scaffold'u bulun ve kullanın\n// bir SnackBar göstermek için.\nScaffold.of(context).showSnackBar(snackBar);\n```\n\nGet ile:\n\n```dart\nGet.snackbar('Hi', 'i am a modern snackbar');\n```\n\nGet ile, Yapmanız gereken tek şey kodunuzun herhangi bir yerinden Get.snackbar'ınızı aramak veya onu istediğiniz gibi özelleştirmek!\n\n```dart\nGet.snackbar(\n  \"Hey i'm a Get SnackBar!\", // title\n  \"It's unbelievable! I'm using SnackBar without context, without boilerplate, without Scaffold, it is something truly amazing!\", // message\n  icon: Icon(Icons.alarm),\n  shouldIconPulse: true,\n  onTap:(){},\n  barBlur: 20,\n  isDismissible: true,\n  duration: Duration(seconds: 3),\n);\n\n\n  ////////// ALL FEATURES //////////\n  //     Color colorText,\n  //     Duration duration,\n  //     SnackPosition snackPosition,\n  //     Widget titleText,\n  //     Widget messageText,\n  //     bool instantInit,\n  //     Widget icon,\n  //     bool shouldIconPulse,\n  //     double maxWidth,\n  //     EdgeInsets margin,\n  //     EdgeInsets padding,\n  //     double borderRadius,\n  //     Color borderColor,\n  //     double borderWidth,\n  //     Color backgroundColor,\n  //     Color leftBarIndicatorColor,\n  //     List<BoxShadow> boxShadows,\n  //     Gradient backgroundGradient,\n  //     TextButton mainButton,\n  //     OnTap onTap,\n  //     bool isDismissible,\n  //     bool showProgressIndicator,\n  //     AnimationController progressIndicatorController,\n  //     Color progressIndicatorBackgroundColor,\n  //     Animation<Color> progressIndicatorValueColor,\n  //     SnackStyle snackStyle,\n  //     Curve forwardAnimationCurve,\n  //     Curve reverseAnimationCurve,\n  //     Duration animationDuration,\n  //     double barBlur,\n  //     double overlayBlur,\n  //     Color overlayColor,\n  //     Form userInputForm\n  ///////////////////////////////////\n```\n\nGeleneksel snackbar'ı tercih ediyorsanız veya yalnızca bir satır eklemek de dahil olmak üzere sıfırdan özelleştirmek istiyorsanız (Get.snackbar zorunlu bir başlık ve mesaj kullanır), \nGet.snackbar'ın üzerine inşa edildiği RAW API'sini sağlayan `Get.rawSnackbar();` kullanabilirsiniz. \n\n### Dialogs\n\nDialog'u açmak için:\n\n```dart\nGet.dialog(YourDialogWidget());\n```\n\nVarsayılan dialog açmak için:\n\n```dart\nGet.defaultDialog(\n  onConfirm: () => print(\"Ok\"),\n  middleText: \"Dialog made in 3 lines of code\"\n);\n```\n\nshowGeneralDialog yerine Get.generalDialog'u da kullanabilirsiniz.\n\nCupertinos dahil olmak üzere tüm diğer Flutter Dialog widget'ları için bağlam(context) yerine Get.overlayContext'i kullanabilir ve kodunuzun herhangi bir yerinde açabilirsiniz.\nOverlay kullanmayan widget'lar için Get.context'i kullanabilirsiniz.\nBu iki bağlam(context), inheritedWidget'ın bir gezinme bağlamı(context) olmadan kullanıldığı durumlar dışında, kullanıcı arayüzünüzün bağlamını(context) değiştirmek için vakaların %99'unda çalışacaktır.\n\n### BottomSheets\n\nGet.bottomSheet, showModalBottomSheet gibidir, ancak bağlama(context) ihtiyaç duymaz.\n\n```dart\nGet.bottomSheet(\n  Container(\n    child: Wrap(\n      children: <Widget>[\n        ListTile(\n          leading: Icon(Icons.music_note),\n          title: Text('Music'),\n          onTap: () {}\n        ),\n        ListTile(\n          leading: Icon(Icons.videocam),\n          title: Text('Video'),\n          onTap: () {},\n        ),\n      ],\n    ),\n  )\n);\n```\n\n## Nested Navigasyon\n\nFlutter'ın iç içe gezinmesini daha da kolaylaştırın.\nİçeriğe ihtiyacınız yoktur ve navigasyon yığınınızı kimliğe(ID) göre bulacaksınız.\n\n- NOT: Paralel gezinme yığınları oluşturmak tehlikeli olabilir. İdeal olan, NestedNavigators'ı kullanmamak veya idareli kullanmaktır. Projeniz gerektiriyorsa, devam edin, ancak bellekte birden çok gezinme yığınını tutmanın RAM tüketimi için iyi bir fikir olmayabileceğini unutmayın.\n\nBakın ne kadar basit:\n\n```dart\nNavigator(\n  key: Get.nestedKey(1), // index göre anahtar oluşturma\n  initialRoute: '/',\n  onGenerateRoute: (settings) {\n    if (settings.name == '/') {\n      return GetPageRoute(\n        page: () => Scaffold(\n          appBar: AppBar(\n            title: Text(\"Main\"),\n          ),\n          body: Center(\n            child: TextButton(\n              color: Colors.blue,\n              onPressed: () {\n                Get.toNamed('/second', id:1); // indexe göre iç içe geçmiş rotanıza göre gezinin\n              },\n              child: Text(\"Go to second\"),\n            ),\n          ),\n        ),\n      );\n    } else if (settings.name == '/second') {\n      return GetPageRoute(\n        page: () => Center(\n          child: Scaffold(\n            appBar: AppBar(\n              title: Text(\"Main\"),\n            ),\n            body: Center(\n              child:  Text(\"second\")\n            ),\n          ),\n        ),\n      );\n    }\n  }\n),\n```\n"
  },
  {
    "path": "documentation/tr_TR/state_management.md",
    "content": "* [State Management](#state-management)\n  + [Reactive State Manager](#reactive-state-manager)\n    - [Avantajlar](#avantajlar)\n    - [Maksimum Performans:](#maksimum-performans)\n    - [Reaktif bir değişken bildirmek](#reaktif-bir-değişken-bildirmek)\n        - [Reaktif bir state'e sahip olmak kolaydır.](#reaktif-bir-state'e-sahip-olmak-kolaydır)\n    - [Görünümdeki değerleri kullanmak](#görünümdeki-değerleri-kullanmak)\n    - [Yeniden oluşturulacak koşullar](#yeniden-oluşturulacak-koşullar)\n    - [Nerede .obs kullanılabilir](#nerede-obs-kullanılabilir)\n    - [Listeler hakkında not](#listeler-hakkında-not)\n    - [Neden .value kullanmak zorundayım?](#neden-value-kullanmak-zorundayım?)\n    - [Obx()](#obx)\n    - [Çalışanlar](#Çalışanlar)\n  + [Simple State Manager](#simple-state-manager)\n    - [Avantajlar](#avantajlar-1)\n    - [Kullanımı](#kullanımı)\n    - [Controller'lar nasıl çalışır](#controller'lar-nasıl-çalışır)\n    - [Artık StatefulWidget'lara ihtiyacınız olmayacak](#artık-statefulwidget'lara-ihtiyacınız-olmayacak)\n    - [Neden var](#neden-var)\n    - [Kullanmanın diğer yolları](#kullanmanın-diğer-yolları)\n    - [Unique IDs-Benzersiz Kimlikler](#unique-ids-benzersiz-kimlikler)\n  + [İki state managers ile Mixing](#İki-state-managers-ile-mixing)\n  + [GetBuilder vs GetX vs Obx vs MixinBuilder](#getbuilder-vs-getx-vs-obx-vs-mixinbuilder)\n\n# State Management\n\nGetX, diğer State Management'ler (Durum Yöneticileri) gibi Streams veya ChangeNotifier kullanmaz. Niye? GetX ile android, iOS, web, linux, macos ve linux için uygulamalar oluşturmaya ek olarak, Flutter/GetX ile aynı syntax(sözdizimine) sahip server(sunucu) uygulamaları oluşturabilirsiniz. Yanıt süresini iyileştirmek ve RAM tüketimini azaltmak için düşük işletim maliyetiyle çok fazla performans sunan düşük gecikmeli çözümler olan GetValue ve GetStream'i oluşturduk. State Management (Durum Yönetimi) de dahil olmak üzere tüm kaynaklarımızı oluşturmak için bu temeli kullanıyoruz.\n\n* _Complexity_ (Karmaşıklık):  Bazı state management'ler karmaşıktır ve çok fazla ortak özelliği vardır. GetX ile her olay için bir sınıf tanımlamanız gerekmez, kod son derece temiz ve nettir ve daha az yazarak çok daha fazlasını yaparsınız. Pek çok insan bu konu yüzünden Flutter'dan vazgeçti ve şimdi nihayet durumları yönetmek için basit bir çözüme sahipler.\n* _No code generators_ (Kod Oluşturucu Yok): Geliştirme zamanınızın yarısını uygulama mantığınızı yazmaya harcarsınız. Bazı state management'ler, minimum düzeyde okunabilir koda sahip olmak için kod oluşturuculara güvenir. Bir değişkeni değiştirmek ve build_runner'ı çalıştırmak verimsiz olabilir ve genellikle flutter clean'den sonraki bekleme süresi uzun olur ve çok fazla kahve içmeniz gerekir.\n\nGetX ile her şey reaktiftir ve hiçbir şey kod oluşturuculara bağlı değildir, bu da geliştirmenizin tüm yönlerinde üretkenliğinizi artırır.\n\n* _It does not depend on context(Context'e bağlı değil)_: Muhtemelen görünümünüzün context'ini (bağlam) bir denetleyiciye göndermeniz gerekiyordu, bu da görünümün iş mantığınızla bağlantısını yüksek hale getirdi. Muhtemelen context'i (bağlamı) olmayan bir yer için bir bağımlılık kullanmak zorunda kaldınız ve context'i(bağlamı) çeşitli sınıflar ve fonksiyonlardan geçirmek zorunda kaldınız.Bu sadece GetX ile mevcut değil. Controller'larınıza (Denetleyicilerinize) , controller'larınızın(denetleyicilerinizin) içinden herhangi bir context (bağlam) olmadan erişebilirsiniz. Kelimenin tam anlamıyla hiçbir şey için context'i(bağlamı) parametreye göre göndermeniz gerekmez.\n* _Granular control(Parçacıklı Kontrol)_: Çoğu state management(durum yöneticisi) ChangeNotifier'ı temel alır. ChangeNotifier, notifyListeners çağrıldığında kendisine bağlı olan tüm widget'ları bilgilendirecektir. Bir ekranda ChangeNotifier sınıfınızın bir değişkenine sahip 40 widget'ınız varsa, birini güncellediğinizde hepsi yeniden oluşturulacaktır.\n\nGetX ile iç içe geçmiş widget'lara bile saygı duyulur. Obx listview'inizi izliyorsa ve diğeri ListView içinde bir onay kutusu izliyorsa, CheckBox değerini değiştirirken yalnızca o onay kutusu güncellenir, Liste değerini değiştirirken yalnızca ListView güncellenir.\n\n* _It only reconstructs if its variable REALLY changes (Değişken değişirse GERÇEKTEN yeniden yapılandırır)_: GetX akış kontrolüne sahiptir, yani 'Paola' ile bir text(metin) görüntülerseniz, (observable)gözlemlenebilir değişkeni tekrar 'Paola' olarak değiştirirseniz, widget yeniden yapılandırılmayacaktır. Çünkü GetX, 'Paola'nın' zaten text'de(metinde) görüntülendiğini ve gereksiz rekonstrüksiyonlar yapmayacağını biliyor.\n\nMevcut state management'lerin(durum yöneticilerin) çoğu (hepsi değilse de) ekranda yeniden oluşturulur.\n\n## Reactive State Manager\n\nReaktif programlama birçok insanı yabancılaştırabilir çünkü karmaşık olduğu söylenir. GetX reaktif programlamayı oldukça basit bir şeye dönüştürür:\n\n* Stream Controller oluşturmanıza gerek yoktur.\n* Her değişken için bir StreamBuilder oluşturmanız gerekmez.\n* Her state(durum) için bir sınıf oluşturmanız gerekmeyecektir.\n* Bir initial value(başlangıç değeri) için bir get oluşturmanız gerekmeyecektir.\n\nGet ile reaktif programlama, Setstate'i kullanmak kadar kolaydır.\n\nBir ad değişkeniniz olduğunu ve her değiştirdiğinizde onu kullanan tüm widget'ların otomatik olarak değiştirilmesini istediğinizi düşünelim.\n\nBu sizin count(sayım) değişkeninizdir:\n\n``` dart\nvar name = 'Jonatas Borges';\n```\n\nObservable hale getirmek için, sonuna \".obs\" eklemeniz gerekir:\n\n``` dart\nvar name = 'Jonatas Borges'.obs;\n```\n\nHepsi bu. *Bu kadar basit* bir şey.\n\nŞu andan itibaren, bu reaktif-\".obs\"(ervables) değişkenlerine _Rx_ adını verebiliriz.\n\nBaşlık altında ne yaptık? `String` lerin bir `Stream` oluşturduk, `\"Jonatas Borges\"` initial value'sunu(başlangıç değerini) atadık, `\"Jonatas Borges\"` kullanan tüm widget'lara artık bu değişkene \"ait olduklarını\" bildirdik ve _Rx_ değeri değiştiğinde de değişmeleri gerekecek.\n\nBu, Dart'ın yetenekleri sayesinde **GetX'in büyüsüdür**.\n\nAncak, bildiğimiz gibi, bir `Widget` yalnızca bir işlevin içindeyse değiştirilebilir, çünkü statik sınıflar \"otomatik değiştirme\" gücüne sahip değildir.\n\nBir `StreamBuilder` oluşturmanız, değişiklikleri dinlemek için bu değişkene abone olmanız ve aynı kapsamdaki birkaç değişkeni değiştirmek istiyorsanız, iç içe geçmiş `StreamBuilder` bir \"kaskad\" oluşturmanız gerekir, değil mi?\n\nHayır, bir `StreamBuilder`a ihtiyacınız yok, ancak statik sınıflar konusunda haklısınız.\n\nPekala, görünüşe göre, belirli bir Widget'ı değiştirmek istediğimizde genellikle çok fazla ortak bilgimiz olur, bu Flutter yoludur.\n**GetX** ile bu ortak kod kodunu da unutabilirsiniz.\n\n`StreamBuilder( … )` ? `initialValue: …` ? `builder: …` ? Hayır, bu değişkeni bir `Obx()` Widget'ına yerleştirmeniz yeterlidir.\n\n``` dart\nObx (() => Text (controller.name));\n```\n\n_Ezberlemek için neye ihtiyacın var?_Sadece `Obx(() =>` .\n\nBu Widget'ı bir ok işlevinden bir `Obx()` (_Rx_'in \"Observable\") içine geçiriyorsunuz.\n\n`Obx` oldukça akıllıdır ve yalnızca `controller.name`nin değeri değiştiğinde değişecektir.\n\n`name`, `\"John\"` ise ve onu `\"John\"` ( `name.value = \"John\"` ) olarak değiştirirseniz, öncekiyle aynı `değer` olduğundan, ekranda hiçbir şey değişmeyecektir, ve 'Obx' , kaynakları kurtarmak için yeni değeri yok sayar ve Widget'ı yeniden oluşturmaz. **Harika değil mi?**\n\n> Peki ya bir `Obx` içinde 5 _Rx_ (observable) değişkenim varsa?\n\nYalnızca **herhangi biri** değiştiğinde güncellenecektir.\n\n> Ve bir sınıfta 30 değişkenim varsa, birini güncellediğimde, o sınıftaki değişkenlerin **tümünü** günceller mi?\n\nHayır, sadece bu _Rx_ değişkenini kullanan **belirli Widget**.\n\nBu nedenle, **GetX** yalnızca _Rx_ değişkeni değerini değiştirdiğinde ekranı günceller.\n\n```\n\nfinal isOpen = false.obs;\n\n// NOTHING will happen... same value.\nvoid onButtonTap() => isOpen.value=false;\n```\n\n### Avantajlar\n\n**GetX()**, güncellenen değişkenler üzerinde **ayrıntılı** kontrole ihtiyacınız olduğunda size yardımcı olur.\n\nBir eylem gerçekleştirdiğinizde tüm değişkenleriniz değiştirileceğinden `unique IDs(benzersiz kimliklere)` ihtiyacınız yoksa, `GetBuilder`ı kullanın,\nçünkü Simple State Updater(Basit Durum Güncelleyicisi)'dir (`setState ()` gibi bloklar halinde), sadece birkaç kod satırında yapılır.\nEn az CPU etkisine sahip olmak ve sadece tek bir amacı (_State_ rebuild) yerine getirmek ve mümkün olan en az kaynağı harcamak için basitleştirildi.\n\n**Güçlü** bir State Management (Durum Yöneticisi)'e ihtiyacınız varsa, **GetX** ile yanlış yapmış olamazsınız.\n\nDeğişkenlerle çalışmaz, ancak __flows__, içindeki her şey başlık altındaki `Streams`dır.\n\n\n_rxDart_ ile birlikte kullanabilirsiniz, çünkü her şey `Streams`,\nher \"_Rx_variable\"ın 'event(olayını)' dinleyebilirsiniz,\nçünkü içindeki her şey `Streams`'dir.\n\nKelimenin tam anlamıyla bir _BLoC_ yaklaşımıdır, _MobX_'den daha kolaydır ve kod oluşturucuları veya süslemeleri yoktur.\n**Herhangi bir şeyi** yalnızca bir `.obs` ile _\"Observable\"_ hale getirebilirsiniz.\n\n### Maksimum Performans:\n\nState Management (Durum Yöneticisinin)'in değiştiğinden emin olmak için akıllı bir algoritmaya sahip olmanın yanı sıra **GetX** comparators kullanır.\n\nUygulamanızda herhangi bir hatayla karşılaşırsanız ve yinelenen bir State(durum) değişikliği gönderirseniz,\n**GetX** çökmemesini sağlayacaktır.\n\n**GetX** ile State(Durum) yalnızca `value(değer)` değişirse değişir.\nBu, **GetX** ile mobx_'den _ `computed` kullanımı arasındaki temel farktır.\nİki defa __observable__ 'da bir değişiklik yapıldığında; o _observable_ dinleyicisi de değişecektir.\n\n\n**GetX** ile, iki değişkeni birleştirirseniz, `GetX()` (`Observer()`a benzer) yalnızca gerçek bir State(Durum) değişikliği gerektiriyorsa yeniden oluşturacaktır.\n\n### Reaktif bir değişken bildirmek\n\nBir değişkeni \"observable\" hale getirmenin 3 yolu vardır.\n\n1 - Birincisi **`Rx{Type}`** kullanmak.\n\n``` dart\n// initial value önerilir, zorunlu değildir.\nfinal name = RxString('');\nfinal isLogged = RxBool(false);\nfinal count = RxInt(0);\nfinal balance = RxDouble(0.0);\nfinal items = RxList<String>([]);\nfinal myMap = RxMap<String, int>({});\n```\n\n2 - İkincisi, **`Rx`** kullanmak ve Darts Generics, `Rx<Type>` kullanmaktır.\n\n``` dart\nfinal name = Rx<String>('');\nfinal isLogged = Rx<Bool>(false);\nfinal count = Rx<Int>(0);\nfinal balance = Rx<Double>(0.0);\nfinal number = Rx<Num>(0);\nfinal items = Rx<List<String>>([]);\nfinal myMap = Rx<Map<String, int>>({});\n\n// Custom classes - herhangi bir sınıf olabilir\nfinal user = Rx<User>();\n```\n\n3 - Üçüncü, daha pratik, daha kolay ve tercih edilen yaklaşım,`value`'ya bir **`.obs`** ekleyin:\n\n``` dart\nfinal name = ''.obs;\nfinal isLogged = false.obs;\nfinal count = 0.obs;\nfinal balance = 0.0.obs;\nfinal number = 0.obs;\nfinal items = <String>[].obs;\nfinal myMap = <String, int>{}.obs;\n\n// Custom classes - herhangi bir sınıf olabilir\nfinal user = User().obs;\n```\n\n##### Reaktif bir state'e sahip olmak kolaydır.\n\nBildiğimiz gibi, _Dart_ şimdi _null safety_ doğru gidiyor.\nŞu andan itibaren hazırlıklı olmak için, _Rx_ değişkenlerinizi her zaman bir **initial value** ile başlatmalısınız.\n\n> Bir değişkeni **GetX** ile _observable_ + _initial value_ değerine dönüştürmek en basit ve pratik yaklaşımdır.\n\nKelimenin tam anlamıyla bir değişkeninizin sonuna bir \" `.obs` \" ekleyeceksiniz, ve **bu kadar**. Şimdi onu gözlemlenebilir hale getirdiniz,\nve onun `.value(değer)`'i,  _initial value_ olacaktır.\n\n### Görünümdeki değerleri kullanmak\n\n``` dart\n// controller dosyası\nfinal count1 = 0.obs;\nfinal count2 = 0.obs;\nint get sum => count1.value + count2.value;\n```\n\n``` dart\n// view dosyası\nGetX<Controller>(\n  builder: (controller) {\n    print(\"count 1 rebuild\");\n    return Text('${controller.count1.value}');\n  },\n),\nGetX<Controller>(\n  builder: (controller) {\n    print(\"count 2 rebuild\");\n    return Text('${controller.count2.value}');\n  },\n),\nGetX<Controller>(\n  builder: (controller) {\n    print(\"count 3 rebuild\");\n    return Text('${controller.sum}');\n  },\n),\n```\n\n`count1.value++` değerini artırırsak, şunu yazdırır:\n\n* `count 1 rebuild`\n\n* `count 3 rebuild`\n\n`count1`,  `1` değerine sahip olduğundan ve `1 + 0 = 1` olduğundan, `toplam` değeri değiştirilir.\n\n`count2.value++` değerini değiştirirsek, şunu yazdırır:\n\n* `count 2 rebuild`\n\n* `count 3 rebuild`\n\nçünkü `count2.value`  değişti ve `sum`un sonucu şimdi `2` oldu.\n\n* NOT: Varsayılan olarak, ilk etkinlik aynı `value` olsa bile widget'ı yeniden oluşturacaktır.\n\nBu durum boolean değişkenlerinde de mevcuttur.\n\nBunu yaptığınızı hayal edin:\n\n``` dart\nvar isLogged = false.obs;\n```\n\nArdından, bir kullanıcının `ever` içinde bir olayı tetiklemek için `isLogged` olup olmadığını kontrol ettiniz.\n\n``` dart\n@override\nonInit() async {\n  ever(isLogged, fireRoute);\n  isLogged.value = await Preferences.hasToken();\n}\n\nfireRoute(logged) {\n  if (logged) {\n   Get.off(Home());\n  } else {\n   Get.off(Login());\n  }\n}\n```\n\n\n`hasToken` `false` olsaydı, `isLogged`da herhangi bir değişiklik olmazdı, bu nedenle `ever()` asla çağrılmazdı.\nBu tür davranışlardan kaçınmak için, bir _observable_ öğesindeki ilk değişiklik her zaman bir olayı tetikleyecektir,\naynı `.value` değerini içerse bile.\n\nİsterseniz bu davranışı kullanarak kaldırabilirsiniz:\n `isLogged.firstRebuild = false;`\n\n### Yeniden oluşturulacak koşullar\n\nEk olarak, Get gelişmiş durum kontrolü sağlar. Bir olayı (listeye nesne ekleme gibi) belirli bir koşulda koşullandırabilirsiniz.\n\n``` dart\n// İlk parametre: koşul, true veya false döndürmelidir.\n// İkinci parametre: koşul doğruysa yeni değer uygulanacaktır.\nlist.addIf(item < limit, item);\n```\n\nSüslemesiz, kod oluşturucusuz, komplikasyonsuz :smile:\n\nFlutter'ın sayaç uygulamasını biliyor musunuz? Controller sınıfınız şöyle görünebilir:\n\n``` dart\nclass CountController extends GetxController {\n  final count = 0.obs;\n}\n```\n\nBasit bir şekilde:\n\n``` dart\ncontroller.count.value++\n```\n\nKullanıcı arabiriminizdeki sayaç değişkenini nerede depolandığına bakılmaksızın güncelleştirebilirsiniz.\n\n### Nerede .obs kullanılabilir\n\nObs üzerindeki her şeyi dönüştürebilirsiniz. İşte bunu yapmanın iki yolu:\n\n* Sınıf değerlerinizi obs'ye dönüştürebilirsiniz\n\n``` dart\nclass RxUser {\n  final name = \"Camila\".obs;\n  final age = 18.obs;\n}\n```\n\n* veya tüm sınıfı observable hale getirebilirsiniz.\n\n``` dart\nclass User {\n  User({String name, int age});\n  var name;\n  var age;\n}\n\n// örnek:\nfinal user = User(name: \"Camila\", age: 18).obs;\n```\n\n### Listeler hakkında not\n\nListeler, içindeki nesneler gibi tamamen gözlemlenebilir. Bu şekilde, bir listeye bir değer eklerseniz, onu kullanan widget'ları otomatik olarak yeniden oluşturur.\n\nAyrıca listelerde \".value\" kullanmanıza gerek yok, harika dart api'ları bunu kaldırmamıza izin verdi.\nNe yazık ki, String ve int gibi ilkel türler genişletilemez, bu da kullanımını sağlar. Değer zorunludur, ancak bunlar için get ve setter'larla çalışıyorsanız bu bir sorun olmayacaktır.\n\n``` dart\n// On the controller\nfinal String title = 'User Info:'.obs\nfinal list = List<User>().obs;\n\n// on the view\nText(controller.title.value), // .value olması gerekir\nListView.builder (\n  itemCount: controller.list.length // listelerin buna ihtiyacı yok\n)\n```\n\nKendi sınıflarınızı observable hale getirirken, bunları güncellemenin farklı bir yolu vardır:\n\n``` dart\n// model dosyasında\n// her bir öznitelik yerine tüm sınıfı observable hale getireceğiz\nclass User() {\n  User({this.name = '', this.age = 0});\n  String name;\n  int age;\n}\n\n// Controller dosyası\nfinal user = User().obs;\n// User değişkenini güncellemeniz gerektiğinde:\nuser.update( (user) { // bu parametre, güncellemek istediğiniz sınıfın kendisidir.\nuser.name = 'Jonny';\nuser.age = 18;\n});\n// user değişkenini güncellemenin alternatif bir yolu:\nuser(User(name: 'João', age: 35));\n\n// on view:\nObx(()=> Text(\"Name ${user.value.name}: Age: ${user.value.age}\"))\n// model değerlerine .value olmadan da erişebilirsiniz:\nuser().name;\n```\n\nİstemiyorsanız setlerle çalışmak zorunda değilsiniz. \"assign\" ve \"assignAll\" api'sini kullanabilirsiniz.\n\"assign\" api'si listenizi temizler ve oradan başlatmak istediğiniz tek bir nesneyi ekler.\n\"assignAll\" api, mevcut listeyi temizleyecek ve ona enjekte ettiğiniz yinelenebilir nesneleri ekleyecektir.\n\n### Neden .value kullanmak zorundayım?\n\nBasit bir decoration ve code generator ile `String` ve `int` için 'value' kullanma zorunluluğunu kaldırabiliriz, ancak bu kütüphanenin amacı kesinlikle dış bağımlılıklardan kaçınmaktır. Temelleri (route, dependencies ve state management) içeren, harici bir pakete ihtiyaç duymadan basit, hafif ve performanslı bir şekilde programlamaya hazır bir ortam sunmak istiyoruz.\n\nPubspec'inize (get) tam anlamıyla 3 harf ve iki nokta üst üste ekleyebilir ve programlamaya başlayabilirsiniz. Rota yönetiminden durum yönetimine kadar varsayılan olarak dahil edilen tüm çözümler kolaylık, üretkenlik ve performansı hedefler.\n\nBu kitaplığın toplam ağırlığı, eksiksiz bir çözüm olmasına rağmen tek bir state manager'den daha azdır.\n\n\nEğer `.value` dan rahatsızsanız MobX harika bir alternatiftir ve Get ile birlikte kullanabilirsiniz.\n\n\nMobX code generator ile bir sorununuz yoksa veya BLoC ilgili bir sorununuz yoksa Get ile route'u kullanabilirsiniz. Get SEM ve RSM ile doğdu, şirketimin 90'dan fazla controller'a sahip bir projesi var.Büyük bir projeniz varsa, oldukça iyi bir makinede bir Flutter Clean'den sonra görevlerini tamamlaması 30 dakikadan fazla sürdü. 5, 10, 15 controller, herhangi bir state manager size yardımcı olacaktır. Büyük bir projeniz varsa ve code generator sizin için bir sorunsa, bu çözüm size verildi.\n\nAçıkçası, birisi projeye katkıda bulunmak ve bir code generator veya benzeri bir şey oluşturmak istiyorsa, bunu readme'de alternatif olarak bağlantı ekleyeceğim, şimdilik diyorum ki, bunu zaten yapan iyi çözümler var, MobX gibi.\n\n### Obx()\n\nBindings kullanarak Get yazmak gereksizdir. Yalnızca bir pencere öğesi oluşturan anonim işlevi alan GetX yerine Obx pencere aracını kullanabilirsiniz.\nAçıkçası, bir tür kullanmıyorsanız, değişkenleri kullanmak için denetleyicinizin bir örneğine sahip olmanız veya değeri almak için `Get.find<Controller>()` .value veya Controller.to.value öğesini kullanmanız gerekir. .\n\n### Çalışanlar\n\nBir olay meydana geldiğinde belirli geri aramaları tetikleyerek size yardımcı olacaktır.\n\n``` dart\n/// 'Count1' her değiştiğinde çağrılır.\never(count1, (_) => print(\"$_ has been changed\"));\n\n/// $_ değişkeni yalnızca ilk kez değiştirildiğinde çağrılır.\nonce(count1, (_) => print(\"$_ was changed once\"));\n\n/// Anti DDoS - Örneğin, kullanıcı 1 saniye boyunca yazmayı her durdurduğunda çağrılır.\ndebounce(count1, (_) => print(\"debouce$_\"), time: Duration(seconds: 1));\n\n/// 1 saniye içinde tüm değişiklikleri yok sayın.\ninterval(count1, (_) => print(\"interval $_\"), time: Duration(seconds: 1));\n```\n\nTüm çalışanlar (`debounce` dışında), \"bool\" veya \"bool\" döndüren bir callback olabilen bir \"Koşul\" adlı parametreye sahiptir.\nBu \"koşul\", \"callback\" işlevinin ne zaman yürütüleceğini tanımlar.\n\nTüm çalışanlar, çalışanı iptal etmek için ( `dispose()` aracılığıyla) kullanabileceğiniz bir 'Worker' örneği döndürür.\n\n\n* **`ever`**\n\n_Rx_ değişkeni her yeni bir değer yaydığında çağrılır.\n\n* **`everAll`**\n\n`ever` gibi, ancak değişkeni her değiştirildiğinde çağrılan _Rx_ değerlerinin bir `List`'ini alır. Bu kadar.\n\n* **`once`**\n\n'once', yalnızca değişken ilk değiştirildiğinde çağrılır.\n\n* **`debounce`**\n\n'debounce', yalnızca kullanıcı yazmayı bitirdiğinde API'nin çağrılmasını istediğiniz arama işlevlerinde çok kullanışlıdır. Kullanıcı \"Jonny\" yazarsa, apı'lerde J, o, n, n ve y harfleriyle 5 aramanız olur. Get ile bu olmaz, çünkü yalnızca yazmanın sonunda tetiklenecek bir \"debounce\" çalışanınız olur.\n\n* **`interval`**\n\n'interval' debouce'dan farklıdır. debouce kullanıcı 1 saniye içinde bir değişkene 1000 değişiklik yaparsa, öngörülen zamanlayıcıdan sonra yalnızca sonuncusunu gönderir (varsayılan değer 800 milisaniyedir). Interval bunun yerine, öngörülen süre boyunca tüm kullanıcı eylemlerini yoksayar. Olayları saniyede 1000 olmak üzere 1 dakika boyunca gönderirseniz, debounce yalnızca kullanıcı olayları engellemeyi bıraktığında size sonuncusunu gönderir. aralık, her saniye olayları teslim eder ve 3 saniyeye ayarlanırsa, o dakika 20 olay teslim eder. Bu, kullanıcının bir şeye hızlı bir şekilde tıklayabileceği ve bir avantaj elde edebileceği işlevlerde kötüye kullanımı önlemek için önerilir (kullanıcının bir şeye tıklayarak para kazanabileceğini düşünün, aynı dakikada 300 kez tıklarsa, 300 jetona sahip olur, aralığı kullanarak, bir zaman dilimi ayarlayabilirsiniz 3 saniye boyunca ve hatta 300 veya bin kez tıklandığında, 1 dakika içinde alacağı maksimum 20 jeton, 300 veya 1 milyon kez tıklanır). Debounce, anti-DDoS için, Onchange'deki her değişikliğin apı'nizde bir sorguya neden olacağı arama gibi işlevler için uygundur. Debounce, kullanıcının isteği yapmak için adı yazmayı bırakmasını bekleyecektir. Yukarıda belirtilen jeton senaryosunda kullanılmış olsaydı, kullanıcı yalnızca belirlenen süre boyunca \"durakladığında\" çalıştırıldığı için kullanıcı yalnızca 1 jeton kazanırdı.\n\n* NOT: Çalışanlar her zaman bir Controller veya Class başlatırken kullanılmalıdır, bu nedenle her zaman onInit (önerilen), Class oluşturucu veya statefulwidget'in initState üzerinde olmalıdır (bu uygulama çoğu durumda önerilmez, ancak herhangi bir yan etkisi olmamalıdır).\n\n## Simple State Manager(Basit Durum Yöneticisi)\n\nGet'in son derece hafif ve kolay, ChangeNotifier kullanmayan, özellikle Flutter'a yeni başlayanların ihtiyacını karşılayacak ve büyük uygulamalar için sorun yaratmayacak bir state manager'i var.\n\nGetBuilder tam olarak çoklu state controller'a yöneliktir. Bir sepete 30 ürün eklediğinizi, birini sil'i tıklattığınızı, aynı zamanda listenin güncellendiğini, fiyatın güncellendiğini ve alışveriş sepetindeki rozetin daha küçük bir sayıya güncellendiğini düşünün. Bunu GetBuilder yapar, çünkü durumları gruplandırır ve bunun için herhangi bir \"hesaplama mantığı\" olmadan hepsini bir kerede değiştirir. GetBuilder, bu tür bir durum göz önünde bulundurularak oluşturuldu, çünkü geçici durum değişikliği için Setstate'i kullanabilirsiniz ve bunun için bir state manager'e ihtiyacınız olmaz.\n\nBu şekilde, tek bir controller'a ihtiyacınız varsa, bunun için ID'ler atayabilir veya getx'i kullanabilirsiniz. Bu size kalmış, sahip olduğunuz daha fazla \"individual\" widget'ın, getx'in performansının o kadar fazla öne çıkacağını, Getbuilder'ın performansının ise birden fazla durum değişikliği olduğunda üstün olması gerektiğini unutmayın.\n\n### Avantajlar\n\n1. Yalnızca gerekli widget'ları günceller.\n\n2. ChangeNotifier kullanmaz, daha az bellek kullanan (0mb'ye yakın) durum yöneticisidir.\n\n3. StatefulWidget'ı unutun! Get ile buna asla ihtiyacınız olmayacak. Diğer state manager'lar ile (BLoC, MobX Controller vb.) muhtemelen bir StatefulWidget kullanmanız gerekecek. Stateless Widget mı? Öyleyse, yalnızca state bilgisi olan Widget'ın durumunu kaydedebiliyorsanız, neden tüm sınıfın durumunu kurtarın? Get bunu da çözer. Stateless bir sınıf oluşturun, her şeyi Stateless yapın. Tek bir bileşeni güncellemeniz gerekiyorsa, onu GetBuilder ile sarın.\n\n4. Projenizi gerçek anlamda düzenleyin! Denetleyiciler UI'nizde bulunmamalı, TextEditController'ınızı veya kullandığınız herhangi bir denetleyiciyi Controller sınıfınıza yerleştirmemelidir.\n\n5.Bir widget'ı oluşturulduğu anda güncellemek için bir olayı tetiklemeniz mi gerekiyor? GetBuilder, StatefulWidget gibi \"initState\" özelliğine sahiptir ve initState'inize daha fazla event yerleştirilmeden, doğrudan denetleyicinizden event'leri çağırabilirsiniz.\n\n6. Stream, timer vb. kapatmak gibi bir eylemi tetiklemeniz gerekiyor mu? Get Builder ayrıca, widget yok edilir edilmez olayları çağırabileceğiniz dispose özelliğine de sahiptir.\n\n7. Stream'leri yalnızca gerektiğinde kullanın. Stream Controller controller içinde normal olarak kullanabilir ve Streambuilder'ı da normal olarak kullanabilirsiniz, ancak unutmayın, bir stream makul bir şekilde bellek tüketir, reaktif programlama güzeldir, ancak kötüye kullanmamalısınız. aynı anda açılan 30 stream, Changenotifier'den daha kötü olabilir (ve changeNotifier çok kötüdür).\n\n8. Ram harcamadan widget'ları güncelleyin. Get yalnızca Get Builderlder içerik oluşturucu kimliğini ve gerektiğinde GetBuilder güncelleştirmelerini depolar. Bellekte get ID depolama bellek tüketimi bile GetBuilders binlerce çok düşüktür. Yeni bir GetBuilder oluşturduğunuzda, aslında bir içerik oluşturucu kimliği olan GetBuilder durumunu paylaşıyorsunuz demektir. Her GetBuilder için büyük uygulamalar için çok fazla ram tasarrufu sağlayan yeni bir durum oluşturulmaz. Temel olarak uygulamanız tamamen Stateless olacak ve State Bilgisi olan birkaç Widget (GetBuilder içinde) tek bir duruma sahip olacak ve bu nedenle birini güncellemek hepsini güncelleyecektir. State sadece bir tanesidir.\n\n9. Get her şeyi bilir ve çoğu durumda bir denetleyiciyi bellekten çıkarma zamanını tam olarak bilir. Bir denetleyiciyi ne zaman elden çıkaracağınız konusunda endişelenmemelisiniz, Bunu yapmak için en iyi zamanı öğrenin.\n\n### Kullanımı\n\n``` dart\n// Controller sınıfı oluşturun ve GetxController'ı extends edin\nclass Controller extends GetxController {\n  int counter = 0;\n  void increment() {\n    counter++;\n    update(); // artış çağrıldığında kullanıcı arayüzünde sayaç değişkenini güncellemek için update() işlevini kullanın\n  }\n}\n// Stateless/Stateful sınıfınızda, artış çağrıldığında Metni güncellemek için Get Builder'ı kullanın\nGetBuilder<Controller>(\n  init: Controller(), // INIT IT ONLY THE FIRST TIME\n  builder: (_) => Text(\n    '${_.counter}',\n  ),\n)\n\n//Initialize yalnızca ilk kez başlatın. Aynı controller için ReBuilder'ı ikinci kez kullanıyorsanız, tekrar kullanmayın. Controller'ınız, onu 'init' olarak işaretleyen pencere öğesi yerleştirildiği anda bellekten otomatik olarak kaldırılacaktır. Bunun için endişelenmenize gerek yok, Get bunu otomatik olarak yapacak, sadece aynı contrroller'ın iki kez başlatmadığınızdan emin olun.\n```\n\n**Tamamlandı!**\n\n* Get ile durumları nasıl yöneteceğinizi öğrendiniz.\n\n* Not: Daha büyük bir organizasyon isteyebilirsiniz ve init özelliğini kullanmayabilirsiniz. Bunun için bir sınıf oluşturup Bindings sınıfını extends edebilir ve bunun içinde o rotada oluşturulacak controller'dan bahsedebilirsiniz. Controller'lar o anda oluşturulmaz, tam tersine, bu sadece bir ifadedir, böylece bir Controller'ı ilk kullandığınızda, nereye bakacağınızı bilecek. Get lazyLoad olarak kalacak ve artık ihtiyaç duyulmadığında Controller'ları elden çıkarmaya devam edecek. Nasıl çalıştığını görmek için pub.dev örneğine bakın.\n\nBirçok rotada gezinirseniz ve daha önce kullandığınız controller'ınızda bulunan verilere ihtiyacınız varsa, GetBuilder tekrar (init olmadan) kullanmanız yeterlidir:\n\n``` dart\nclass OtherClass extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      body: Center(\n        child: GetBuilder<Controller>(\n          builder: (s) => Text('${s.counter}'),\n        ),\n      ),\n    );\n  }\n\n```\n\nController'ınızı GetBuilder dışında birçok başka yerde kullanmanız gerekiyorsa, controller'ınıza bir get oluşturun ve kolayca elde edin. (veya `Get.find<Controller>()` kullanın)\n\n``` dart\nclass Controller extends GetxController {\n\n   /// Buna ihtiyacın yok. Sadece syntax kolaylığı için kullanmanızı öneririm.\n   /// statik yöntemle: Controller.to.increment();\n   /// statik yöntem olmadan: Get.find<Controller>().increment();\n   /// Her iki syntax kullanmanın herhangi bir yan etkisi veya performans farkı yoktur. Yalnızca birinin türe ihtiyacı yoktur ve diğeri IDE tarafından otomatik olarak tamamlanır.\n  static Controller get to => Get.find(); // bu satırı ekleyin\n\n  int counter = 0;\n  void increment() {\n    counter++;\n    update();\n  }\n}\n```\n\nVe sonra controller'a doğrudan bu şekilde erişebilirsiniz:\n\n``` dart\nFloatingActionButton(\n  onPressed: () {\n    Controller.to.increment(),\n  } // Bu inanılmaz derecede basit!\n  child: Text(\"${Controller.to.counter}\"),\n),\n```\n\nFloatingActionButton tuşuna bastığınızda, 'counter' değişkenini dinleyen tüm widget'lar otomatik olarak güncellenir.\n\n### Controller'lar nasıl çalışır\n\nDiyelim ki elimizde bu var:\n\n `Class a => Class B (has controller X) => Class C (has controller X)`\n\nA sınıfında controller henüz bellekte değil çünkü henüz kullanmadınız (Get is lazyLoad). B sınıfında controller kullandınız ve belleğe girdi. C sınıfında, B sınıfındakiyle aynı controller'ı kullandınız, Get, controller B'nin durumunu C controller'ı ile paylaşacak ve aynı controller hala bellekte kalacaktır. C ekranını ve B ekranını kapatırsanız, Get, A Sınıfı controller'ı kullanmadığından otomatik olarak X controller'ını bellekten alır ve kaynakları boşaltır. Tekrar B'ye giderseniz, X controller'ı tekrar belleğe girer, C sınıfına gitmek yerine tekrar A sınıfına dönerseniz Get, controller aynı şekilde bellekten çıkarır. C sınıfı controller'ı kullanmadıysa ve B sınıfını bellekten çıkardıysanız, hiçbir sınıf controller'ı X kullanmayacak ve aynı şekilde imha edilecektir. Get ile bulaşabilecek tek istisna, B'yi rotadan beklenmedik bir şekilde kaldırırsanız ve controller'ı C'de kullanmaya çalışırsanız. Bu durumda, controller'ın B'deki ID silindi ve Get şu şekilde programlandı: ID olmayan her controller'ı bellekten kaldırın. Bunu yapmayı düşünüyorsanız, \"autoRemove: false\" işaretini B sınıfının GetBuilder'ına ekleyin ve adoptID = true; yapın C sınıfında GetBuilder kullanın.\n\n### Artık StatefulWidget'lara ihtiyacınız olmayacak\n\nStateful Widget kullanmak, tüm ekranların durumunu gereksiz yere depolamak anlamına gelir, çünkü bir widget'ı minimum düzeyde yeniden oluşturmanız gerekse bile, onu başka bir Stateful Widget olacak olan bir Consumer/Observer/BlocProvider/GetBuilder/GetX/Obx içine gömeceksiniz. StatefulWidget sınıfı, daha fazla RAM tahsis edecek olan StatelessWidget'ten daha büyük bir sınıftır ve bu, bir veya iki sınıf arasında önemli bir fark yaratmayabilir, ancak 100 tanesine sahip olduğunuzda kesinlikle yapacaktır! TickerProviderStateMixin gibi bir mixin kullanmanız gerekmiyorsa, Get ile bir StatefulWidget kullanmak tamamen gereksiz olacaktır.\n\nStatefulWidget'ın tüm yöntemlerini doğrudan bir GetBuilder'dan çağırabilirsiniz.\nÖrneğin, initState() veya Dispose() yöntemini çağırmanız gerekiyorsa, bunları doğrudan çağırabilirsiniz;\n\n``` dart\nGetBuilder<Controller>(\n  initState: (_) => Controller.to.fetchApi(),\n  dispose: (_) => Controller.to.closeStreams(),\n  builder: (s) => Text('${s.username}'),\n),\n```\n\nBundan çok daha iyi bir yaklaşım, doğrudan controller'dan onInit() ve onClose() yöntemini kullanmaktır.\n\n``` dart\n@override\nvoid onInit() {\n  fetchApi();\n  super.onInit();\n}\n```\n\n* NOT: Controller ilk kez çağrıldığı anda bir metot başlatmak istiyorsanız, bunun için constructors kullanmanıza GEREK YOKTUR, aslında Get gibi performans odaklı bir paket kullanarak bu sorunu çözebilirsiniz.  Controller'ların oluşturulduğu veya tahsis edildiği mantıktan saptığı için (bu controller'ın bir örneğini oluşturursanız, constructor hemen çağrılır, bir controller kullanılmadan önce bellek ayırırsınız ve belleği doldurursunuz. Bu kesinlikle bu kütüphanenin ilkelerine zarar verir. onInit() yöntemleri; ve onClose(); için oluşturulduysa, Get.lazyPut kullanıp kullanmadığınıza bağlı olarak Controller oluşturulduğunda veya ilk kez kullanıldığında çağrılırlar. Örneğin, verileri doldurmak için API'nize bir çağrı yapmak istiyorsanız, eski moda initState/dispose yöntemini unutabilirsiniz, sadece onInit'te api'ye çağrınızı başlatın ve herhangi bir komutu çalıştırmanız gerekirse akışları kapatmak gibi, bunun için onClose()'u kullanın.\n\n### Neden var\n\nBu paketin amacı, mümkün olan en az bağımlılıkları kullanarak, yüksek derecede ayrıştırma ile rotaların gezinmesi, bağımlılıkların ve durumların yönetimi için eksiksiz bir çözüm sunmaktır. Get, mümkün olan en az bağlantıyla çalıştığınızdan emin olmak için tüm yüksek ve düşük seviyeli Flutter API'lerini kendi içinde çalıştırır. Projenizde herhangi bir bağlantı olmadığından emin olmak için her şeyi tek bir pakette merkezileştiriyoruz. Bu şekilde, görünümünüze yalnızca widget'lar koyabilir ve ekibinizin iş mantığıyla çalışan bölümünü, Görünümün herhangi bir öğesine bağlı kalmadan iş mantığıyla çalışmak üzere serbest bırakabilirsiniz. Bu, çok daha temiz bir çalışma ortamı sağlar, böylece ekibinizin bir kısmı controller'a veri göndermekten endişe etmeden yalnızca widget'larla çalışır ve ekibinizin bir kısmı, görünümün hiçbir öğesine bağlı kalmadan yalnızca genişliğindeki iş mantığıyla çalışır.\n\nYani bunu basitleştirirsek:\nInitstate'deki yöntemleri çağırmanız ve bunları controller'ınıza parametre ile göndermeniz veya bunun için controller içerisinde constructor kullanmanız gerekmez, doğru zamanda çağrılan onInit () yöntemine sahip olursunuz.\nCihaz aramak zorunda değilsiniz, gerektiğinde tam zamanında close() yöntemi ile hafızasından silinecektir. Bu şekilde, yalnızca widget'lar için görünümler bırakın, her türlü iş mantığından kaçının.\n\nGetxController içinde bir dispose yöntemi çağırmayın, hiçbir şey yapmaz, controller'ın bir Widget olmadığını, \"dispose\" gerektiğini ve Get tarafından bellekten otomatik ve akıllıca kaldırılacağını unutmayın. Üzerinde herhangi bir akış kullandıysanız ve kapatmak istiyorsanız, onu close yöntemine eklemeniz yeterlidir. Örnek:\n\n\n``` dart\nclass Controller extends GetxController {\n  StreamController<User> user = StreamController<User>();\n  StreamController<String> name = StreamController<String>();\n\n  /// close stream = onClose yöntemi, dispose değil.\n  @override\n  void onClose() {\n    user.close();\n    name.close();\n    super.onClose();\n  }\n}\n```\n\nController life cycle(yaşam döngüsü):\n\n* onInit() oluşturulduğu yer.\n* onClose() close yöntemine hazırlanırken herhangi bir değişiklik yapmak için kapatıldığı yer.\n* deleted: Controller bellekten tam anlamıyla kaldırdığı için bu API'ye erişiminiz olmaz. Herhangi bir iz bırakmadan kelimenin tam anlamıyla silinir.\n\n### Kullanmanın diğer yolları\n\n\nController'ı doğrudan GetBuilder ile kullanabilirsiniz:\n\n``` dart\nGetBuilder<Controller>(\n  init: Controller(),\n  builder: (value) => Text(\n    '${value.counter}', //here\n  ),\n),\n```\n\nController'ınızı GetBuilder dışında bir örneğine de ihtiyacınız olabilir ve bunu başarmak için bu yaklaşımları kullanabilirsiniz:\n\n``` dart\nclass Controller extends GetxController {\n  static Controller get to => Get.find();\n[...]\n}\n// görünümde:\nGetBuilder<Controller>(\n  init: Controller(), // Her controller'ı bir kez kullanın\n  builder: (_) => Text(\n    '${Controller.to.counter}', //burada\n  )\n),\n```\n\nor\n\n``` dart\nclass Controller extends GetxController {\n // static Controller get to => Get.find(); // static olmadan\n[...]\n}\n// on stateful/stateless class\nGetBuilder<Controller>(\n  init: Controller(), // Her controller'ı bir kez kullanın\n  builder: (_) => Text(\n    '${Get.find<Controller>().counter}', //burada\n  ),\n),\n```\n\n* Bunu yapmak için \"non-canonical\" yaklaşımları kullanabilirsiniz. Get_it, modular vb. Gibi başka bir dependency manager kullanıyorsanız ve sadece controller instance etmek istiyorsanız, bunu yapabilirsiniz:\n\n``` dart\nController controller = Controller();\n[...]\nGetBuilder<Controller>(\n  init: controller, //burada\n  builder: (_) => Text(\n    '${controller.counter}', // burada\n  ),\n),\n\n```\n\n### Unique IDs-Benzersiz Kimlikler\n\nBir widget'ın controller'ını güncellemek istiyorsanız GetBuilder onlara benzersiz kimlikler atayabilirsiniz:\n\n``` dart\nGetBuilder<Controller>(\n  id: 'text'\n  init: Controller(), // Her controller'ı bir kez kullanın\n  builder: (_) => Text(\n    '${Get.find<Controller>().counter}', //burada\n  ),\n),\n```\n\nVe bu formu güncelleyin:\n\n``` dart\nupdate(['text']);\n```\n\nGüncelleme için koşullar da uygulayabilirsiniz:\n\n``` dart\nupdate(['text'], counter < 10);\n```\n\nGetX bunu otomatik olarak yapar ve yalnızca değiştirilen değişkeni tam olarak kullanan widget'ı yeniden yapılandırır, bir değişkeni öncekiyle aynı olacak şekilde değiştirirseniz ve bu state değişikliği anlamına gelmezse GetX widget'ı bellek ve CPU döngülerinden tasarruf etmek için yeniden oluşturmaz (ekranda 3 görüntüleniyor ve değişkeni tekrar 3 olarak değiştirirsiniz. Çoğu state manager, bu yeni bir yeniden yapılanmaya neden olur, ancak Get ile widget yalnızca state değiştiyse yeniden oluşturulur).\n\n## İki state managers ile Mixing\n\nBazı insanlar, yalnızca bir tür reaktif değişken ve diğer mekanikleri kullanmak istediklerinden ve bunun için bir GetBuilder'a bir Obx eklemeleri gerektiğinden bir özellik request'i açtı. Bunu düşünerek MixinBuilder oluşturuldu. Hem \".obs\" değişkenlerini değiştirerek reaktif değişikliklere hem de update() aracılığıyla mekanik güncellemelere izin verildi. Bununla birlikte, 4 widget'tan en çok kaynak tüketendir, çünkü children'larda değişiklik olaylarını anlaması için sahip olmasının yanı sıra, controller'ın güncelleme yöntemine sahip olur.\n\nGetxController'ı extends etmek önemlidir, çünkü yaşam döngüleri vardır ve olayları onInit() ve onClose() yöntemlerinde \"başlatabilir\" ve \"bitebilir\". Bunun için herhangi bir sınıfı kullanabilirsiniz, ancak değişkenlerinizi observable olsun ya da olmasın yerleştirmek için GetxController sınıfını kullanmanızı şiddetle tavsiye ederim.\n\n## StateMixin\n\n`UI` state'ini ele almanın başka bir yolu da `StateMixin<T>` kullanmaktır.\nBunu uygulamak için, `StateMixin<T>` ile `with`i kullanın.\nbir controller'a T modelinizi ekleyin.\n\n``` dart\nclass Controller extends GetController with StateMixin<User>{}\n```\n\n\n`change()` yöntemi istediğimiz zaman State'i değiştirir.\nSadece verileri ve state'i bu şekilde iletin:\n\n```dart\nchange(data, status: RxStatus.success());\n```\n\nRxStatus şu duruma izin verir:\n\n``` dart\nRxStatus.loading();\nRxStatus.success();\nRxStatus.empty();\nRxStatus.error('message');\n```\n\nUI'da bu şekilde kullanın:\n\n```dart\nclass OtherClass extends GetView<Controller> {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n\n      body: controller.obx(\n        (state)=>Text(state.name),\n        \n        // burada özel yükleme göstergenizi koyabilirsiniz, ancak\n       // varsayılan olarak Center(child:CircularProgressIndicator()) olacaktır.\n        onLoading: CustomLoadingIndicator(),\n        onEmpty: Text('No data found'),\n\n        // burada ayrıca kendi hata widget'ınızı ayarlayabilirsiniz, ancak\n        // default birCenter(child:Text(error)) olacaktır.\n        onError: (error)=>Text(error),\n      ),\n    );\n}\n```\n\n## GetBuilder vs GetX vs Obx vs MixinBuilder\n\nProgramlamayla geçen on yılda bazı değerli dersler öğrenebildim.\n\nReaktif programlama ile ilk temasım çok \"vay be, bu inanılmaz\" oldu ve aslında reaktif programlama inanılmaz.\nAncak, tüm durumlar için uygun değildir. Çoğu zaman tek ihtiyacınız olan, aynı anda 2 veya 3 parçacığın durumunu değiştirmek veya geçici bir durum değişikliğidir, bu durumda reaktif programlama kötü değildir, ancak uygun değildir.\n\nReaktif programlama, bireysel iş akışıyla telafi edilebilecek daha yüksek bir RAM tüketimine sahiptir; bu, yalnızca bir widget'ın yeniden oluşturulmasını ve gerektiğinde yapılmasını sağlar, ancak her biri birkaç akışa sahip 80 nesneden oluşan bir liste oluşturmak iyi bir fikir değildir. Dartı açın ve bir StreamBuilder'ın ne kadar tükettiğini kontrol edin ve size ne söylemeye çalıştığımı anlayacaksınız.\n\nBunu akılda tutarak, basit bir state manager yarattım. Bu basittir ve ondan tam olarak talep etmeniz gereken şey budur: State'i bloklar halinde basit bir şekilde ve en ekonomik şekilde güncellemek.\n\nGetBuilder RAM'de çok ekonomiktir ve ondan daha ekonomik bir yaklaşım yoktur (en azından ben bir tane hayal edemiyorum, varsa lütfen bize bildirin).\n\nAncak GetBuilder hala mekanik bir state manager'dir, tıpkı Provider'ın notifyListeners() işlevini çağırmanız gerektiği gibi update() öğesini çağırmanız gerekir.\n\nReaktif programlamanın gerçekten ilginç olduğu başka durumlar da vardır ve onunla çalışmamak, tekerleği yeniden icat etmekle aynı şeydir. Bunu akılda tutarak GetX, bir State Manager'de en modern ve gelişmiş olan her şeyi sağlamak için oluşturuldu. Sadece gerekli olanı günceller ve gerektiğinde, bir hatanız varsa ve aynı anda 300 durum değişikliği gönderirseniz GetX, yalnızca durum gerçekten değiştiğinde ekranı filtreler ve günceller.\n\nGetX, diğer herhangi bir reaktif durum yöneticisinden hala daha ekonomiktir, ancak GetBuilder'dan biraz daha fazla RAM tüketir. Bunu düşünerek ve Obx'in yarattığı kaynakların tüketimini en üst düzeye çıkarmayı hedefleyerek. GetX ve GetBuilder'dan farklı olarak, bir Obx içinde bir controller başlatamayacaksınız, bu sadece children'larda değişiklik olaylarını alan bir StreamSubscription'a sahip bir Widget'tır, hepsi bu. GetX'ten daha ekonomiktir, ancak reaktif olduğu için beklendiği gibi GetBuilder'a kaydeder ve GetBuilder, bir parçacığın hashcode'unu ve StateSetter'ını depolamak için var olan en basit yaklaşıma sahiptir. Obx ile controller türünüzü yazmanız gerekmez ve değişikliği birden çok farklı controller'dan ulaşabilir ve dinleyebilirsiniz, ancak bu readme dosyasının başındaki örnek yaklaşım kullanılarak veya Bindings classı kullanılarak daha önce başlatılması gerekir.\n"
  },
  {
    "path": "documentation/vi_VI/dependency_management.md",
    "content": "# Quản lý dependency\n- [Quản lý dependency](#dependency-management)\n  - [Instancing methods](#instancing-methods)\n    - [Get.put()](#getput)\n    - [Get.lazyPut](#getlazyput)\n    - [Get.putAsync](#getputasync)\n    - [Get.create](#getcreate)\n  - [Sử dụng các phương thức / class](#using-instantiated-methodsclasses)\n  - [Khác nhau giữa phương thức (methods)](#differences-between-methods)\n  - [Bindings](#bindings)\n    - [Cách sử dụng](#how-to-use)\n    - [BindingsBuilder](#bindingsbuilder)\n    - [SmartManagement](#smartmanagement)\n      - [Cách thay đổi](#How-to-change)\n      - [SmartManagement.full](#smartmanagementfull)\n      - [SmartManagement.onlyBuilders](#smartmanagementonlybuilders)\n      - [SmartManagement.keepFactory](#smartmanagementkeepfactory)\n    - [Cách bindings làm việc ngầm](#how-bindings-work-under-the-hood)\n  - [Chí ú](#notes)\n\nGet có một trình quản lý dependency đơn giản và mạnh mẽ cho phép bạn truy xuất cùng một class với Blocs hoặc Controller của bạn chỉ với 1 dòng mã, không có \"context\", không có InheritedWidget\n\n```dart\nController controller = Get.put(Controller()); // Rather Controller controller = Controller();\n```\n\nThay vì khởi tạo class của bạn trong class bạn đang sử dụng, bạn đang khởi tạo nó trong phiên bản Get, điều này sẽ làm cho nó có sẵn trên toàn bộ Ứng dụng của bạn.\nVì vậy, bạn có thể sử dụng controller (hoặc class Blocs) của mình một cách bình thường\n\n- Note: Nếu bạn đang sử dụng Get's State Manager, hãy chú ý hơn đến [Bindings](#bindings) api, điều này sẽ giúp kết nối chế độ xem với controller của bạn dễ dàng hơn.\n- Note²: Quản lý state của Get được tách biệt khỏi các phần khác của gói, vì vậy, nếu ví dụ: nếu ứng dụng của bạn đã sử dụng trình quản lý state (bất kỳ cái nào, không quan trọng), bạn không cần phải thay đổi điều đó, bạn có thể sử dụng phần dependency này người quản lý không có vấn đề gì cả\n\n## Instancing methods\nCác phương thức và các tham số có thể định cấu hình của nó là:\n\n### Get.put()\n\nCách phổ biến nhất để chèn một dependency, là một điều tốt cho controller của View của bạn.\n\n```dart\nGet.put<SomeClass>(SomeClass());\nGet.put<LoginController>(LoginController(), permanent: true);\nGet.put<ListItemController>(ListItemController, tag: \"some unique string\");\n```\n\nĐây là tùy chọn mà bạn có thể đặt lệnh:\n```dart\nGet.put<S>(\n  // mandatory: the class that you want to get to save, like a controller or anything\n  // note: \"S\" means that it can be a class of any type\n  S dependency\n\n  // optional: this is for when you want multiple classess that are of the same type\n  // since you normally get a class by using Get.find<Controller>(),\n  // you need to use tag to tell which instance you need\n  // must be unique string\n  String tag,\n\n  // optional: by default, get will dispose instances after they are not used anymore (example,\n  // the controller of a view that is closed), but you might need that the instance\n  // to be kept there throughout the entire app, like an instance of sharedPreferences or something\n  // so you use this\n  // defaults to false\n  bool permanent = false,\n\n  // optional: allows you after using an abstract class in a test, replace it with another one and follow the test.\n  // defaults to false\n  bool overrideAbstract = false,\n\n  // optional: allows you to create the dependency using function instead of the dependency itself.\n  // this one is not commonly used\n  InstanceBuilderCallback<S> builder,\n)\n```\n\n### Get.lazyPut\nCó thể lazyLoad một dependecy để nó chỉ được khởi tạo khi được sử dụng. Rất hữu ích cho các class ngốn nhiều tài nguyên hoặc nếu bạn muốn khởi tạo một số class chỉ ở một nơi (như trong class Bindings) và bạn biết rằng mình sẽ không sử dụng class đó tại thời điểm nhất định.\n\n```dart\n/// ApiMock will only be called when someone uses Get.find<ApiMock> for the first time\nGet.lazyPut<ApiMock>(() => ApiMock());\n\nGet.lazyPut<FirebaseAuth>(\n  () {\n    // ... some logic if needed\n    return FirebaseAuth();\n  },\n  tag: Math.random().toString(),\n  fenix: true\n)\n\nGet.lazyPut<Controller>( () => Controller() )\n```\n\nĐây là các tùy chọn bạn có thể đặt lệnh:\n```dart\nGet.lazyPut<S>(\n  // mandatory: a method that will be executed when your class is called for the first time\n  InstanceBuilderCallback builder,\n  \n  // optional: same as Get.put(), it is used for when you want multiple different instance of a same class\n  // must be unique\n  String tag,\n\n  // optional: It is similar to \"permanent\", the difference is that the instance is discarded when\n  // is not being used, but when it's use is needed again, Get will recreate the instance\n  // just the same as \"SmartManagement.keepFactory\" in the bindings api\n  // defaults to false\n  bool fenix = false\n  \n)\n```\n\n### Get.putAsync\n Đây là khi bạn muốn xài asynchronize code `Get.putAsync`:\n\n```dart\nGet.putAsync<SharedPreferences>(() async {\n  final prefs = await SharedPreferences.getInstance();\n  await prefs.setInt('counter', 12345);\n  return prefs;\n});\n\nGet.putAsync<YourAsyncClass>( () async => await YourAsyncClass() )\n```\n\nĐây là tùy chọn bạn có thể đặt lệnh với putAsync:\n```dart\nGet.putAsync<S>(\n\n  // mandatory: an async method that will be executed to instantiate your class\n  AsyncInstanceBuilderCallback<S> builder,\n\n  // optional: same as Get.put(), it is used for when you want multiple different instance of a same class\n  // must be unique\n  String tag,\n\n  // optional: same as in Get.put(), used when you need to maintain that instance alive in the entire app\n  // defaults to false\n  bool permanent = false\n)\n```\n\n### Get.create\n\nCái này hơi khó giải thích, nhưng sự khác nhau giữa chúng có thể được tìm thấy trên mục [Differences between methods:](#differences-between-methods)\n\n```dart\nGet.Create<SomeClass>(() => SomeClass());\nGet.Create<LoginController>(() => LoginController());\n```\n\nTùy chọn có thể sử dụng:\n\n```dart\nGet.create<S>(\n  // required: a function that returns a class that will be \"fabricated\" every\n  // time `Get.find()` is called\n  // Example: Get.create<YourClass>(() => YourClass())\n  FcBuilderFunc<S> builder,\n\n  // optional: just like Get.put(), but it is used when you need multiple instances\n  // of a of a same class\n  // Useful in case you have a list that each item need it's own controller\n  // needs to be a unique string. Just change from tag to name\n  String name,\n\n  // optional: just like int`Get.put()`, it is for when you need to keep the\n  // instance alive thoughout the entire app. The difference is in Get.create\n  // permanent is true by default\n  bool permanent = true\n```\n\n## Sử dụng các phương thức / class\n\nHãy tưởng tượng rằng bạn đã điều hướng qua nhiều route và bạn cần một dữ liệu còn sót trong controller của mình, bạn sẽ cần một trình quản lý state kết hợp với Provider hoặc Get_it, phải hem? Với Get, bạn chỉ cần yêu cầu Get to \"find\" cho controller của mình và thế là xong:\n\n```dart\nfinal controller = Get.find<Controller>();\n// OR\nController controller = Get.find();\n\n// Yes, it looks like Magic, Get will find your controller, and will deliver it to you.\n// You can have 1 million controllers instantiated, Get will always give you the right controller.\n```\n\nVà sau đó, bạn sẽ có thể khôi phục dữ liệu controller của mình đã lấy được ở đó:\n\n```dart\nText(controller.textFromApi);\n```\n\nVì giá trị trả về là một class bình thường, bạn có thể làm bất cứ điều gì bạn muốn:\n```dart\nint count = Get.find<SharedPreferences>().getInt('counter');\nprint(count); // out: 12345\n```\n\nĐể xóa một controller đang chạy ngầm của Get:\n\n```dart\nGet.delete<Controller>(); //thường thì Get tự xóa, bạn không cần phải đặt lệnh này.\n```\n\n## Khác nhau giữa phương thức (methods)\n\nĐầu tiên, hãy nói về `fenix` của Get.lazyPut và `permanent`của các phương thức khác.\n\nSự khác biệt cơ bản giữa `permanent` và `fenix` là cách bạn muốn lưu trữ các cá thể của mình.\n\nCủng cố: theo mặc định, GetX xóa các trường hợp khi chúng không được sử dụng.\nCó nghĩa là: Nếu màn hình 1 có controller 1 và màn hình 2 có controller 2 và bạn xóa route đầu tiên khỏi stack, (chẳng hạn như nếu bạn sử dụng `` Get.off () 'hoặc' `Get.offNamed()``) thì controller 1 bị mất việc sử dụng nó vì vậy nó sẽ bị xóa.\n\nNhưng nếu bạn muốn chọn sử dụng `permanent: true`, thì controller sẽ không bị mất trong quá trình chuyển đổi này - điều này rất hữu ích cho các dịch vụ mà bạn muốn duy trì hoạt động trong toàn bộ ứng dụng.\n\nMặt khác, `fenix` dành cho các dịch vụ mà bạn không lo bị mất giữa các lần thay đổi màn hình, nhưng khi bạn cần dịch vụ đó, bạn hy vọng rằng nó vẫn tồn tại. Vì vậy, về cơ bản, nó sẽ loại bỏ controller / service / class không sử dụng, nhưng khi bạn cần, nó sẽ \"tạo lại từ đống tro tàn\" ở một trường hợp (instance) mới.\n\nTiếp tục với sự khác biệt giữa các phương pháp:\n\n- Get.put và Get.putAsync tuân theo cùng một thứ tự tạo, với sự khác biệt là một cái sử dụng phương thức không đồng bộ: hai phương thức đó đều tạo và khởi tạo các trường hợp. Cái sử dụng không đồng bộ được chèn trực tiếp vào bộ nhớ, bằng cách sử dụng phương thức nội bộ `insert` với các tham số `permanent: false` và` isSingleton: true` (tham số isSingleton này chỉ nhằm mục đích cho biết liệu nó có sử dụng dependency vào `dependency` hay không hoặc nếu nó được sử dụng dependency vào `FcBuilderFunc`). Sau đó, `Get.find ()` được gọi để khởi tạo ngay lập tức các các trường hợp trên bộ nhớ.\n\n- Get.create: Như tên của nó, nó sẽ \"tạo ra\" sự dependency cho bạn! Tương tự như `Get.put ()`, nó cũng gọi phương thức nội bộ là `insert` để các trường hợp. Nhưng `permanent` trở thành true và` isSingleton` trở thành false (vì chúng ta đang \"tạo\" dependency của mình, không có cách nào để nó là một instace singleton, đó là lý do tại sao lại là false). Và bởi vì nó có `permanent: true`, chúng tôi mặc định có lợi ích là không bị mất nó giữa các màn hình! Ngoài ra, `` Get.find () 'không được gọi ngay lập tức, nó phải chờ được sử dụng trong màn hình để được gọi. Nó được tạo ra theo cách này để sử dụng tham số `permanent ', vì vậy, đáng chú ý là` Get.create () `được tạo ra với mục tiêu tạo ra các phiên bản không được chia sẻ, nhưng không bị loại bỏ, như ví dụ: trong listView, mà bạn muốn có một phiên bản duy nhất cho danh sách đó - do đó, Get.create phải được sử dụng cùng với GetWidget.\n\n- Get.lazyPut: Như tên của nó, nó là một quy trình lười biếng. Cá thể được tạo, nhưng nó không được gọi để sử dụng ngay lập tức, nó vẫn đang chờ được gọi. Trái ngược với các phương thức khác, `insert` không được gọi ở đây. Thay vào đó, cá thể được chèn vào một phần khác của bộ nhớ, một phần chịu trách nhiệm cho biết liệu cá thể đó có thể được tạo lại hay không, chúng ta hãy gọi nó là \"nhà máy\". Nếu chúng ta muốn tạo ra thứ gì đó để sử dụng sau này, nó sẽ không bị trộn lẫn với những thứ đã được sử dụng ngay bây giờ. Và đây là nơi phép thuật của `fenix` đi vào: nếu bạn chọn bỏ` fenix: false`, và `smartManagement` của bạn không phải là` keepFactory`, thì khi sử dụng `Get.find`, instance sẽ thay đổi vị trí trong bộ nhớ từ \"nhà máy\" đến vùng bộ nhớ cá thể chung. Ngay sau đó, theo mặc định, nó được xóa khỏi \"nhà máy\". Bây giờ, nếu bạn chọn `fenix: true`, cá thể vẫn tiếp tục tồn tại trong phần dành riêng này, thậm chí sẽ chuyển sang vùng chung, sẽ được gọi lại trong tương lai.\n\n## Bindings\n\nCó lẽ, một trong những điểm khác biệt lớn của gói này là khả năng tích hợp đầy đủ các route, trình quản lý state và trình quản lý dependency.\nKhi một route bị xóa khỏi stack, tất cả các controller, biến và phiên bản của các đối tượng liên quan đến nó sẽ bị xóa khỏi bộ nhớ. Nếu bạn đang sử dụng luồng hoặc bộ hẹn giờ, chúng sẽ tự động bị đóng và bạn không phải lo lắng về bất kỳ điều gì trong số đó.\nTrong phiên bản 2.10 Được triển khai hoàn toàn API bindings.\nBây giờ bạn không cần sử dụng phương thức init nữa. Bạn thậm chí không cần phải nhập controller của mình nếu bạn không muốn. Bạn có thể khởi động controller và dịch vụ của mình ở nơi thích hợp cho việc đó.\nLớp Binding là một class sẽ tách riêng việc tiêm dependency, trong khi \"bindings\" các route đường tới trình quản lý state và trình quản lý dependency.\nĐiều này cho phép Nhận biết màn hình nào đang được hiển thị khi một controller cụ thể được sử dụng và biết vị trí và cách vứt bỏ nó.\nNgoài ra, class Binding sẽ cho phép bạn kiểm soát cấu hình SmartManager. Bạn có thể định cấu hình các phần dependency được sắp xếp khi xóa một route khỏi ngăn xếp hoặc khi widget con đã sử dụng nó được bố trí hoặc không. Bạn sẽ có quản lý dependency thông minh làm việc cho bạn, nhưng ngay cả như vậy, bạn có thể định cấu hình nó theo ý muốn.\n\n### Bindings class\n\n- Tạo một class và implements Binding\n\n```dart\nclass HomeBinding implements Bindings {}\n```\n\nIDE của bạn sẽ tự động yêu cầu bạn ghi đè phương thức \"dependency\" và bạn chỉ cần nhấp vào đèn, ghi đè phương thức và chèn tất cả các class bạn sẽ sử dụng trên route đó:\n\n```dart\nclass HomeBinding implements Bindings {\n  @override\n  void dependencies() {\n    Get.lazyPut<HomeController>(() => HomeController());\n    Get.put<Service>(()=> Api());\n  }\n}\n\nclass DetailsBinding implements Bindings {\n  @override\n  void dependencies() {\n    Get.lazyPut<DetailsController>(() => DetailsController());\n  }\n}\n```\n\nBây giờ bạn chỉ cần thông báo route của mình, rằng bạn sẽ sử dụng bindings đó để tạo kết nối giữa trình quản lý route, các dependency và state.\n\n- Sử dụng routes có tên:\n\n```dart\ngetPages: [\n  GetPage(\n    name: '/',\n    page: () => HomeView(),\n    binding: HomeBinding(),\n  ),\n  GetPage(\n    name: '/details',\n    page: () => DetailsView(),\n    binding: DetailsBinding(),\n  ),\n];\n```\n\n- Sử dụng routes thường:\n\n```dart\nGet.to(Home(), binding: HomeBinding());\nGet.to(DetailsView(), binding: DetailsBinding())\n```\n\nỞ đó, bạn không phải lo lắng về việc quản lý bộ nhớ của ứng dụng của mình nữa, Get sẽ thay bạn làm điều đó.\n\nLớp Binding được gọi khi một route được gọi, bạn có thể tạo một \"InitialBinding trong GetMaterialApp của mình để chèn tất cả các dependency sẽ được tạo.\n\n```dart\nGetMaterialApp(\n  initialBinding: SampleBind(),\n  home: Home(),\n);\n```\n\n### BindingsBuilder\n\nCách mặc định để tạo bindings là tạo một class thực hiện các bindings.\nNhưng cách khác, bạn có thể sử dụng lệnh gọi lại `BindingsBuilder` để bạn có thể chỉ cần sử dụng một hàm để khởi tạo bất cứ thứ gì bạn muốn.\n\nExample:\n\n```dart\ngetPages: [\n  GetPage(\n    name: '/',\n    page: () => HomeView(),\n    binding: BindingsBuilder(() {\n      Get.lazyPut<ControllerX>(() => ControllerX());\n      Get.put<Service>(()=> Api());\n    }),\n  ),\n  GetPage(\n    name: '/details',\n    page: () => DetailsView(),\n    binding: BindingsBuilder(() {\n      Get.lazyPut<DetailsController>(() => DetailsController());\n    }),\n  ),\n];\n```\n\nBằng cách đó, bạn có thể tránh tạo một class Binding cho mỗi routes, làm cho việc này trở nên đơn giản hơn.\n\nCả hai cách làm việc đều hoàn toàn tốt và chúng tôi muốn bạn sử dụng những gì phù hợp với sở thích của bạn nhất.\n\n### SmartManagement\n\nGetX theo mặc định loại bỏ controller không sử dụng khỏi bộ nhớ, ngay cả khi xảy ra lỗi và widget con sử dụng nó không được xử lý đúng cách.\nĐây được gọi là chế độ quản lý dependency `` đầy đủ`.\nNhưng nếu bạn muốn thay đổi cách GetX kiểm soát việc xử lý các class, bạn có class `SmartManagement` để bạn có thể thiết lập các hành vi khác nhau.\n\n#### Cách thay đổi\n\nNếu bạn muốn thay đổi cấu hình này (mà bạn thường không cần) thì đây là cách:\n\n```dart\nvoid main () {\n  runApp(\n    GetMaterialApp(\n      smartManagement: SmartManagement.onlyBuilders //here\n      home: Home(),\n    )\n  )\n}\n```\n\n#### SmartManagement.full\n\nNó là một trong những mặc định. Loại bỏ các class không được sử dụng và không được đặt thành vĩnh viễn. Trong phần lớn các trường hợp, bạn sẽ muốn giữ nguyên cấu hình này. Nếu bạn mới sử dụng GetX thì đừng thay đổi điều này.\n\n#### SmartManagement.onlyBuilders\nVới tùy chọn này, chỉ những controller bắt đầu trong `init: 'hoặc được tải vào Binding với` `Get.lazyPut ()` mới được xử lý.\n\nNếu bạn sử dụng `Get.put () 'hoặc' Get.putAsync ()` hoặc bất kỳ cách tiếp cận nào khác, SmartManagement sẽ không có quyền loại trừ sự dependency này.\n\nVới hành vi mặc định, ngay cả các widget con được khởi tạo bằng \"Get.put\" sẽ bị xóa, không giống như SmartManagement.onlyBuilders.\n\n#### SmartManagement.keepFactory\n\nCũng giống như SmartManagement.full, nó sẽ loại bỏ các phần dependency của nó khi nó không được sử dụng nữa. Tuy nhiên, nó sẽ giữ nguyên chế độ factory của họ, có nghĩa là nó sẽ tạo lại phần dependency nếu bạn cần lại phiên bản đó.\n\n### Cách bindings làm việc ngầm\nCác liên kết tạo ra các factory tạm thời, được tạo ra ngay khi bạn nhấp để chuyển sang màn hình khác và sẽ bị phá hủy ngay sau khi hoạt ảnh thay đổi màn hình xảy ra.\nĐiều này xảy ra quá nhanh đến nỗi máy phân tích thậm chí sẽ không thể đăng ký nó.\nKhi bạn điều hướng đến màn hình này một lần nữa, một factory tạm thời mới sẽ được gọi, vì vậy điều này thích hợp hơn khi sử dụng SmartManagement.keepFactory, nhưng nếu bạn không muốn tạo Bindings hoặc muốn giữ tất cả các dependency của mình trên cùng một Binding, thì chắc chắn sẽ giúp ích cho bạn.\nCác factory chiếm ít bộ nhớ, chúng không chứa các cá thể mà là một chức năng có \"hình dạng\" của class đó mà bạn muốn.\nĐiều này có chi phí bộ nhớ rất thấp, nhưng vì mục đích của lib này là để đạt được hiệu suất tối đa có thể bằng cách sử dụng tài nguyên tối thiểu, Get xóa ngay cả các factory theo mặc định.\nSử dụng cái nào thuận tiện nhất cho bạn.\n\n## Chí ú\n\n- KHÔNG SỬ DỤNG SmartManagement.keepFactory nếu bạn đang sử dụng nhiều Binding. Nó được thiết kế để sử dụng mà không có Bindings, hoặc với một Bindings duy nhất được liên kết trong `initialBinding` của GetMaterialApp.\n\n- Việc sử dụng Bindings là hoàn toàn tùy chọn, nếu muốn, bạn có thể sử dụng `Get.put () 'và' Get.find()` trên các class sử dụng controller nhất định mà không gặp bất kỳ vấn đề gì.\nTuy nhiên, nếu bạn làm việc với Service hoặc bất kỳ abstract nào khác, tôi khuyên bạn nên sử dụng Bindings để tổ chức tốt hơn.\n"
  },
  {
    "path": "documentation/vi_VI/route_management.md",
    "content": "- [Quản lý route](#route-management)\n  - [Hướng dẫn sử dụng trước khi dùng](#how-to-use)\n  - [Điều hướng không cần tên](#navigation-without-named-routes)\n  - [Điều hướng cần tên](#navigation-with-named-routes)\n    - [Gửi data cho route có tên](#send-data-to-named-routes)\n    - [Dynamic urls links](#dynamic-urls-links)\n    - [Middleware](#middleware)\n  - [Điều hướng không cần context](#navigation-without-context)\n    - [SnackBars](#snackbars)\n    - [Dialogs](#dialogs)\n    - [BottomSheets](#bottomsheets)\n  - [Điều hướng lồng (Nested Navigation)](#nested-navigation)\n\n# Quản lý route\n\nĐây là lời giải thích đầy đủ về tất cả những gì có cho Getx khi vấn đề là quản lý routes.\n\n## Hướng dẫn sử dụng trước khi dùng\n\nThêm cái này vào file pubspec.yaml của bạn:\n\n```yaml\ndependencies:\n  get:\n```\n\nNếu bạn định sử dụng các routes / snackbars / dialogs / bottomsheets mà không có \"context\" hoặc sử dụng các API cấp cao, bạn chỉ cần thêm Get trước MaterialApp của mình, biến nó thành GetMaterialApp và tung hành!\n\n```dart\nGetMaterialApp( // Before: MaterialApp(\n  home: MyHome(),\n)\n```\n\n## Điều hướng không cần tên\n\nĐể điều hướng đến một màn hình mới:\n\n```dart\nGet.to(NextScreen());\n```\n\nĐể đóng snackbars, dialog, bottomsheets hoặc bất cứ thứ gì bạn thường đóng bằng Navigator.pop (context);\n\n```dart\nGet.back();\n```\n\nĐể chuyển đến màn hình tiếp theo và không có tùy chọn nào để quay lại màn hình trước đó (để sử dụng trong SplashScreens, màn hình đăng nhập, v.v.)\n\n```dart\nGet.off(NextScreen());\n```\n\nĐể chuyển đến màn hình tiếp theo và hủy tất cả các lộ trình trước đó (hữu ích trong giỏ hàng, polls và test)\n\n```dart\nGet.offAll(NextScreen());\n```\n\nĐể điều hướng đến routes tiếp theo và nhận hoặc cập nhật dữ liệu ngay sau khi bạn trở về từ routes đó:\n\n```dart\nvar data = await Get.to(Payment());\n```\n\ntrên màn hình khác, gửi dữ liệu cho routes trước đó:\n\n```dart\nGet.back(result: 'success');\n```\n\nAnd use it:\n\nex:\n\n```dart\nif(data == 'success') madeAnything();\n```\n\nBạn không muốn học cú pháp của chúng tôi?\nChỉ cần thay đổi Navigator (chữ in hoa) thành navigator (chữ thường) và bạn sẽ có tất cả các chức năng của điều hướng tiêu chuẩn mà không cần phải sử dụng \"context\"\nThí dụ:\n\n```dart\n\n// Default Flutter navigator\nNavigator.of(context).push(\n  context,\n  MaterialPageRoute(\n    builder: (BuildContext context) {\n      return HomePage();\n    },\n  ),\n);\n\n// Get using Flutter syntax without needing context\nnavigator.push(\n  MaterialPageRoute(\n    builder: (_) {\n      return HomePage();\n    },\n  ),\n);\n\n// Get syntax (It is much better, but you have the right to disagree)\nGet.to(HomePage());\n\n\n```\n\n## Điều hướng cần tên\n\n- Nếu bạn thích điều hướng bằng tên, Get cũng hỗ trợ điều này.\n\nTo navigate to nextScreen\n\n```dart\nGet.toNamed(\"/NextScreen\");\n```\n\nĐể điều hướng và xóa màn hình trước đó khỏi cây widget.\n\n```dart\nGet.offNamed(\"/NextScreen\");\n```\n\nĐể điều hướng và xóa tất cả các màn hình trước đó khỏi cây widget.\n\n```dart\nGet.offAllNamed(\"/NextScreen\");\n```\n\nĐể định dạng routes, sử dụng GetMaterialApp:\n\n```dart\nvoid main() {\n  runApp(\n    GetMaterialApp(\n      initialRoute: '/',\n      getPages: [\n        GetPage(name: '/', page: () => MyHomePage()),\n        GetPage(name: '/second', page: () => Second()),\n        GetPage(\n          name: '/third',\n          page: () => Third(),\n          transition: Transition.zoom  \n        ),\n      ],\n    )\n  );\n}\n```\n\nĐể xử lý điều hướng đến các routes không được xác định (lỗi 404), bạn có thể xác định trang 'không xác định' trong GetMaterialApp.\n\n```dart\nvoid main() {\n  runApp(\n    GetMaterialApp(\n      unknownRoute: GetPage(name: '/notfound', page: () => UnknownRoutePage()),\n      initialRoute: '/',\n      getPages: [\n        GetPage(name: '/', page: () => MyHomePage()),\n        GetPage(name: '/second', page: () => Second()),\n      ],\n    )\n  );\n}\n```\n\n### Gửi data cho route có tên\n\nChỉ cần gửi những gì bạn muốn cho các đối số (arguments). Get chấp nhận bất kỳ thứ gì ở đây, cho dù đó là String, Map, List hay thậm chí là một class trường hợp.\n\n```dart\nGet.toNamed(\"/NextScreen\", arguments: 'Get is the best');\n```\n\nTrong class controller của bạn:\n\n```dart\nprint(Get.arguments);\n//print out: Get is the best\n```\n\n### Dynamic urls links\n\nGet hỗ trợ các url động nâng cao giống như trên Web. Các nhà phát triển web có lẽ đã muốn tính năng này trên Flutter và rất có thể đã thấy một gói hứa hẹn tính năng này và cung cấp một cú pháp hoàn toàn khác so với một URL sẽ có trên web, và Get cũng giải quyết được điều này.\n\n```dart\nGet.offAllNamed(\"/NextScreen?device=phone&id=354&name=Enzo\");\n```\n\ntrong controller/bloc/stateful/stateless của class:\n\n```dart\nprint(Get.parameters['id']);\n// out: 354\nprint(Get.parameters['name']);\n// out: Enzo\n```\n\nBạn có thể đặt NamedParameters với Get dễ dàng:\n\n```dart\nvoid main() {\n  runApp(\n    GetMaterialApp(\n      initialRoute: '/',\n      getPages: [\n      GetPage(\n        name: '/',\n        page: () => MyHomePage(),\n      ),\n      GetPage(\n        name: '/profile/',\n        page: () => MyProfile(),\n      ),\n       //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.\n       GetPage(\n        name: '/profile/:user',\n        page: () => UserProfile(),\n      ),\n      GetPage(\n        name: '/third',\n        page: () => Third(),\n        transition: Transition.cupertino  \n      ),\n     ],\n    )\n  );\n}\n```\n\nGửi data bằng tên\n\n```dart\nGet.toNamed(\"/profile/34954\");\n```\n\nTrên màn hình thứ hai, lấy dữ liệu theo tham số (parameters)\n\n```dart\nprint(Get.parameters['user']);\n// out: 34954\n```\n\nhoặc gửi nhiều tham số như thế này\n\n```dart\nGet.toNamed(\"/profile/34954?flag=true&country=italy\");\n```\nor\n```dart\nvar parameters = <String, String>{\"flag\": \"true\",\"country\": \"italy\",};\nGet.toNamed(\"/profile/34954\", parameters: parameters);\n```\n\nTrên màn hình thứ hai, lấy dữ liệu theo các tham số như thường lệ\n\n```dart\nprint(Get.parameters['user']);\nprint(Get.parameters['flag']);\nprint(Get.parameters['country']);\n// out: 34954 true italy\n```\n\n\n\nVà bây giờ, tất cả những gì bạn cần làm là sử dụng Get.toNamed () để điều hướng các routes đã đặt tên của bạn mà không cần bất kỳ \"context\" nào (bạn có thể gọi các routes của mình trực tiếp từ BLoC hoặc lớp Bộ điều khiển) và khi ứng dụng của bạn được biên dịch lên web, các routes sẽ xuất hiện trong url <3\n\n### Middleware\n\nNếu bạn muốn nghe Get events để kích hoạt các hành động, bạn có thể sử dụng routingCallback cho nó\n\n```dart\nGetMaterialApp(\n  routingCallback: (routing) {\n    if(routing.current == '/second'){\n      openAds();\n    }\n  }\n)\n```\n\nNếu bạn không sử dụng GetMaterialApp, bạn có thể sử dụng API thủ công để đính kèm trình quan sát Middleware.\n\n```dart\nvoid main() {\n  runApp(\n    MaterialApp(\n      onGenerateRoute: Router.generateRoute,\n      initialRoute: \"/\",\n      navigatorKey: Get.key,\n      navigatorObservers: [\n        GetObserver(MiddleWare.observer), // HERE !!!\n      ],\n    ),\n  );\n}\n```\n\nTạo một MiddleWare class\n\n```dart\nclass MiddleWare {\n  static observer(Routing routing) {\n    /// You can listen in addition to the routes, the snackbars, dialogs and bottomsheets on each screen.\n    ///If you need to enter any of these 3 events directly here,\n    ///you must specify that the event is != Than you are trying to do.\n    if (routing.current == '/second' && !routing.isSnackbar) {\n      Get.snackbar(\"Hi\", \"You are on second route\");\n    } else if (routing.current =='/third'){\n      print('last route called');\n    }\n  }\n}\n```\n\nBây giờ, hãy sử dụng Get trên code của bạn:\n\n```dart\nclass First extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        leading: IconButton(\n          icon: Icon(Icons.add),\n          onPressed: () {\n            Get.snackbar(\"hi\", \"i am a modern snackbar\");\n          },\n        ),\n        title: Text('First Route'),\n      ),\n      body: Center(\n        child: ElevatedButton(\n          child: Text('Open route'),\n          onPressed: () {\n            Get.toNamed(\"/second\");\n          },\n        ),\n      ),\n    );\n  }\n}\n\nclass Second extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        leading: IconButton(\n          icon: Icon(Icons.add),\n          onPressed: () {\n            Get.snackbar(\"hi\", \"i am a modern snackbar\");\n          },\n        ),\n        title: Text('second Route'),\n      ),\n      body: Center(\n        child: ElevatedButton(\n          child: Text('Open route'),\n          onPressed: () {\n            Get.toNamed(\"/third\");\n          },\n        ),\n      ),\n    );\n  }\n}\n\nclass Third extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: Text(\"Third Route\"),\n      ),\n      body: Center(\n        child: ElevatedButton(\n          onPressed: () {\n            Get.back();\n          },\n          child: Text('Go back!'),\n        ),\n      ),\n    );\n  }\n}\n```\n\n## Điều hướng không cần context\n\n### SnackBars\n\nĐể có một SnackBar đơn giản với Flutter, bạn phải lấy context của Scaffold, hoặc bạn phải sử dụng GlobalKey được gắn vào Scaffold của bạn\n\n```dart\nfinal snackBar = SnackBar(\n  content: Text('Hi!'),\n  action: SnackBarAction(\n    label: 'I am a old and ugly snackbar :(',\n    onPressed: (){}\n  ),\n);\n// Find the Scaffold in the widget tree and use\n// it to show a SnackBar.\nScaffold.of(context).showSnackBar(snackBar);\n```\n\nWith Get:\n\n```dart\nGet.snackbar('Hi', 'i am a modern snackbar');\n```\n\nVới Get, tất cả những gì bạn phải làm là gọi thanh Get.snackbar từ bất kỳ đâu trong code của bạn hoặc tùy chỉnh nó theo cách bạn muốn!\n\n```dart\nGet.snackbar(\n  \"Hey i'm a Get SnackBar!\", // title\n  \"It's unbelievable! I'm using SnackBar without context, without boilerplate, without Scaffold, it is something truly amazing!\", // message\n  icon: Icon(Icons.alarm),\n  shouldIconPulse: true,\n  onTap:(){},\n  barBlur: 20,\n  isDismissible: true,\n  duration: Duration(seconds: 3),\n);\n\n\n  ////////// ALL FEATURES //////////\n  //     Color colorText,\n  //     Duration duration,\n  //     SnackPosition snackPosition,\n  //     Widget titleText,\n  //     Widget messageText,\n  //     bool instantInit,\n  //     Widget icon,\n  //     bool shouldIconPulse,\n  //     double maxWidth,\n  //     EdgeInsets margin,\n  //     EdgeInsets padding,\n  //     double borderRadius,\n  //     Color borderColor,\n  //     double borderWidth,\n  //     Color backgroundColor,\n  //     Color leftBarIndicatorColor,\n  //     List<BoxShadow> boxShadows,\n  //     Gradient backgroundGradient,\n  //     TextButton mainButton,\n  //     OnTap onTap,\n  //     bool isDismissible,\n  //     bool showProgressIndicator,\n  //     AnimationController progressIndicatorController,\n  //     Color progressIndicatorBackgroundColor,\n  //     Animation<Color> progressIndicatorValueColor,\n  //     SnackStyle snackStyle,\n  //     Curve forwardAnimationCurve,\n  //     Curve reverseAnimationCurve,\n  //     Duration animationDuration,\n  //     double barBlur,\n  //     double overlayBlur,\n  //     Color overlayColor,\n  //     Form userInputForm\n  ///////////////////////////////////\n```\n\nNếu bạn thích snackbar truyền thống hoặc muốn tùy chỉnh nó từ đầu, bao gồm chỉ thêm một dòng (Get.snackbar sử dụng tiêu đề và thông báo bắt buộc), bạn có thể sử dụng\n`Get.rawSnackbar ()`; 'cung cấp API RAW trên đó Get.\n\n### Dialogs\n\nTo open dialog:\n\n```dart\nGet.dialog(YourDialogWidget());\n```\n\nTo open default dialog:\n\n```dart\nGet.defaultDialog(\n  onConfirm: () => print(\"Ok\"),\n  middleText: \"Dialog made in 3 lines of code\"\n);\n```\n\nBạn cũng có thể sử dụng Get.generalDialog thay vì showGeneralDialog.\n\nĐối với tất cả các tiện ích hộp thoại Flutter khác, bao gồm cả cupertinos, bạn có thể sử dụng Get.overlayContext thay vì context và mở nó ở bất kỳ đâu trong mã của bạn.\nĐối với các widget không sử dụng Overlay, bạn có thể sử dụng Get.context.\nHai context này sẽ hoạt động trong 99% trường hợp để thay thế context của UI của bạn, ngoại trừ các trường hợp trong đó inheritWidget được sử dụng mà không có context điều hướng.\n\n### BottomSheets\n\nGet.bottomSheet giống như showModalBottomSheet, nhưng không cần context.\n\n```dart\nGet.bottomSheet(\n  Container(\n    child: Wrap(\n      children: <Widget>[\n        ListTile(\n          leading: Icon(Icons.music_note),\n          title: Text('Music'),\n          onTap: () {}\n        ),\n        ListTile(\n          leading: Icon(Icons.videocam),\n          title: Text('Video'),\n          onTap: () {},\n        ),\n      ],\n    ),\n  )\n);\n```\n\n## Điều hướng lồng (Nested Navigation)\n\nLàm cho điều hướng lồng (nested navigation) của Flutter thậm chí còn dễ dàng hơn.\nBạn không cần context và bạn sẽ tìm thấy stack điều hướng của mình theo Id.\n\n- CHÍ Ú: Việc tạo các stack điều hướng song song có thể gây nguy hiểm. Lý tưởng nhất là không sử dụng NestedNavigators, hoặc sử dụng một cách tối thiểu. Nếu dự án của bạn yêu cầu, hãy tiếp tục, nhưng hãy nhớ rằng việc giữ nhiều stack điều hướng trong bộ nhớ có thể không phải là một ý tưởng hay cho việc tiêu thụ RAM.\n\nXem nó code đơn giản nè:\n\n```dart\nNavigator(\n  key: Get.nestedKey(1), // create a key by index\n  initialRoute: '/',\n  onGenerateRoute: (settings) {\n    if (settings.name == '/') {\n      return GetPageRoute(\n        page: () => Scaffold(\n          appBar: AppBar(\n            title: Text(\"Main\"),\n          ),\n          body: Center(\n            child: TextButton(\n              color: Colors.blue,\n              onPressed: () {\n                Get.toNamed('/second', id:1); // navigate by your nested route by index\n              },\n              child: Text(\"Go to second\"),\n            ),\n          ),\n        ),\n      );\n    } else if (settings.name == '/second') {\n      return GetPageRoute(\n        page: () => Center(\n          child: Scaffold(\n            appBar: AppBar(\n              title: Text(\"Main\"),\n            ),\n            body: Center(\n              child:  Text(\"second\")\n            ),\n          ),\n        ),\n      );\n    }\n  }\n),\n```\n"
  },
  {
    "path": "documentation/vi_VI/state_management.md",
    "content": "* [Quản lý State](#state-management)\n  + [Quản lý Reactive State](#reactive-state-manager)\n    - [Lợi thế](#advantages)\n    - [Hiệu suất tối đa:](#maximum-performance)\n    - [Khai báo một biến phản ứng (reactive variable)](#declaring-a-reactive-variable)\n        - [Thât dễ khi có reactive state.](#having-a-reactive-state-is-easy)\n    - [Sử dụng values trong View](#using-the-values-in-the-view)\n    - [Điều kiện để tái tạo lại](#conditions-to-rebuild)\n    - [Nơi .obs có thể dùng](#where-obs-can-be-used)\n    - [Chí ú về Lists](#note-about-lists)\n    - [Tại sao tôi phải dùng .value](#why-i-have-to-use-value)\n    - [Obx()](#obx)\n    - [Workers](#workers)\n  + [Quản lý State đơn giản](#simple-state-manager)\n    - [Lợi thế](#advantages-1)\n    - [Sử dụng](#usage)\n    - [Cách GetX sử dụng controllers](#how-it-handles-controllers)\n    - [Không cần StatefulWidget nữa!](#you-wont-need-statefulwidgets-anymore)\n    - [Tại sao GetX tồn tại?](#why-it-exists)\n    - [Cách sử dụng khác](#other-ways-of-using-it)\n    - [IDs độc nhất](#unique-ids)\n  + [Trộn hai trình quản lý state](#mixing-the-two-state-managers)\n  + [GetBuilder vs GetX vs Obx vs MixinBuilder](#getbuilder-vs-getx-vs-obx-vs-mixinbuilder)\n\n# Quản lý State\n\nGetX không sử dụng Streams hoặc ChangeNotifier như các quản lý state khác. Tại sao? Ngoài việc xây dựng các ứng dụng cho android, iOS, web, linux, macos và linux, với GetX bạn có thể xây dựng các ứng dụng máy chủ với cú pháp tương tự như Flutter / GetX. Để cải thiện thời gian phản hồi và giảm mức tiêu thụ RAM, chúng tôi đã tạo GetValue và GetStream, là các giải pháp có độ trễ thấp mang lại nhiều hiệu suất với chi phí vận hành thấp. Chúng tôi sử dụng cơ sở này để xây dựng tất cả các nguồn lực của mình, bao gồm cả quản lý state.\n\n* _Phức hợp_: Một số quản lý state rất phức tạp và có rất nhiều cơ sở hạ tầng. Với GetX, bạn không phải xác định một class cho mỗi event, code rất rõ ràng và rõ ràng, và bạn làm được nhiều việc hơn bằng cách viết ít hơn. Nhiều người đã từ bỏ Flutter vì chủ đề này, và cuối cùng họ đã có một giải pháp đơn giản đến mức đần độn để quản lý các state.\n* _Không trình tạo mã_: Bạn dành một nửa thời gian phát triển để viết logic ứng dụng của mình. Một số quản lý state dựa vào trình tạo mã để có mã có thể đọc được ở mức tối thiểu. Việc thay đổi một biến và phải chạy build_runner có thể gây mất hiệu quả, chuyện này rất ngốn thời gian chờ đợi sau khi quét sạch sẽ rất lâu và bạn phải uống rất nhiều cà phê.\n\nVới GetX, mọi thứ đều hoạt động và độc lập với trình tạo mã, giúp tăng năng suất của bạn trong mọi khía cạnh phát triển của bạn.\n\n* _Không phụ thuộc vào context_: Có thể bạn đã cần gửi context của chế độ xem của mình tới controller, làm cho khả năng kết hợp của View với business logic của bạn cao hơn. Bạn có thể phải sử dụng một dependency cho một nơi không có context và phải chuyển context qua các class và hàm khác nhau. Điều này không tồn tại với GetX. Bạn có quyền truy cập vào controller của mình từ bên trong controller mà không cần bất kỳ context nào. Bạn không cần phải gửi context theo tham số vì không có gì theo nghĩa đen.\n* _Kiểm soát hạt_: Hầu hết các quản lý state đều dựa trên ChangeNotifier. ChangeNotifier sẽ thông báo cho tất cả các widget phụ thuộc vào nó khi thông báo cho các widget được gọi. Nếu bạn có 40 widget con trên một màn hình, trong đó có một biến thuộc class ChangeNotifier của bạn, khi bạn cập nhật một widget con, tất cả chúng sẽ được xây dựng lại.\n\nVới GetX, ngay cả các widget lồng nhau cũng được tôn trọng. Nếu bạn có Obx đang xem ListView của bạn và người khác đang xem hộp kiểm bên trong ListView, thì khi thay đổi giá trị CheckBox, chỉ nó mới được cập nhật, khi thay đổi giá trị List, chỉ ListView sẽ được cập nhật.\n\n* _Chỉ tái tạo lại nếu biến CẦN thay đổi_: GetX có tính năng kiểm soát streams, điều đó có nghĩa là nếu bạn hiển thị Text là 'Kaiser', nếu bạn thay đổi lại biến có thể quan sát thành 'Kaiser', widget sẽ không được tạo lại. Đó là bởi vì GetX biết rằng 'Kaiser' đã được hiển thị trong Văn bản và sẽ không thực hiện các thao tác tái tạo không cần thiết.\n\nHầu hết (nếu không phải tất cả) các trình quản lý state hiện tại sẽ xây dựng lại trên màn hình.\n\n## Quản lý Reactive State\n\nLập trình phản ứng (Reactive programming) có thể khiến nhiều người xa lánh vì nó được cho là phức tạp. GetX biến lập trình phản ứng thành một thứ khá đơn giản:\n\n* Bạn sẽ không cần tạo StreamControllers.\n* Bạn sẽ không cần tạo StreamBuilder cho mỗi biến\n* Bạn sẽ không cần phải tạo một class cho mỗi state.\n* Bạn sẽ không cần tạo get cho một giá trị ban đầu.\n\nLập trình phản ứng với Get dễ dàng như sử dụng setState.\n\nHãy tưởng tượng rằng bạn có một biến tên và muốn rằng mỗi khi bạn thay đổi nó, tất cả các widget sử dụng nó sẽ được tự động thay đổi.\n\nĐây là count variable của bạn:\n\n``` dart\nvar name = 'Khang Huỳnh';\n```\n\nĐể làm cho nó có thể quan sát được, bạn chỉ cần thêm \".obs\" vào cuối nó:\n\n``` dart\nvar name = 'Khang Huỳnh'.obs;\n```\n\nChỉ vậy thôi, chỉ *vậy thôi* người ơi~\n\nTừ bây giờ, chúng ta có thể tham chiếu đến các biến reactive - \". Obs\" (có thể thay thế) này là _Rx_.   \n\nChúng tôi đã làm gì phía dưới class code? Chúng tôi đã tạo một `Stream` của `String`, được gán giá trị ban đầu `\"Khang Huỳnh\"`, chúng tôi đã thông báo cho tất cả các widget con sử dụng `\"Khang Huỳnh\"` rằng chúng hiện \"thuộc về\" biến này và khi giá trị _Rx_ thay đổi, chúng phải thay đổi theo.\nĐây là **phép màu của GetX**, nhờ vào khả năng của Dart.\n\nTuy nhiên, như chúng ta đã biết, một `Widget` chỉ có thể được thay đổi nếu nó nằm bên trong một hàm, bởi vì các class tĩnh không có quyền\" tự động thay đổi \".\n\nBạn sẽ cần tạo một `StreamBuilder`, đăng ký biến này để lắng nghe các thay đổi và tạo một \"stream\" các` StreamBuilder` lồng nhau nếu bạn muốn thay đổi một số biến trong cùng một phạm vi, phải không?\n\nKhông, bạn không cần `StreamBuilder`, nhưng bạn đã đúng về các class tĩnh.\n\nTheo quan điểm, chúng ta thường có rất nhiều bảng soạn sẵn khi chúng ta muốn thay đổi một Widget cụ thể, đó là cách Flutter.\nVới ** GetX **, bạn cũng có thể quên mã soạn sẵn này.\n\n`StreamBuilder (…)`? `initialValue:…`? `builder:…`? Không, bạn chỉ cần đặt biến này bên trong Widget `Obx ()`.\n\n``` dart\nObx (() => Text (controller.name));\n```\n\n_Bạn cần nhớ gì?_  Chỉ `Obx(() =>` . \n\nBạn chỉ đang chuyển Widget đó thông qua một hàm mũi tên vào một `Obx ()` (\"Observer\" của _Rx_).\n\n`Obx` khá thông minh và sẽ chỉ thay đổi nếu giá trị của `controller.name` thay đổi.\n\nNếu `name` là` \"Kaiser\" `và bạn thay đổi nó thành` \"Kaiser\" `(` name.value = \"Kaiser\" `), vì nó giống như` giá trị` như trước, sẽ không có gì thay đổi trên màn hình, và `Obx`, để tiết kiệm tài nguyên, sẽ đơn giản bỏ qua giá trị mới và không xây dựng lại Widget. **Tuyệt vời ông mặt trời chứ?**\n\n> So, what if I have 5 _Rx_ (observable) variables within an `Obx` ?\n\nNó sẽ chỉ cập nhật khi ** bất kỳ ** nào trong số chúng thay đổi.\n\n> And if I have 30 variables in a class, when I update one, will it update **all** the variables that are in that class?\n\nKhông, chỉ **Widget cụ thể** sử dụng biến _Rx_ đó.\n\nVì vậy, **GetX** chỉ cập nhật màn hình, khi biến _Rx_ thay đổi giá trị của nó.\n\n``` \n\nfinal isOpen = false.obs;\n\n// NOTHING will happen... same value.\nvoid onButtonTap() => isOpen.value=false;\n```\n\n### Lợi thế\n\n**GetX()** giúp bạn khi bạn cần kiểm soát **chi tiết** đối với những gì đang được cập nhật.\n\nNếu bạn không cần `ID duy nhất`, vì tất cả các biến của bạn sẽ được sửa đổi khi bạn thực hiện một hành động, thì hãy sử dụng` GetBuilder`,\nbởi vì nó là một Trình cập nhật state đơn giản (trong các khối, như `setState ()` '), được tạo chỉ trong một vài dòng mã.\nNó được làm đơn giản, ít ảnh hưởng đến CPU nhất và chỉ để thực hiện một mục đích duy nhất (xây dựng lại _State_) và sử dụng tài nguyên tối thiểu có thể.\n\nNếu bạn cần một Trình quản lý state **mạnh mẽ**, bạn không thể làm sai với **GetX**.\n\nNó không hoạt động với các biến, nhưng __flows__, mọi thứ trong đó đều là `Streams`.\n\nBạn có thể sử dụng _rxDart_ kết hợp với nó, vì mọi thứ đều là `Luồng`,\nbạn có thể nghe `event` của từng\" biến _Rx_ \",\nbởi vì mọi thứ trong đó đều là `Streams`.\n\nNó thực sự là một cách tiếp cận _BLoC_, dễ dàng hơn _MobX_ và không có trình tạo code hoặc decorations.\nBạn có thể biến **mọi thứ** thành một _\"Observable\" _ chỉ với một `.obs`.\n\n### Hiệu suất tối đa:\n\nNgoài việc có một thuật toán thông minh để xây dựng lại tối thiểu, **GetX** sử dụng trình so sánh để đảm bảo rằng Bang đã thay đổi.\n\nNếu bạn gặp bất kỳ lỗi nào trong ứng dụng của mình và gửi một bản thay đổi state, **GetX** sẽ đảm bảo rằng nó sẽ không gặp sự cố.\n\nVới **GetX** State chỉ thay đổi nếu `giá trị` thay đổi.\nĐó là sự khác biệt chính giữa **GetX** và việc sử dụng _ `computed` từ MobX_.\nKhi kết hợp hai __observables__, và một thay đổi; trình nghe của _observable_ đó cũng sẽ thay đổi.\n\nVới **GetX**, nếu bạn nối hai biến, `GetX ()` (tương tự như `Observer ()`) sẽ chỉ xây dựng lại nếu nó ngụ ý thay đổi state thực sự.\n\n### Khai báo một biến phản ứng (reactive variable)\n\nBạn có 3 cách để thay đổi variable thành \"observable\".\n\n1 - Sử dụng **`Rx{Type}`**.\n\n``` dart\n// initial value is recommended, but not mandatory\nfinal name = RxString('');\nfinal isLogged = RxBool(false);\nfinal count = RxInt(0);\nfinal balance = RxDouble(0.0);\nfinal items = RxList<String>([]);\nfinal myMap = RxMap<String, int>({});\n```\n\n2 - Sử dụng **`Rx`** và dùng Darts Generics, `Rx<Type>`\n\n``` dart\nfinal name = Rx<String>('');\nfinal isLogged = Rx<Bool>(false);\nfinal count = Rx<Int>(0);\nfinal balance = Rx<Double>(0.0);\nfinal number = Rx<Num>(0);\nfinal items = Rx<List<String>>([]);\nfinal myMap = Rx<Map<String, int>>({});\n\n// Custom classes - it can be any class, literally\nfinal user = Rx<User>();\n```\n\n3 - Cách tối ưu nhất, thêm **`.obs`** ở `value` :\n\n``` dart\nfinal name = ''.obs;\nfinal isLogged = false.obs;\nfinal count = 0.obs;\nfinal balance = 0.0.obs;\nfinal number = 0.obs;\nfinal items = <String>[].obs;\nfinal myMap = <String, int>{}.obs;\n\n// Custom classes - it can be any class, literally\nfinal user = User().obs;\n```\n\n##### Thât dễ khi có reactive state.\n\nNhư chúng ta biết, _Dart_ đang hướng tới _null safety_.\nĐể chuẩn bị, từ bây giờ, bạn phải luôn bắt đầu các biến _Rx_ của mình bằng một **initial value**.\n\n> Transforming a variable into an _observable_ + _initial value_ with **GetX** is the simplest, and most practical approach.\n\nTheo đúng nghĩa đen, bạn sẽ thêm một \"` .obs` \"vào cuối biến của mình và **vậy thôi người ơi~**, bạn đã làm cho nó có thể quan sát được, và `.value` của nó sẽ là _initial value_).\n\n### Sử dụng values trong View\n\n``` dart\n// controller file\nfinal count1 = 0.obs;\nfinal count2 = 0.obs;\nint get sum => count1.value + count2.value;\n```\n\n``` dart\n// view file\nGetX<Controller>(\n  builder: (controller) {\n    print(\"count 1 rebuild\");\n    return Text('${controller.count1.value}');\n  },\n),\nGetX<Controller>(\n  builder: (controller) {\n    print(\"count 2 rebuild\");\n    return Text('${controller.count2.value}');\n  },\n),\nGetX<Controller>(\n  builder: (controller) {\n    print(\"count 3 rebuild\");\n    return Text('${controller.sum}');\n  },\n),\n```\n\nNếu chúng ta cộng `count1.value++` , nó sẽ in:\n\n* `count 1 rebuild`\n\n* `count 3 rebuild`\n\nbởi vì `count1` có giá trị là` 1` và `1 + 0 = 1`, thay đổi giá trị getter` sum`.\n\nNếu ta thay đổi `count2.value++` , nó sẽ in:\n\n* `count 2 rebuild`\n\n* `count 3 rebuild`\n\nbởi vì `count2.value` đã thay đổi, và kết quả của` sum` bây giờ là `2`.\n\n* LƯU Ý: Theo mặc định, event đầu tiên sẽ xây dựng lại widget con, ngay cả khi nó là cùng một `giá trị`.\n\nHành vi này tồn tại do các biến Boolean.\n\nVí dụ, bạn code thế này:\n\n``` dart\nvar isLogged = false.obs;\n```\n\nVà sau đó, bạn đã kiểm tra xem người dùng có \"đăng nhập\" để kích hoạt event trong `ever` không.\n\n``` dart\n@override\nonInit(){\n  ever(isLogged, fireRoute);\n  isLogged.value = await Preferences.hasToken();\n}\n\nfireRoute(logged) {\n  if (logged) {\n   Get.off(Home());\n  } else {\n   Get.off(Login());\n  }\n}\n```\n\nnếu `hasToken` là` false`, sẽ không có thay đổi thành `isLogged`, vì vậy `ever ()` sẽ không bao giờ được gọi.\nĐể tránh loại hành vi này, thay đổi đầu tiên đối với _observable_ sẽ luôn kích hoạt một event,\nngay cả khi nó chứa cùng một `.value`.\n\nBạn có thể xóa hành vi này nếu muốn, bằng cách sử dụng:\n `isLogged.firstRebuild = false;`\n\n### Điều kiện để tái tạo lại\n\nNgoài ra, Get cung cấp khả năng kiểm soát state đã được tinh chỉnh. Bạn có thể điều kiện một event (chẳng hạn như thêm một đối tượng vào danh sách), với một điều kiện nhất định.\n\n``` dart\n// First parameter: condition, must return true or false.\n// Second parameter: the new value to apply if the condition is true.\nlist.addIf(item < limit, item);\n```\n\nKhông có decoration, không có trình tạo mã, không có phức tạp hóa vấn đề: smile:\n\nBạn có biết ứng dụng counter của Flutter không? Class controller của bạn có thể trông giống như sau:\n\n``` dart\nclass CountController extends GetxController {\n  final count = 0.obs;\n}\n```\n\nĐơn giản hơn:\n\n``` dart\ncontroller.count.value++\n```\n\nBạn có thể cập nhật counter trong UI của mình, bất kể nó được lưu trữ ở đâu.\n\n### Nơi .obs có thể dùng\n\nBạn có thể biến đổi bất cứ thứ gì trên obs. Đây là hai cách để làm điều đó:\n\n* Bạn có thể chuyển đổi các giá trị class của mình thành obs\n\n``` dart\nclass RxUser {\n  final name = \"Camila\".obs;\n  final age = 18.obs;\n}\n```\n\n* hoặc bạn có thể biến cả 1 class thành observable\n\n``` dart\nclass User {\n  User({String name, int age});\n  var name;\n  var age;\n}\n\n// when instantianting:\nfinal user = User(name: \"Camila\", age: 18).obs;\n```\n\n### Chí ú về Lists\n\nList hoàn toàn có thể quan sát được cũng như các đối tượng bên trong nó. Bằng cách đó, nếu bạn thêm một giá trị vào danh sách, nó sẽ tự động xây dựng lại các widget con sử dụng nó.\n\nBạn cũng không cần phải sử dụng \".value\" với các danh sách, api phi tiêu tuyệt vời đã cho phép chúng tôi loại bỏ điều đó.\nTiếc thay, các kiểu nguyên thủy như String và int không thể được mở rộng, khiến việc sử dụng .value là bắt buộc, nhưng điều đó sẽ không thành vấn đề nếu bạn làm việc với getters và setters cho những thứ này.\n\n``` dart\n// On the controller\nfinal String title = 'User Info:'.obs\nfinal list = List<User>().obs;\n\n// on the view\nText(controller.title.value), // String need to have .value in front of it\nListView.builder (\n  itemCount: controller.list.length // lists don't need it\n)\n```\n\nKhi bạn đang làm cho các class của riêng mình có thể quan sát được, có một cách khác để cập nhật chúng:\n\n``` dart\n// on the model file\n// we are going to make the entire class observable instead of each attribute\nclass User() {\n  User({this.name = '', this.age = 0});\n  String name;\n  int age;\n}\n\n// on the controller file\nfinal user = User().obs;\n// when you need to update the user variable:\nuser.update( (user) { // this parameter is the class itself that you want to update\nuser.name = 'Jonny';\nuser.age = 18;\n});\n// an alternative way of update the user variable:\nuser(User(name: 'João', age: 35));\n\n// on view:\nObx(()=> Text(\"Name ${user.value.name}: Age: ${user.value.age}\"))\n// you can also access the model values without the .value:\nuser().name; // notice that is the user variable, not the class (variable has lowercase u)\n```\n\nBạn không cần phải làm việc với các bộ nếu bạn không muốn. bạn có thể sử dụng api \"assign\" và \"assignAll\".\nApi \"assign\" sẽ xóa danh sách của bạn và thêm một đối tượng duy nhất mà bạn muốn bắt đầu ở đó.\nApi \"allowAll\" sẽ xóa danh sách hiện có và thêm bất kỳ đối tượng có thể lặp lại nào mà bạn đưa vào đó.\n\n### Tại sao tôi phải dùng .value\n\nChúng ta có thể loại bỏ việc sử dụng 'value' đối với `String` và` int` bằng một trình tạo mã và decoration đơn giản, nhưng mục đích của thư viện này chính là tránh các dependency bên ngoài. Chúng tôi muốn cung cấp một môi trường sẵn sàng cho việc lập trình, liên quan đến các yếu tố cần thiết (quản lý các route, dependency và state), theo cách đơn giản, nhẹ và hiệu quả mà không cần gói bên ngoài.\n\nTheo nghĩa đen, bạn có thể thêm 3 chữ cái vào pubspec (get) của mình và dấu hai chấm và bắt đầu lập trình. Tất cả các giải pháp được bao gồm theo mặc định, từ quản lý route đến quản lý state, nhằm mục đích dễ dàng, năng suất và hiệu suất.\n\nTổng trọng lượng của thư viện này ít hơn của một trình quản lý state duy nhất, mặc dù nó là một giải pháp hoàn chỉnh và đó là những gì bạn phải hiểu.\n\nNếu bạn bị làm phiền bởi `.value`, và giống như một trình tạo mã, MobX là một giải pháp thay thế tuyệt vời và bạn có thể sử dụng nó cùng với Get. Đối với những người muốn thêm một gói dependency duy nhất vào pubspec và bắt đầu lập trình mà không cần lo lắng về phiên bản của gói không tương thích với gói khác hoặc nếu lỗi cập nhật state đến từ trình quản lý state hoặc dependency, hoặc vẫn không muốn lo lắng về sự sẵn có của controller, cho dù theo nghĩa đen là \"chỉ là lập trình\", GetX là lựa chọn hoàn hảo.\n\nNếu bạn không gặp vấn đề gì với trình tạo mã MobX hoặc không gặp vấn đề gì với bảng soạn sẵn BLoC, bạn có thể chỉ cần sử dụng Get cho các route và quên rằng nó có trình quản lý state. Get SEM và RSM ra đời không cần thiết, công ty của tôi có một dự án với hơn 90 controller và trình tạo mã chỉ mất hơn 30 phút để hoàn thành nhiệm vụ của nó sau khi Flutter Clean trên một máy khá tốt, nếu dự án của bạn có 5, 10, 15 controller, bất kỳ nhà quản lý state sẽ cung cấp cho bạn tốt. Nếu bạn có một dự án lớn đến mức ngớ ngẩn và trình tạo mã là một vấn đề đối với bạn, thì bạn đã được trao giải pháp này.\n\nRõ ràng, nếu ai đó muốn đóng góp vào dự án và tạo trình tạo mã, hoặc thứ gì đó tương tự, tôi sẽ liên kết trong readme này như một giải pháp thay thế, nhu cầu của tôi không phải là nhu cầu của tất cả các nhà phát triển, nhưng ý tôi là thế, đã có những giải pháp tốt đã làm được điều đó, như MobX.\n\n### Obx()\n\nNhập vào Get bằng cách sử dụng Bindings là không cần thiết. bạn có thể sử dụng widget Obx thay vì GetX, widget chỉ nhận được chức năng ẩn danh tạo widget.\nRõ ràng, nếu bạn không sử dụng một kiểu, bạn sẽ cần phải có một phiên bản của controller để sử dụng các biến hoặc sử dụng `Get.find <Controller> ()` .value hoặc Controller.to.value để truy xuất giá trị .\n\n### Workers\n\nWorkers sẽ hỗ trợ bạn, kích hoạt các lệnh gọi lại cụ thể khi một event xảy ra.\n\n``` dart\n/// Called every time `count1` changes.\never(count1, (_) => print(\"$_ has been changed\"));\n\n/// Called only first time the variable $_ is changed\nonce(count1, (_) => print(\"$_ was changed once\"));\n\n/// Anti DDos - Called every time the user stops typing for 1 second, for example.\ndebounce(count1, (_) => print(\"debouce$_\"), time: Duration(seconds: 1));\n\n/// Ignore all changes within 1 second.\ninterval(count1, (_) => print(\"interval $_\"), time: Duration(seconds: 1));\n```\n\nTất cả các workers (except `debounce` ) có `condition` tham số được đặt tên, mà có thể là loại `bool` hoặc lệnh gọi lại trả về một `bool` .\n`condition` này mô tả khi `callback` kích hoạt.\n\nTất cả các workers đều trả về trường hợp `Worker`, mà bạn có thể đóng ( thông qua `dispose()` ) của worker.\n \n\n* **`ever`**\n\n được gọi mỗi khi biến _Rx_ tạo ra một giá trị mới.\n\n* **`everAll`**\n\nGiống như `ever`, nhưng nó có một` List` gồm các giá trị _Rx_ Được gọi mỗi khi biến của nó bị thay đổi. Chỉ vậy thôi người ơi~ 😊\n\n* **`once`**\n\n'once' chỉ được gọi lần đầu tiên biến được thay đổi.\n\n* **`debounce`**\n\n'debounce' rất hữu ích trong các hàm tìm kiếm, nơi bạn chỉ muốn API được gọi khi người dùng nhập xong. Nếu người dùng nhập \"Kaiser\", bạn sẽ có 6 tìm kiếm trong các API, theo ký tự K, a, i, s, e và r. Với Get, điều này không xảy ra, bởi vì bạn sẽ có một Worker \"debounce\" sẽ chỉ được kích hoạt khi kết thúc nhập.\n\n* **`interval`**\n\n'interval' khác với debounce. Debounce xảy ra nếu người dùng thực hiện 1000 thay đổi đối với một biến trong vòng 1 giây, y sẽ chỉ gửi biến cuối cùng sau bộ hẹn giờ quy định (mặc định là 800 mili giây). Thay vào đó, interval sẽ bỏ qua tất cả các hành động của người dùng trong interval quy định. Nếu bạn gửi event trong 1 phút, 1000 mỗi giây, tính năng gỡ lỗi sẽ chỉ gửi cho bạn event cuối cùng, khi người dùng ngừng phân chia event. interval sẽ phân phối các event mỗi giây và nếu được đặt thành 3 giây, nó sẽ phân phối 20 event trong phút đó. Điều này được khuyến nghị để tránh lạm dụng, trong các chức năng mà người dùng có thể nhanh chóng nhấp vào một thứ gì đó và có được một số lợi thế (hãy tưởng tượng rằng người dùng có thể kiếm được xu bằng cách nhấp vào thứ gì đó, nếu y nhấp 300 lần trong cùng một phút, y sẽ có 300 xu, bằng cách sử dụng interval, bạn có thể đặt khung thời gian trong 3 giây, và thậm chí sau đó nhấp vào 300 hoặc một nghìn lần, tối đa y sẽ nhận được trong 1 phút sẽ là 20 xu, nhấp 300 hoặc 1 triệu lần). Việc gỡ lỗi này phù hợp cho việc chống DDos, cho các chức năng như tìm kiếm trong đó mỗi thay đổi đối với onChange sẽ gây ra một truy vấn tới api của bạn. Debounce sẽ đợi người dùng ngừng nhập tên để thực hiện yêu cầu. Nếu nó được sử dụng trong kịch bản đồng xu được đề cập ở trên, người dùng sẽ chỉ giành được 1 đồng xu, bởi vì nó chỉ được thực thi, khi người dùng \"tạm dừng\" trong thời gian đã thiết lập.\n\n* CHÍ Ú: Workers phải luôn được sử dụng khi khởi động Controller hoặc Class, vì vậy nó phải luôn ở trên onInit (được khuyến nghị), phương thức khởi tạo Class hoặc initState của StatefulWidget (phương pháp này không được khuyến khích trong hầu hết các trường hợp, nhưng nó không nên có hiệu ứng phụ nào khác).\n\n## Quản lý State đơn giản\n\nGet có một trình quản lý state cực kỳ nhẹ và dễ dàng, không sử dụng ChangeNotifier, sẽ đáp ứng nhu cầu đặc biệt cho những người mới sử dụng Flutter và sẽ không gây ra sự cố cho các ứng dụng lớn.\n\nGetBuilder nhắm chính xác vào việc kiểm soát nhiều state. Hãy tưởng tượng rằng bạn đã thêm 30 sản phẩm vào giỏ hàng, bạn nhấp vào xóa một sản phẩm, đồng thời danh sách được cập nhật, giá được cập nhật và huy hiệu trong giỏ hàng được cập nhật thành số lượng nhỏ hơn. Kiểu tiếp cận này khiến GetBuilder trở thành kẻ giết người, bởi vì nó nhóm các state và thay đổi tất cả chúng cùng một lúc mà không có bất kỳ \"logic tính toán\" nào cho điều đó. GetBuilder được tạo ra với loại tình huống này, vì để thay đổi state tạm thời, bạn có thể sử dụng setState và bạn sẽ không cần trình quản lý state cho việc này.\n\nBằng cách đó, nếu bạn muốn một controller riêng lẻ, bạn có thể gán ID cho controller đó hoặc sử dụng GetX. Điều này là tùy thuộc vào bạn, hãy nhớ rằng bạn càng có nhiều widget \"riêng lẻ\" thì hiệu suất của GetX càng nổi bật, trong khi hiệu suất của GetBuilder phải vượt trội hơn khi có nhiều thay đổi state.\n\n### Lợi thế\n\n1. Chỉ cập nhật các widget được yêu cầu.\n\n2. Không sử dụng changeNotifier, đó là trình quản lý state sử dụng ít bộ nhớ hơn (gần như bằng 0mb).\n\n3. Quên StatefulWidget! Với Get, bạn sẽ không bao giờ cần đến nó. Với các trình quản lý state khác, bạn có thể sẽ phải sử dụng StatefulWidget để lấy phiên bản của Provider, BLoC, MobX, v.v. Nhưng bạn đã bao giờ nghĩ rằng AppBar, Scaffole và hầu hết các widget trong class của bạn là stateless? Vậy tại sao phải lưu state của toàn bộ class, nếu bạn chỉ có thể lưu state của Widget là stateful? Get giải quyết được điều đó bằng cách tạo một class Stateless, làm cho mọi thứ trở nên vô trạng. Nếu bạn cần cập nhật một thành phần riêng lẻ, hãy bọc nó bằng GetBuilder và state của nó sẽ được duy trì.\n\n4. Tái cơ cấu cho dự án của bạn xanh, sạch và đẹp! Controller không được nằm trong UI của bạn, hãy đặt TextEditController của bạn hoặc bất kỳ controller nào bạn sử dụng trong class Controller của mình.\n\n5. Bạn có cần kích hoạt event để cập nhật widget con ngay khi nó được hiển thị không? GetBuilder có thuộc tính \"initState\", giống như StatefulWidget và bạn có thể gọi các event từ controller của mình, trực tiếp từ nó, không có thêm event nào được đặt trong initState của bạn.\n\n6. Bạn có cần phải kích hoạt một hành động như đóng streams, hẹn giờ, v.v. không? GetBuilder cũng có dispose property, nơi bạn có thể gọi các event ngay khi widget đó bị phá hủy.\n\n7. Chỉ sử dụng các streams nếu cần thiết. Bạn có thể sử dụng StreamControllers bên trong controller của mình một cách bình thường và sử dụng StreamBuilder cũng bình thường, nhưng hãy nhớ rằng, một streams tiêu thụ bộ nhớ một kha khá, lập trình phản ứng rất đẹp, nhưng bạn không nên lạm dụng nó. 30 streams mở cùng lúc có thể tệ hơn changeNotifier (và changeNotifier đã rất là tệ).\n\n8. Cập nhật các widgets mà không tốn ram. Chỉ lưu trữ ID người tạo GetBuilder và cập nhật GetBuilder đó khi cần thiết. Mức tiêu thụ bộ nhớ của get ID trong bộ nhớ là rất thấp ngay cả đối với hàng nghìn GetBuilders. Khi bạn tạo GetBuilder mới, bạn thực sự đang chia sẻ state GetBuilder có ID người tạo. Một state mới không được tạo cho mỗi GetBuilder, giúp tiết kiệm RẤT NHIỀU ram cho các ứng dụng lớn. Về cơ bản, ứng dụng của bạn sẽ hoàn toàn là Không state và một số ít Tiện ích sẽ có state (trong GetBuilder) sẽ có một state duy nhất, và do đó cập nhật một sẽ cập nhật tất cả. Nhà nước chỉ là một.\n\n9. Get là toàn trí và trong hầu hết các trường hợp, nó biết chính xác thời gian để lấy controller ra khỏi bộ nhớ. Bạn không nên lo lắng về việc khi nào nên vứt bỏ controller, Get biết thời điểm tốt nhất để thực hiện việc này.\n\n### Sử dụng\n\n``` dart\n// Create controller class and extends GetxController\nclass Controller extends GetxController {\n  int counter = 0;\n  void increment() {\n    counter++;\n    update(); // use update() to update counter variable on UI when increment be called\n  }\n}\n// On your Stateless/Stateful class, use GetBuilder to update Text when increment be called\nGetBuilder<Controller>(\n  init: Controller(), // INIT IT ONLY THE FIRST TIME\n  builder: (_) => Text(\n    '${_.counter}',\n  ),\n)\n//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.\n```\n\n**OK, giải thích xong rồi!**\n\n* Bạn đã học cách quản lý state với Get.\n\n* Lưu ý: Bạn có thể muốn một tổ chức lớn hơn và không sử dụng thuộc tính init. Vì vậy, bạn có thể tạo một class và mở rộng class Bindings và trong đó đề cập đến các controller sẽ được tạo trong route đó. Khi đó các Controllers sẽ không được tạo, ngược lại, đây chỉ là một câu lệnh, để lần đầu sử dụng Controller, Get sẽ biết cần tìm ở đâu. Get sẽ vẫn là lazyLoad và sẽ tiếp tục loại bỏ Controller khi chúng không còn cần thiết nữa. Hãy xem ví dụ pub.dev để xem nó hoạt động như thế nào.\n\nNếu bạn điều hướng nhiều route và cần dữ liệu trong controller đã sử dụng trước đó, bạn chỉ cần sử dụng GetBuilder Again (không có init):\n\n``` dart\nclass OtherClass extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      body: Center(\n        child: GetBuilder<Controller>(\n          builder: (s) => Text('${s.counter}'),\n        ),\n      ),\n    );\n  }\n\n```\n\nNếu bạn cần sử dụng controller của mình ở nhiều nơi khác và bên ngoài GetBuilder, chỉ cần tạo quyền truy cập vào controller của bạn và có nó một cách dễ dàng. (hoặc sử dụng `Get.find <Controller> ()`)\n\n``` dart\nclass Controller extends GetxController {\n\n  /// You do not need that. I recommend using it just for ease of syntax.\n  /// with static method: Controller.to.increment();\n  /// with no static method: Get.find<Controller>().increment();\n  /// 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.\n  static Controller get to => Get.find(); // add this line\n\n  int counter = 0;\n  void increment() {\n    counter++;\n    update();\n  }\n}\n```\n\nSau đó, truy cập thẳng vào controller của bạn:\n\n``` dart\nFloatingActionButton(\n  onPressed: () {\n    Controller.to.increment(),\n  } // This is incredibly simple!\n  child: Text(\"${Controller.to.counter}\"),\n),\n```\n\nKhi bạn nhấn FloatingActionButton, tất cả các widget đang lắng nghe biến 'counter' sẽ được cập nhật tự động.\n\n### Cách GetX sử dụng controllers\n\nVí dụ:\n\n `Class a => Class B (has controller X) => Class C (has controller X)`\n\nTrong class A, controller chưa có trong bộ nhớ, vì bạn chưa sử dụng nó (Get là lazyLoad). Trong class B, bạn đã sử dụng controller và nó đã vào bộ nhớ. Trong class C, bạn đã sử dụng cùng một controller như trong class B, Get sẽ chia sẻ state của controller B với controller C, và controller tương tự vẫn còn trong bộ nhớ. Nếu bạn đóng màn hình C và màn hình B, Get sẽ tự động lấy controller X ra khỏi bộ nhớ và giải phóng tài nguyên, vì Class A không sử dụng controller. Nếu bạn điều hướng đến B một lần nữa, controller X sẽ nhập lại bộ nhớ, nếu thay vì đi đến class C, bạn quay lại class A một lần nữa, Get sẽ đưa controller ra khỏi bộ nhớ theo cách tương tự. Nếu class C không sử dụng controller và bạn đã lấy class B ra khỏi bộ nhớ, thì sẽ không có class nào sử dụng controller X và tương tự như vậy, nó sẽ bị loại bỏ. Ngoại lệ duy nhất có thể gây rắc rối với Get là nếu bạn xóa B khỏi route một cách bất ngờ và cố gắng sử dụng controller trong C. Trong trường hợp này, ID người tạo của controller ở B đã bị xóa và Get được lập trình để xóa nó khỏi bộ nhớ mọi controller không có ID người tạo. Nếu bạn dự định làm điều này, hãy thêm flag \"autoRemove: false\" vào GetBuilder của class B và sử dụng adoptID = true trong GetBuilder của class C.\n\n### Không cần StatefulWidget nữa!\n\nSử dụng StatefulWidgets có nghĩa là lưu trữ state của toàn bộ màn hình một cách không cần thiết, ngay cả khi bạn cần xây dựng lại một cách tối thiểu widget, bạn sẽ nhúng nó vào Consumer / Observer / BlocProvider / GetBuilder / GetX / Obx, đây sẽ là một StatefulWidget khác.\nClass StatefulWidget là một class lớn hơn StatelessWidget, class này sẽ phân bổ nhiều RAM hơn và điều này có thể không tạo ra sự khác biệt đáng kể giữa một hoặc hai class, nhưng chắc chắn nó sẽ làm được khi bạn có 100 class trong số chúng!\nTrừ khi bạn cần sử dụng một mixin, như TickerProviderStateMixin, thì việc sử dụng StatefulWidget với Get là hoàn toàn không cần thiết.\n\nBạn có thể gọi trực tiếp tất cả các phương thức của StatefulWidget từ GetBuilder.\nNếu bạn cần gọi phương thức initState () hoặc dispose () chẳng hạn, bạn có thể gọi chúng trực tiếp;\n\n``` dart\nGetBuilder<Controller>(\n  initState: (_) => Controller.to.fetchApi(),\n  dispose: (_) => Controller.to.closeStreams(),\n  builder: (s) => Text('${s.username}'),\n),\n```\n\nMột cách tiếp cận tốt hơn nhiều so với cách này là sử dụng phương thức onInit () và onClose () trực tiếp từ controller của bạn.\n\n``` dart\n@override\nvoid onInit() {\n  fetchApi();\n  super.onInit();\n}\n```\n\n* CHÍ Ú: Nếu bạn muốn bắt đầu một phương thức tại thời điểm controller được gọi lần đầu tiên, bạn KHÔNG CẦN sử dụng các hàm tạo cho việc này, trên thực tế, bằng cách sử dụng gói hướng hiệu suất như Get, điều này không phù hợp với thực tiễn xấu, bởi vì nó lệch khỏi logic trong đó controller được tạo hoặc chỉ định (nếu bạn tạo một phiên bản của controller này, hàm tạo sẽ được gọi ngay lập tức, bạn sẽ điền controller trước khi nó được sử dụng, bạn đang cấp phát bộ nhớ mà không sử dụng nó , điều này chắc chắn làm hỏng các nguyên tắc của thư viện này). Các phương thức onInit(); và onClose(); được tạo ra cho mục đích này, chúng sẽ được gọi khi Controller được tạo hoặc được sử dụng lần đầu tiên, tùy thuộc vào việc bạn có đang sử dụng Get.lazyPut hay không. Ví dụ: nếu bạn muốn thực hiện lệnh gọi tới API của mình để điền dữ liệu, bạn có thể quên phương thức cũ của initState / dispose, chỉ cần bắt đầu lệnh gọi tới api trong onInit. Nếu bạn cần thực thi bất kỳ lệnh nào, như đóng streams, hãy sử dụng onClose() cho việc đó.\n\n### Tại sao GetX tồn tại?\n\nMục đích của gói này chính xác là cung cấp cho bạn một giải pháp hoàn chỉnh để điều hướng các route, quản lý các dependency và state, sử dụng các dependency ít nhất có thể, với mức độ tách biệt cao. Nhận tất cả các API Flutter cấp cao và cấp thấp trong chính nó, để đảm bảo rằng bạn làm việc với ít khớp nối nhất có thể. Chúng tôi tập trung mọi thứ trong một gói duy nhất, để đảm bảo rằng bạn không có bất kỳ loại khớp nối nào trong dự án của mình. Bằng cách đó, bạn có thể chỉ đặt các widget trong chế độ xem của mình và để phần của nhóm làm việc với logic nghiệp vụ tự do làm việc với logic nghiệp vụ độc lập với View. Điều này cung cấp một môi trường làm việc sạch hơn nhiều, để một phần nhóm của bạn chỉ hoạt động với các widget mà không phải lo lắng về việc gửi dữ liệu đến controller của bạn và một phần nhóm của bạn chỉ làm việc với logic nghiệp vụ trong phạm vi bề rộng của nó mà không dependency vào bất kỳ yếu tố View.\n\nVì vậy, để đơn giản hóa điều này:\nBạn không cần gọi các phương thức trong initState và gửi chúng theo tham số đến controller của mình, cũng như không sử dụng phương thức khởi tạo controller cho việc đó, bạn có phương thức onInit() được gọi vào đúng thời điểm để bạn khởi động các dịch vụ của mình.\nBạn không cần phải gọi thiết bị, bạn có phương thức onClose() sẽ được gọi vào thời điểm chính xác khi controller của bạn không còn cần thiết nữa và sẽ bị xóa khỏi bộ nhớ. Bằng cách đó, chỉ để lại chế độ xem cho các widget, tránh bất kỳ loại logic nghiệp vụ nào từ nó.\n\nĐừng gọi một phương thức vứt bỏ bên trong GetxController, nó sẽ không làm được gì cả, hãy nhớ rằng controller không phải là một Widget, bạn không nên \"vứt bỏ\" nó, và nó sẽ được Get tự động và thông minh xóa khỏi bộ nhớ. Nếu bạn đã sử dụng bất kỳ streams nào trên đó và muốn đóng streams đó, chỉ cần chèn streams đó vào phương thức đóng. Thí dụ:\n\n``` dart\nclass Controller extends GetxController {\n  StreamController<User> user = StreamController<User>();\n  StreamController<String> name = StreamController<String>();\n\n  /// close stream = onClose method, not dispose.\n  @override\n  void onClose() {\n    user.close();\n    name.close();\n    super.onClose();\n  }\n}\n```\n\nVòng đời của controller:\n\n* onInit() nơi nó được tạo.\n* onClose() nơi nó được đóng để thực hiện bất kỳ thay đổi nào nhằm chuẩn bị cho phương thức xóa\n* deleted: bạn không có quyền truy cập vào API này vì nó sẽ xóa controller khỏi bộ nhớ theo đúng nghĩa đen. Nó được xóa theo đúng nghĩa đen, mà không để lại bất kỳ dấu vết nào.\n\n### Cách sử dụng khác\n\nBạn có thể sử dụng phiên bản Controller trực tiếp trên giá trị GetBuilder:\n\n``` dart\nGetBuilder<Controller>(\n  init: Controller(),\n  builder: (value) => Text(\n    '${value.counter}', //here\n  ),\n),\n```\n\nBạn cũng có thể cần một phiên bản của controller bên ngoài GetBuilder và bạn có thể sử dụng các phương pháp này để đạt được điều này:\n\n``` dart\nclass Controller extends GetxController {\n  static Controller get to => Get.find();\n[...]\n}\n// on you view:\nGetBuilder<Controller>(  \n  init: Controller(), // use it only first time on each controller\n  builder: (_) => Text(\n    '${Controller.to.counter}', //here\n  )\n),\n```\n\nor\n\n``` dart\nclass Controller extends GetxController {\n // static Controller get to => Get.find(); // with no static get\n[...]\n}\n// on stateful/stateless class\nGetBuilder<Controller>(  \n  init: Controller(), // use it only first time on each controller\n  builder: (_) => Text(\n    '${Get.find<Controller>().counter}', //here\n  ),\n),\n```\n\n* Bạn có thể sử dụng các phương pháp tiếp cận \"không chuẩn\" để thực hiện việc này. Nếu bạn đang sử dụng một số trình quản lý dependency khác, như get_it, modular, v.v. và chỉ muốn cung cấp phiên bản controller, bạn có thể thực hiện điều này:\n\n``` dart\nController controller = Controller();\n[...]\nGetBuilder<Controller>(\n  init: controller, //here\n  builder: (_) => Text(\n    '${controller.counter}', // here\n  ),\n),\n\n```\n\n### IDs độc nhất\n\nNếu bạn muốn tinh chỉnh kiểm soát cập nhật của widget con với GetBuilder, bạn có thể gán cho chúng các ID độc:\n\n``` dart\nGetBuilder<Controller>(\n  id: 'text'\n  init: Controller(), // use it only first time on each controller\n  builder: (_) => Text(\n    '${Get.find<Controller>().counter}', //here\n  ),\n),\n```\n\nVà cập nhật nó vào biểu mẫu này:\n\n``` dart\nupdate(['text']);\n```\n\nBạn cũng có thể áp đặt các điều kiện cho bản cập nhật:\n\n``` dart\nupdate(['text'], counter < 10);\n```\n\nGetX thực hiện điều này tự động và chỉ cấu trúc lại widget con sử dụng biến chính xác đã được thay đổi, nếu bạn thay đổi một biến thành giống với biến trước đó và điều đó không ngụ ý thay đổi state, GetX sẽ không xây dựng lại widget con để tiết kiệm bộ nhớ và Chu kỳ CPU ( 3 đang được hiển thị trên màn hình và bạn lại thay đổi biến thành 3. Trong hầu hết các trình quản lý state, điều này sẽ gây ra việc xây dựng lại mới, nhưng với GetX, widget sẽ chỉ được xây dựng lại, nếu trên thực tế state của nó đã thay đổi ).\n\n## Trộn hai trình quản lý state\n\nMột số người đã mở một yêu cầu tính năng, vì họ chỉ muốn sử dụng một loại biến phản ứng và cơ chế khác và cần chèn Obx vào GetBuilder cho việc này. Suy nghĩ về nó MixinBuilder đã được tạo ra. Nó cho phép cả những thay đổi phản ứng bằng cách thay đổi các biến \".obs\" và cập nhật thủ công thông qua update(). Tuy nhiên, trong số 4 widget, nó là widget tiêu tốn nhiều tài nguyên nhất, vì ngoài việc có Subscription để nhận các event thay đổi từ con mình, nó còn đăng ký phương thức cập nhật của controller của mình.\n\nViệc mở rộng GetxController rất quan trọng, vì chúng có vòng đời và có thể \"bắt đầu\" và \"kết thúc\" các event trong các phương thức onInit() và onClose() của chúng. Bạn có thể sử dụng bất kỳ lớp nào cho việc này, nhưng tôi thực sự khuyên bạn nên sử dụng lớp GetxController để đặt các biến của bạn, cho dù chúng có thể quan sát được hay không.\n\n## StateMixin\n\nMột cách khác để xử lý state `UI` của bạn là sử dụng` StateMixin <T> `.\nĐể triển khai nó, hãy sử dụng dấu `với` để thêm` StateMixin <T> ` bộ điều khiển của bạn cho phép một mô hình T.\n\n``` dart\nclass Controller extends GetController with StateMixin<User>{}\n```\n\nPhương thức `change()` thay đổi state bất cứ khi nào chúng ta muốn.\nChỉ cần truyền dữ liệu và state theo cách này:\n\n```dart\nchange(data, status: RxStatus.success());\n```\n\nRxStatus cho phép các state này:\n\n``` dart\nRxStatus.loading();\nRxStatus.success();\nRxStatus.empty();\nRxStatus.error('message');\n```\n\nĐể diễn tả nó trên UI, sử dụng:\n\n```dart\nclass OtherClass extends GetView<Controller> {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n\n      body: controller.obx(\n        (state)=>Text(state.name),\n        \n        // here you can put your custom loading indicator, but\n        // by default would be Center(child:CircularProgressIndicator())\n        onLoading: CustomLoadingIndicator(),\n        onEmpty: Text('No data found'),\n\n        // here also you can set your own error widget, but by\n        // default will be an Center(child:Text(error))\n        onError: (error)=>Text(error),\n      ),\n    );\n}\n```\n\n## GetBuilder vs GetX vs Obx vs MixinBuilder\n\nTrong một thập kỷ làm việc với lập trình, tôi đã có thể học được một số bài học quý giá.\n\nLần đầu tiên tôi tiếp xúc với lập trình phản ứng là rất \"Trời thần ơi, tuyệt vời ông mặt trời!\" và trên thực tế, lập trình phản ứng là không thể tin được.\nTuy nhiên, nó không phải là thích hợp cho tất cả các trường hợp. Thông thường, tất cả những gì bạn cần là thay đổi state của 2 hoặc 3 widget cùng lúc, hoặc thay đổi state trong thời gian ngắn, trong trường hợp này, lập trình phản ứng không phải là xấu, nhưng nó không phù hợp.\n\nLập trình phản ứng có mức tiêu thụ RAM cao hơn có thể được bù đắp bởi quy trình làm việc riêng lẻ, điều này sẽ đảm bảo rằng chỉ một widget con được xây dựng lại và khi cần thiết, nhưng tạo danh sách với 80 đối tượng, mỗi đối tượng có nhiều streams không phải là một ý kiến hay . Mở thanh kiểm tra phi tiêu và kiểm tra xem StreamBuilder tiêu thụ bao nhiêu và bạn sẽ hiểu những gì tôi đang cố gắng nói với bạn.\n\nVới ý nghĩ đó, tôi đã tạo trình quản lý state đơn giản. Nó đơn giản, và đó chính xác là những gì bạn cần ở nó: cập nhật state trong các khối theo cách đơn giản và tiết kiệm nhất.\n\nGetBuilder rất tiết kiệm RAM và khó có cách tiếp cận nào tiết kiệm hơn nó (ít nhất là tôi không thể tưởng tượng được, nếu đã tồn tại cách khác, vui lòng cho chúng tôi biết).\n\nTuy nhiên, GetBuilder vẫn là một trình quản lý state cơ học, bạn cần phải gọi update () giống như bạn sẽ cần gọi tới Provider's InformListaries ().\n\nCó những tình huống khác mà lập trình phản ứng thực sự thú vị và nếu không dùng nó đồng nghĩa như đang phát minh lại cái bánh xe. Với suy nghĩ đó, GetX được tạo ra để cung cấp mọi thứ hiện đại và tiên tiến nhất trong một trình quản lý state. Nó chỉ cập nhật những gì cần thiết và khi cần thiết, nếu bạn gặp lỗi và gửi 300 state thay đổi đồng thời, GetX sẽ lọc và cập nhật màn hình chỉ khi state thực sự thay đổi.\n\nGetX vẫn tiết kiệm hơn bất kỳ trình quản lý state phản ứng nào khác, nhưng nó tiêu tốn nhiều RAM hơn GetBuilder một chút. Suy nghĩ về điều đó và hướng tới việc tiêu thụ tối đa tài nguyên mà Obx đã tạo ra. Không giống như GetX và GetBuilder, bạn sẽ không thể khởi tạo controller bên trong Obx, nó chỉ là một Widget với StreamSubscription nhận các event thay đổi từ con bạn, vậy thôi. Nó tiết kiệm hơn GetX, nhưng thua GetBuilder, điều được mong đợi, vì nó có tính phản ứng và GetBuilder có cách tiếp cận đơn giản nhất tồn tại, đó là lưu trữ hashCode của widget con và StateSetter của nó. Với Obx, bạn không cần phải viết loại controller của mình và bạn có thể nghe thấy sự thay đổi từ nhiều controller khác nhau, nhưng nó cần được khởi tạo trước đó, sử dụng phương pháp ví dụ ở đầu readme này hoặc sử dụng class Bindings.\n"
  },
  {
    "path": "documentation/zh_CN/dependency_management.md",
    "content": "# ＃依赖管理\n- [依赖管理](#依赖管理)\n  - [实例方法](#实例方法)\n    - [Get.put()](#Get.put())\n    - [Get.lazyPut](#Get.lazyPut)\n    - [Get.putAsync](#Get.putAsync)\n    - [Get.create](#Get.create)\n  - [使用实例化方法/类](#使用实例化方法/类)\n  - [方法之间的差异](#方法之间的差异)\n  - [Bindings](#Bindings)\n    - [Bindings类](#Bindings类)\n    - [BindingsBuilder](#BindingsBuilder)\n    - [智能管理](#智能管理)\n      - [如何改变](#如何改变)\n      - [SmartManagement.full](#smartmanagementfull)\n      - [SmartManagement.onlyBuilders](#SmartManagement.onlyBuilders)\n      - [SmartManagement.keepFactory](#smartmanagementkeepFactory)\n    - [Bindings的工作原理](#Bindings的工作原理)\n  - [注释](#注释)\n\nGet有一个简单而强大的依赖管理器，它允许你只用1行代码就能检索到与你的Bloc或Controller相同的类，无需Provider上下文，无需 inheritedWidget。\n\n```dart\nController controller = Get.put(Controller()); // 而不是 Controller controller = Controller();\n```\n\n你是在Get实例中实例化它，而不是在你正在使用的类中实例化你的类，这将使它在整个App中可用。\n所以你可以正常使用你的控制器（或Bloc类）。\n\n- 注意：如果你使用的是Get的状态管理器，请多关注[Bindings](#Bindings)api，这将使你的视图更容易连接到你的控制器。\n- 注意事项²。Get的依赖管理与包中的其他部分是分离的，所以如果你的应用已经使用了一个状态管理器（任何一个，都没关系），你不需要修改也可以同时使用这个依赖注入管理器，完全没有问题。\n\n## 实例方法\n这些方法和它的可配置参数是：\n\n### Get.put()\n\n最常见的插入依赖关系的方式。例如，对于你的视图的控制器来说：\n\n```dart\nGet.put<SomeClass>(SomeClass());\nGet.put<LoginController>(LoginController(), permanent: true);\nGet.put<ListItemController>(ListItemController, tag: \"some unique string\");\n```\n\n这是你使用put时可以设置的所有选项。\n```dart\nGet.put<S>(\n  // 必备：你想得到保存的类，比如控制器或其他东西。\n  // 注：\"S \"意味着它可以是任何类型的类。\n  S dependency\n\n  // 可选：当你想要多个相同类型的类时，可以用这个方法。\n  // 因为你通常使用Get.find<Controller>()来获取一个类。\n  // 你需要使用标签来告诉你需要哪个实例。\n  // 必须是唯一的字符串\n  String tag,\n\n  // 可选：默认情况下，get会在实例不再使用后进行销毁\n  // （例如：一个已经销毁的视图的Controller)\n  // 但你可能需要这个实例在整个应用生命周期中保留在那里，就像一个sharedPreferences的实例或其他东西。\n  //所以你设置这个选项\n  // 默认值为false\n  bool permanent = false,\n\n  // 可选：允许你在测试中使用一个抽象类后，用另一个抽象类代替它，然后再进行测试。\n  // 默认为false\n  bool overrideAbstract = false,\n\n  // 可选：允许你使用函数而不是依赖（dependency）本身来创建依赖。\n  // 这个不常用\n  InstanceBuilderCallback<S> builder,\n)\n```\n\n### Get.lazyPut\n可以懒加载一个依赖，这样它只有在使用时才会被实例化。这对于计算代价高的类来说非常有用，或者如果你想在一个地方实例化几个类（比如在Bindings类中），而且你知道你不会在那个时候使用这个类。\n\n```dart\n///只有当第一次使用Get.find<ApiMock>时，ApiMock才会被调用。\nGet.lazyPut<ApiMock>(() => ApiMock());\n\nGet.lazyPut<FirebaseAuth>(\n  () {\n    // ... some logic if needed\n    return FirebaseAuth();\n  },\n  tag: Math.random().toString(),\n  fenix: true\n)\n\nGet.lazyPut<Controller>( () => Controller() )\n```\n\n这是你在使用lazyPut时可以设置的所有选项。\n```dart\nGet.lazyPut<S>(\n  // 强制性：当你的类第一次被调用时，将被执行的方法。\n  InstanceBuilderCallback builder,\n  \n  // 可选：和Get.put()一样，当你想让同一个类有多个不同的实例时，就会用到它。\n  // 必须是唯一的\n  String tag,\n\n  // 可选：类似于 \"永久\"，\n  // 不同的是，当不使用时，实例会被丢弃，但当再次需要使用时，Get会重新创建实例，\n  // 就像 bindings api 中的 \"SmartManagement.keepFactory \"一样。\n  // 默认值为false\n  bool fenix = false\n  \n)\n```\n\n### Get.putAsync\n如果你想注册一个异步实例，你可以使用`Get.putAsync`。\n\n```dart\nGet.putAsync<SharedPreferences>(() async {\n  final prefs = await SharedPreferences.getInstance();\n  await prefs.setInt('counter', 12345);\n  return prefs;\n});\n\nGet.putAsync<YourAsyncClass>( () async => await YourAsyncClass() )\n```\n\n这都是你在使用putAsync时可以设置的选项。\n```dart\nGet.putAsync<S>(\n\n  // 必备：一个将被执行的异步方法，用于实例化你的类。\n  AsyncInstanceBuilderCallback<S> builder,\n\n  // 可选：和Get.put()一样，当你想让同一个类有多个不同的实例时，就会用到它。\n  // 必须是唯一的\n  String tag,\n\n  // 可选：与Get.put()相同，当你需要在整个应用程序中保持该实例的生命时使用。\n  // 默认值为false\n  bool permanent = false\n)\n```\n\n### Get.create\n\n这个就比较棘手了。关于这个是什么和其他的区别，可以在[方法之间的差异](#方法之间的差异)部分找到详细的解释。\n\n```dart\nGet.Create<SomeClass>(() => SomeClass());\nGet.Create<LoginController>(() => LoginController());\n```\n\n这是你在使用create时可以设置的所有选项。\n\n```dart\nGet.create<S>(\n  // 需要：一个返回每次调用\"Get.find() \"都会被新建的类的函数。\n  // 示例: Get.create<YourClass>(()=>YourClass())\n  FcBuilderFunc<S> builder,\n\n  // 可选：就像Get.put()一样，但当你需要多个同类的实例时，会用到它。\n  // 当你有一个列表，每个项目都需要自己的控制器时，这很有用。\n  // 需要是一个唯一的字符串。只要把标签改成名字\n  String name,\n\n  // 可选：就像 Get.put() 一样，\n  // 它是为了当你需要在整个应用中保活实例的时候\n  // 区别在于 Get.create 的 permanent默认为true\n  bool permanent = true\n```\n\n## 使用实例化方法/类\n\n想象一下，你已经浏览了无数条路由，现在你需要拿到一个被遗留在控制器中的数据，那么你会需要一个状态管理器与Provider或Get_it相结合，对吗？用Get则不然，你只需要让Get为你的控制器自动 \"寻找\"，你不需要任何额外的依赖关系。\n\n```dart\nfinal controller = Get.find<Controller>();\n// 或者\nController controller = Get.find();\n\n// 是的，它看起来像魔术，Get会找到你的控制器，并将其提供给你。\n// 你可以实例化100万个控制器，Get总会给你正确的控制器。\n```\n\n然后你就可以恢复你在后面获得的控制器数据。\n\n```dart\nText(controller.textFromApi);\n```\n\n由于返回的值是一个正常的类，你可以做任何你想做的事情。\n```dart\nint count = Get.find<SharedPreferences>().getInt('counter');\nprint(count); // out: 12345\n```\n\n移除一个Get实例:\n\n```dart\nGet.delete<Controller>(); //通常你不需要这样做，因为GetX已经删除了未使用的控制器。\n```\n\n## 方法之间的差异\n\n首先，让我们来看看Get.lazyPut的 \"fenix \"和其他方法的 \"permanent\"。\n\n`permanent`和`fenix`的根本区别在于你想如何存储实例。\n\n强化：默认情况下，GetX会在不使用实例时删除它们。\n这意味着 如果页面1有控制器1，页面2有控制器2，而你从堆栈中删除了第一个路由，（比如你使用`Get.off()`或`Get.offNamed()`）控制器1失去了它的使用，所以它将被删除。\n\n但是如果你想选择使用`permanent:true`，那么控制器就不会在这个过渡中丢失--这对于你想在整个应用程序中保持生命的服务来说非常有用。\n\n`fenix`则是针对那些你不担心在页面变化之间丢失的服务，但当你需要该服务时，你希望它还活着。所以基本上，它会处理未使用的控制器/服务/类，但当你需要它时，它会 \"从灰烬中重新创建 \"一个新的实例。\n\n继续说说方法之间的区别：\n\n- Get.put和Get.putAsync的创建顺序是一样的，不同的是，第二个方法使用的是异步方法创建和初始化实例。put是直接插入内存，使用内部方法`insert`，参数`permanent: false`和`isSingleton: true`（这个isSingleton参数只是告诉它是使用`dependency`上的依赖，还是使用`FcBuilderFunc`上的依赖），之后，调用`Get.find()`，立即初始化内存中的实例。\n\n- Get.create。顾名思义，它将 \"创建 \"你的依赖关系！类似于`Get.put()`。与`Get.put()`类似，它也会调用内部方法`insert`来实例化。但是`permanent`变成了true，而`isSingleton`变成了false（因为我们是在 \"创建 \"我们的依赖关系，所以它没有办法成为一个单例，这就是为什么是false）。因为它有`permanent: true`，所以我们默认的好处是不会在页面跳转之间销毁它。另外，`Get.find()`并不是立即被调用，而是等待在页面中被调用，这样创建是为了利用 \"permanent \"这个参数，值得注意的是，`Get.create()`的目标是创建不共享的实例，但不会被销毁，比如listView中的一个按钮，你想为该列表创建一个唯一的实例--正因为如此，Get.create必须和GetWidget一起使用。\n\n- Get.lazyPut。顾名思义，这是一个懒加载的过程。实例被创建了，但它并没有被调用来立即使用，而是一直等待被调用。与其他方法相反，这里没有调用 \"insert\"。取而代之的是，实例被插入到内存的另一个部分，这个部分负责判断实例是否可以被重新创建，我们称之为 \"工厂\"。如果我们想创建一些以后使用的东西，它不会和现在使用的东西混在一起。这就是 \"fenix \"的魔力所在：如果你选择留下 \"fenix: false\"，并且你的 \"smartManagement \"不是 \"keepFactory\"，那么当使用 \"Get.find \"时，实例将把内存中的位置从 \"工厂 \"改为普通实例内存区域。紧接着，默认情况下，它将从 \"工厂 \"中移除。现在，如果你选择 \"fenix: true\"，实例将继续存在这个专用的部分，甚至进入公共区域，以便将来再次被调用。\n\n## Bindings\n\n这个包最大的区别之一，也许就是可以将路由、状态管理器和依赖管理器完全集成。\n当一个路由从Stack中移除时，所有与它相关的控制器、变量和对象的实例都会从内存中移除。如果你使用的是流或定时器，它们会自动关闭，你不必担心这些。\n在2.10版本中，Get完全实现了Bindings API。\n现在你不再需要使用init方法了。如果你不想的话，你甚至不需要键入你的控制器。你可以在适当的地方启动你的控制器和服务来实现。\nBinding类是一个将解耦依赖注入的类，同时 \"Bindings \"路由到状态管理器和依赖管理器。\n这使得Get可以知道当使用某个控制器时，哪个页面正在显示，并知道在哪里以及如何销毁它。\n此外，Binding类将允许你拥有SmartManager配置控制。你可以配置依赖关系，当从堆栈中删除一个路由时，或者当使用它的widget被布置时，或者两者都不布置。你将有智能依赖管理为你工作，但即使如此，你也可以按照你的意愿进行配置。\n\n### Bindings类\n\n- 创建一个类并实现Binding\n\n```dart\nclass HomeBinding implements Bindings {}\n```\n\n你的IDE会自动要求你重写 \"dependencies\"方法，然后插入你要在该路由上使用的所有类。\n\n```dart\nclass HomeBinding implements Bindings {\n  @override\n  void dependencies() {\n    Get.lazyPut<HomeController>(() => HomeController());\n    Get.put<Service>(()=> Api());\n  }\n}\n\nclass DetailsBinding implements Bindings {\n  @override\n  void dependencies() {\n    Get.lazyPut<DetailsController>(() => DetailsController());\n  }\n}\n```\n\n现在你只需要通知你的路由，你将使用该 Binding 来建立路由管理器、依赖关系和状态之间的连接。\n\n- 使用别名路由：\n\n```dart\ngetPages: [\n  GetPage(\n    name: '/',\n    page: () => HomeView(),\n    binding: HomeBinding(),\n  ),\n  GetPage(\n    name: '/details',\n    page: () => DetailsView(),\n    binding: DetailsBinding(),\n  ),\n];\n```\n\n- 使用正常路由。\n\n```dart\nGet.to(Home(), binding: HomeBinding());\nGet.to(DetailsView(), binding: DetailsBinding())\n```\n\n至此，你不必再担心你的应用程序的内存管理，Get将为你做这件事。\n\nBinding类在调用路由时被调用，你可以在你的GetMaterialApp中创建一个 \"initialBinding \"来插入所有将要创建的依赖关系。\n\n```dart\nGetMaterialApp(\n  initialBinding: SampleBind(),\n  home: Home(),\n);\n```\n\n### BindingsBuilder\n\n创建Bindings的默认方式是创建一个实现Bindings的类，但是，你也可以使用`BindingsBuilder`回调，这样你就可以简单地使用一个函数来实例化任何你想要的东西。\n\n例子:\n\n```dart\ngetPages: [\n  GetPage(\n    name: '/',\n    page: () => HomeView(),\n    binding: BindingsBuilder(() {\n      Get.lazyPut<ControllerX>(() => ControllerX());\n      Get.put<Service>(()=> Api());\n    }),\n  ),\n  GetPage(\n    name: '/details',\n    page: () => DetailsView(),\n    binding: BindingsBuilder(() {\n      Get.lazyPut<DetailsController>(() => DetailsController());\n    }),\n  ),\n];\n```\n\n这样一来，你就可以避免为每条路径创建一个 Binding 类，使之更加简单。\n\n两种方式都可以完美地工作，我们希望您使用最适合您的风格。\n\n### 智能管理\n\nGetX 默认情况下会将未使用的控制器从内存中移除。\n但是如果你想改变GetX控制类的销毁方式，你可以用`SmartManagement`类设置不同的行为。\n\n#### 如何改变\n\n如果你想改变这个配置（你通常不需要），就用这个方法。\n\n```dart\nvoid main () {\n  runApp(\n    GetMaterialApp(\n      smartManagement: SmartManagement.onlyBuilders //这里\n      home: Home(),\n    )\n  )\n}\n```\n\n#### SmartManagement.full\n\n这是默认的。销毁那些没有被使用的、没有被设置为永久的类。在大多数情况下，你会希望保持这个配置不受影响。如果你是第一次使用GetX，那么不要改变这个配置。\n\n#### SmartManagement.onlyBuilders\n使用该选项，只有在`init:`中启动的控制器或用`Get.lazyPut()`加载到Binding中的控制器才会被销毁。\n\n如果你使用`Get.put()`或`Get.putAsync()`或任何其他方法，SmartManagement将没有权限移除这个依赖。\n\n在默认行为下，即使是用 \"Get.put \"实例化的widget也会被移除，这与SmartManagement.onlyBuilders不同。\n\n#### SmartManagement.keepFactory\n\n就像SmartManagement.full一样，当它不再被使用时，它将删除它的依赖关系，但它将保留它们的工厂，这意味着如果你再次需要该实例，它将重新创建该依赖关系。\n### Bindings的工作原理\nBindings会创建过渡性工厂，在你点击进入另一个页面的那一刻，这些工厂就会被创建，一旦换屏动画发生，就会被销毁。\n这种情况发生得非常快，以至于分析器甚至都来不及注册。\n当你再次导航到这个页面时，一个新的临时工厂将被调用，所以这比使用SmartManagement.keepFactory更可取，但如果你不想创建Bindings，或者想让你所有的依赖关系都在同一个Binding上，它肯定会帮助你。\nFactories占用的内存很少，它们并不持有实例，而是一个具有你想要的那个类的 \"形状 \"的函数。\n这在内存上的成本很低，但由于这个库的目的是用最少的资源获得最大的性能，所以Get连工厂都默认删除。\n请使用对你来说最方便的方法。\n\n## 注释\n\n- 如果你使用多个Bindings，不要使用SmartManagement.keepFactory。它被设计成在没有Bindings的情况下使用，或者在GetMaterialApp的初始Binding中链接一个Binding。\n\n- 使用Bindings是完全可选的，你也可以在使用给定控制器的类上使用`Get.put()`和`Get.find()`。\n然而，如果你使用Services或任何其他抽象，我建议使用Bindings来更好地组织。\n"
  },
  {
    "path": "documentation/zh_CN/route_management.md",
    "content": "- [路由管理](#路由管理)\n  - [如何使用](#如何使用)\n  - [普通路由导航](#普通路由导航)\n  - [别名路由导航](#别名路由导航)\n    - [发送数据到别名路由](#发送数据到别名路由)\n    - [动态网页链接](#动态网页链接)\n    - [中间件](#中间件)\n  - [免context导航](#免context导航)\n    - [SnackBars](#SnackBars)\n    - [Dialogs](#dialogs)\n    - [BottomSheets](#bottomSheets)\n  - [嵌套导航](#嵌套导航)\n\n# 路由管理\n\n这是关于Getx在路由管理方面的完整解释。\n\n## 如何使用\n\n将此添加到你的pubspec.yaml文件中。\n\n```yaml\ndependencies:\n  get:\n```\n\n如果你要在没有context的情况下使用路由/SnackBars/Dialogs/BottomSheets，或者使用高级的Get API，你只需要在你的MaterialApp前面加上 \"Get\"，就可以把它变成GetMaterialApp，享受吧!\n\n```dart\nGetMaterialApp( // Before: MaterialApp(\n  home: MyHome(),\n)\n```\n\n## 普通路由导航\n\n导航到新的页面。\n\n```dart\nGet.to(NextScreen());\n```\n\n关闭SnackBars、Dialogs、BottomSheets或任何你通常会用Navigator.pop(context)关闭的东西。\n\n```dart\nGet.back();\n```\n\n进入下一个页面，但没有返回上一个页面的选项（用于SplashScreens，登录页面等）。\n\n```dart\nGet.off(NextScreen());\n```\n\n进入下一个界面并取消之前的所有路由（在购物车、投票和测试中很有用）。\n\n```dart\nGet.offAll(NextScreen());\n```\n\n要导航到下一条路由，并在返回后立即接收或更新数据。\n\n```dart\nvar data = await Get.to(Payment());\n```\n\n在另一个页面上，发送前一个路由的数据。\n\n```dart\nGet.back(result: 'success');\n```\n\n并使用它，例：\n\n```dart\nif(data == 'success') madeAnything();\n```\n\n你不想学习我们的语法吗？\n只要把 Navigator（大写）改成 navigator（小写），你就可以拥有标准导航的所有功能，而不需要使用context，例如：\n\n```dart\n\n// 默认的Flutter导航\nNavigator.of(context).push(\n  context,\n  MaterialPageRoute(\n    builder: (BuildContext context) {\n      return HomePage();\n    },\n  ),\n);\n\n// 使用Flutter语法获得，而不需要context。\nnavigator.push(\n  MaterialPageRoute(\n    builder: (_) {\n      return HomePage();\n    },\n  ),\n);\n\n// get语法 (这要好得多)\nGet.to(HomePage());\n\n\n```\n\n## 别名路由导航\n\n- 如果你喜欢用别名路由导航，Get也支持。\n\n导航到下一个页面\n\n```dart\nGet.toNamed(\"/NextScreen\");\n```\n\n浏览并删除前一个页面。\n\n```dart\nGet.offNamed(\"/NextScreen\");\n```\n\n浏览并删除所有以前的页面。\n\n```dart\nGet.offAllNamed(\"/NextScreen\");\n```\n\n要定义路由，使用GetMaterialApp。\n\n```dart\nvoid main() {\n  runApp(\n    GetMaterialApp(\n      initialRoute: '/',\n      getPages: [\n        GetPage(name: '/', page: () => MyHomePage()),\n        GetPage(name: '/second', page: () => Second()),\n        GetPage(\n          name: '/third',\n          page: () => Third(),\n          transition: Transition.zoom  \n        ),\n      ],\n    )\n  );\n}\n```\n\n要处理到未定义路线的导航（404错误），可以在GetMaterialApp中定义unknownRoute页面。\n\n```dart\nvoid main() {\n  runApp(\n    GetMaterialApp(\n      unknownRoute: GetPage(name: '/notfound', page: () => UnknownRoutePage()),\n      initialRoute: '/',\n      getPages: [\n        GetPage(name: '/', page: () => MyHomePage()),\n        GetPage(name: '/second', page: () => Second()),\n      ],\n    )\n  );\n}\n```\n\n### 发送数据到别名路由\n\n只要发送你想要的参数即可。Get在这里接受任何东西，无论是一个字符串，一个Map，一个List，甚至一个类的实例。\n\n```dart\nGet.toNamed(\"/NextScreen\", arguments: 'Get is the best');\n```\n\n在你的类或控制器上：\n\n```dart\nprint(Get.arguments);\n//print out: Get is the best\n```\n\n### 动态网页链接\n\nGet提供高级动态URL，就像在Web上一样。Web开发者可能已经在Flutter上想要这个功能了，Get也解决了这个问题。\n\n```dart\nGet.offAllNamed(\"/NextScreen?device=phone&id=354&name=Enzo\");\n```\n\n在你的controller/bloc/stateful/stateless类上：\n\n```dart\nprint(Get.parameters['id']);\n// out: 354\nprint(Get.parameters['name']);\n// out: Enzo\n```\n\n你也可以用Get轻松接收NamedParameters。\n\n```dart\nvoid main() {\n  runApp(\n    GetMaterialApp(\n      initialRoute: '/',\n      getPages: [\n      GetPage(\n        name: '/',\n        page: () => MyHomePage(),\n      ),\n      GetPage(\n        name: '/profile/',\n        page: () => MyProfile(),\n      ),\n       //你可以为有参数的路由定义一个不同的页面，也可以为没有参数的路由定义一个不同的页面，但是你必须在不接收参数的路由上使用斜杠\"/\"，就像上面说的那样。\n       GetPage(\n        name: '/profile/:user',\n        page: () => UserProfile(),\n      ),\n      GetPage(\n        name: '/third',\n        page: () => Third(),\n        transition: Transition.cupertino  \n      ),\n     ],\n    )\n  );\n}\n```\n\n发送别名路由数据\n\n```dart\nGet.toNamed(\"/second/34954\");\n```\n\n在第二个页面上，通过参数获取数据\n\n```dart\nprint(Get.parameters['user']);\n// out: 34954\n```\n\n或像这样发送多个参数\n\n```dart\nGet.toNamed(\"/profile/34954?flag=true\");\n```\n\n在第二个屏幕上，通常按参数获取数据\n\n```dart\nprint(Get.parameters['user']);\nprint(Get.parameters['flag']);\n// out: 34954 true\n```\n\n\n现在，你需要做的就是使用Get.toNamed()来导航你的别名路由，不需要任何context(你可以直接从你的BLoC或Controller类中调用你的路由)，当你的应用程序被编译到web时，你的路由将出现在URL中。\n\n### 中间件\n\n如果你想通过监听Get事件来触发动作，你可以使用routingCallback来实现。\n\n```dart\nGetMaterialApp(\n  routingCallback: (routing) {\n    if(routing.current == '/second'){\n      openAds();\n    }\n  }\n)\n```\n\n如果你没有使用GetMaterialApp，你可以使用手动API来附加Middleware观察器。\n\n```dart\nvoid main() {\n  runApp(\n    MaterialApp(\n      onGenerateRoute: Router.generateRoute,\n      initialRoute: \"/\",\n      navigatorKey: Get.key,\n      navigatorObservers: [\n        GetObserver(MiddleWare.observer), // HERE !!!\n      ],\n    ),\n  );\n}\n```\n\n创建一个MiddleWare类\n\n```dart\nclass MiddleWare {\n  static observer(Routing routing) {\n    ///你除了可以监听路由外，还可以监听每个页面上的SnackBars、Dialogs和Bottomsheets。\n    if (routing.current == '/second' && !routing.isSnackbar) {\n      Get.snackbar(\"Hi\", \"You are on second route\");\n    } else if (routing.current =='/third'){\n      print('last route called');\n    }\n  }\n}\n```\n\n现在，在你的代码上使用Get：\n\n```dart\nclass First extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        leading: IconButton(\n          icon: Icon(Icons.add),\n          onPressed: () {\n            Get.snackbar(\"hi\", \"i am a modern snackbar\");\n          },\n        ),\n        title: Text('First Route'),\n      ),\n      body: Center(\n        child: ElevatedButton(\n          child: Text('Open route'),\n          onPressed: () {\n            Get.toNamed(\"/second\");\n          },\n        ),\n      ),\n    );\n  }\n}\n\nclass Second extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        leading: IconButton(\n          icon: Icon(Icons.add),\n          onPressed: () {\n            Get.snackbar(\"hi\", \"i am a modern snackbar\");\n          },\n        ),\n        title: Text('second Route'),\n      ),\n      body: Center(\n        child: ElevatedButton(\n          child: Text('Open route'),\n          onPressed: () {\n            Get.toNamed(\"/third\");\n          },\n        ),\n      ),\n    );\n  }\n}\n\nclass Third extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: Text(\"Third Route\"),\n      ),\n      body: Center(\n        child: ElevatedButton(\n          onPressed: () {\n            Get.back();\n          },\n          child: Text('Go back!'),\n        ),\n      ),\n    );\n  }\n}\n```\n\n## 免context导航\n\n### SnackBars\n\n用Flutter创建一个简单的SnackBar，你必须获得Scaffold的context，或者你必须使用一个GlobalKey附加到你的Scaffold上。\n\n```dart\nfinal snackBar = SnackBar(\n  content: Text('Hi!'),\n  action: SnackBarAction(\n    label: 'I am a old and ugly snackbar :(',\n    onPressed: (){}\n  ),\n);\n// 在小组件树中找到脚手架并使用它显示一个SnackBars。\nScaffold.of(context).showSnackBar(snackBar);\n```\n\n用Get：\n\n```dart\nGet.snackbar('Hi', 'i am a modern snackbar');\n```\n\n有了Get，你所要做的就是在你代码的任何地方调用你的Get.snackbar，或者按照你的意愿定制它。\n\n```dart\nGet.snackbar(\n  \"Hey i'm a Get SnackBar!\", // title\n  \"It's unbelievable! I'm using SnackBar without context, without boilerplate, without Scaffold, it is something truly amazing!\", // message\n  icon: Icon(Icons.alarm),\n  shouldIconPulse: true,\n  onTap:(){},\n  barBlur: 20,\n  isDismissible: true,\n  duration: Duration(seconds: 3),\n);\n\n\n  ////////// ALL FEATURES //////////\n  //     Color colorText,\n  //     Duration duration,\n  //     SnackPosition snackPosition,\n  //     Widget titleText,\n  //     Widget messageText,\n  //     bool instantInit,\n  //     Widget icon,\n  //     bool shouldIconPulse,\n  //     double maxWidth,\n  //     EdgeInsets margin,\n  //     EdgeInsets padding,\n  //     double borderRadius,\n  //     Color borderColor,\n  //     double borderWidth,\n  //     Color backgroundColor,\n  //     Color leftBarIndicatorColor,\n  //     List<BoxShadow> boxShadows,\n  //     Gradient backgroundGradient,\n  //     TextButton mainButton,\n  //     OnTap onTap,\n  //     bool isDismissible,\n  //     bool showProgressIndicator,\n  //     AnimationController progressIndicatorController,\n  //     Color progressIndicatorBackgroundColor,\n  //     Animation<Color> progressIndicatorValueColor,\n  //     SnackStyle snackStyle,\n  //     Curve forwardAnimationCurve,\n  //     Curve reverseAnimationCurve,\n  //     Duration animationDuration,\n  //     double barBlur,\n  //     double overlayBlur,\n  //     Color overlayColor,\n  //     Form userInputForm\n  ///////////////////////////////////\n```\n\n如果您喜欢传统的SnackBars，或者想从头开始定制，包括只添加一行(Get.snackbar使用了一个强制性的标题和信息)，您可以使用\n`Get.rawSnackbar();`它提供了建立Get.snackbar的RAW API。\n\n### Dialogs\n\n打开Dialogs：\n\n```dart\nGet.dialog(YourDialogWidget());\n```\n\n打开默认Dialogs：\n\n```dart\nGet.defaultDialog(\n  onConfirm: () => print(\"Ok\"),\n  middleText: \"Dialog made in 3 lines of code\"\n);\n```\n\n你也可以用Get.generalDialog代替showGeneralDialog。\n\n对于所有其他的FlutterDialogs小部件，包括cupertinos，你可以使用Get.overlayContext来代替context，并在你的代码中任何地方打开它。\n对于不使用Overlay的小组件，你可以使用Get.context。\n这两个context在99%的情况下都可以代替你的UIcontext，除了在没有导航context的情况下使用 inheritedWidget的情况。\n\n### BottomSheets\n\nGet.bottomSheet类似于showModalBottomSheet，但不需要context：\n\n```dart\nGet.bottomSheet(\n  Container(\n    child: Wrap(\n      children: <Widget>[\n        ListTile(\n          leading: Icon(Icons.music_note),\n          title: Text('Music'),\n          onTap: () {}\n        ),\n        ListTile(\n          leading: Icon(Icons.videocam),\n          title: Text('Video'),\n          onTap: () {},\n        ),\n      ],\n    ),\n  )\n);\n```\n\n## 嵌套导航\n\nGet让Flutter的嵌套导航更加简单。\n你不需要context，而是通过Id找到你的导航栈。\n\n- 注意：创建平行导航堆栈可能是危险的。理想的情况是不要使用NestedNavigators，或者尽量少用。如果你的项目需要它，请继续，但请记住，在内存中保持多个导航堆栈可能不是一个好主意(消耗RAM)。\n\n看看它有多简单:\n\n```dart\nNavigator(\n  key: Get.nestedKey(1), // create a key by index\n  initialRoute: '/',\n  onGenerateRoute: (settings) {\n    if (settings.name == '/') {\n      return GetPageRoute(\n        page: () => Scaffold(\n          appBar: AppBar(\n            title: Text(\"Main\"),\n          ),\n          body: Center(\n            child: TextButton(\n              color: Colors.blue,\n              onPressed: () {\n                Get.toNamed('/second', id:1); // navigate by your nested route by index\n              },\n              child: Text(\"Go to second\"),\n            ),\n          ),\n        ),\n      );\n    } else if (settings.name == '/second') {\n      return GetPageRoute(\n        page: () => Center(\n          child: Scaffold(\n            appBar: AppBar(\n              title: Text(\"Main\"),\n            ),\n            body: Center(\n              child:  Text(\"second\")\n            ),\n          ),\n        ),\n      );\n    }\n  }\n),\n```\n"
  },
  {
    "path": "documentation/zh_CN/state_management.md",
    "content": "- [状态管理](#状态管理)\n  - [响应式状态管理器](#响应式状态管理器)\n    - [优点](#优势)\n    - [声明一个响应式变量](#声明一个响应式变量)\n    - [使用视图中的值](#使用视图中的值)\n    - [什么时候重建](#什么时候重建)\n    - [可以使用.obs的地方](#可以使用.obs的地方)\n    - [关于List的说明](#关于List的说明)\n    - [为什么使用.value](#为什么使用.value)\n    - [Obx()](#obx)\n    - [Workers](#Workers)\n  - [简单状态管理器](#简单状态管理器)\n    - [优点](#优点)\n    - [用法](#用法)\n    - [如何处理controller](#如何处理controller)\n    - [无需StatefulWidgets](#无需StatefulWidgets)\n    - [为什么它存在](#为什么它存在)\n    - [其他使用方法](#其他使用方法)\n    - [唯一的ID](#唯一的ID)\n  - [与其他状态管理器混用](#与其他状态管理器混用)\n  - [GetBuilder vs GetX vs Obx vs MixinBuilder](#GetBuilder-vs-GetX-vs-Obx-vs-MixinBuilder)\n\n# 状态管理\n\n目前，Flutter有几种状态管理器。但是，它们中的大多数都涉及到使用ChangeNotifier来更新widget，这对于中大型应用的性能来说是一个糟糕的方法。你可以在Flutter官方文档中查到，[ChangeNotifier应该使用1个或最多2个监听器](https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html)，这使得它实际上无法用于任何中等或大型应用。\n\n其他的状态管理器也不错，但有其细微的差别。\n\n- BLoC非常安全和高效，但是对于初学者来说非常复杂，这使得人们无法使用Flutter进行开发。\n- MobX比BLoC更容易，而且是响应式的，几乎是完美的，但是你需要使用一个代码生成器，对于大型应用来说，这降低了生产力，因为你需要喝很多咖啡，直到你的代码在`flutter clean`之后再次准备好（这不是MobX的错，而是codegen真的很慢！）。\n- Provider使用InheritedWidget来传递相同的监听器，以此来解决上面报告的ChangeNotifier的问题，这意味着对其ChangeNotifier类的任何访问都必须在widget树内。\n\nGet并不是比任何其他状态管理器更好或更差，而是说你应该分析这些要点以及下面的要点来选择是只用Get，还是与其他状态管理器结合使用。Get不是其他状态管理器的敌人，因为Get是一个微框架，而不仅仅是一个状态管理器，它的状态管理功能既可以单独使用，也可以与其他状态管理器结合使用。\n\n## 响应式状态管理器\n\n响应式编程可能会让很多人感到陌生，因为它很复杂，但是GetX将响应式编程变得非常简单。\n\n- 你不需要创建StreamControllers.\n- 你不需要为每个变量创建一个StreamBuilder。\n- 你不需要为每个状态创建一个类。\n- 你不需要为一个初始值创建一个get。\n\n使用 Get 的响应式编程就像使用 setState 一样简单。\n\n让我们想象一下，你有一个名称变量，并且希望每次你改变它时，所有使用它的小组件都会自动刷新。\n\n这是你的计数变量：\n\n```dart\nvar name = 'Jonatas Borges';\n```\n\n要想让它变得可观察，你只需要在它的末尾加上\".obs\"。\n\n```dart\nvar name = 'Jonatas Borges'.obs;\n```\n\n就这么简单！\n\n我们把这个reactive-\".obs\"(ervables)变量称为 _Rx_ 。  \n\n我们做了什么？我们创建了一个 \"Stream \"的 \"String\"，分配了初始值 \"Jonatas Borges\"，我们通知所有使用 \"Jonatas Borges \"的widgets，它们现在 \"属于 \"这个变量，当_Rx_的值发生变化时，它们也要随之改变。\n\n这就是GetX **的** 魔力，这要归功于Dart的能力。\n\n但是，我们知道，一个`Widget`只有在函数里面才能改变，因为静态类没有 \"自动改变 \"的能力。\n\n你需要创建一个`StreamBuilder`，订阅这个变量来监听变化，如果你想在同一个范围内改变几个变量，就需要创建一个 \"级联 \"的嵌套`StreamBuilder`，对吧？\n\n不，你不需要一个`StreamBuilder`，但你对静态类的理解是对的。\n\n在视图中，当我们想改变一个特定的Widget时，我们通常有很多Flutter方式的模板。\n有了**GetX**，你也可以忘记这些模板代码了。\n\n`StreamBuilder( ... )`? `initialValue: ...`? `builder: ...`? 不，你只需要把这个变量放在`Obx()`这个Widget里面就可以了。\n\n```dart\nObx (() => Text (controller.name));\n```\n\n你只需记住 `Obx(()=>`\n\n你只需将Widget通过一个箭头函数传递给 `Obx()`( _Rx_ 的 \"观察者\")。\n\n`Obx`是相当聪明的，只有当`controller.name`的值发生变化时才会改变。\n\n如果`name`是`\"John\"`，你把它改成了`\"John\"`（`name.value=\"John\"`），因为它和之前的`value`是一样的，所以界面上不会有任何变化，而`Obx`为了节省资源，会直接忽略新的值，不重建Widget。**这是不是很神奇**？\n\n> 那么，如果我在一个`Obx`里有5个 _Rx_ （可观察的）变量呢？\n\n当其中**任何**一个变量发生变化时，它就会更新。\n\n> 如果我在一个类中有 30 个变量，当我更新其中一个变量时，它会更新该类中**所有**的变量吗？\n\n不会，只会更新使用那个 _Rx_ 变量的**特定 Widget**。\n\n所以，只有当 _Rx_ 变量的值发生变化时，**GetX**才会更新界面。\n\n```\nfinal isOpen = false.obs;\n\n//什么都不会发生......相同的值。\nvoid onButtonTap() => isOpen.value=false;\n```\n### 优势\n\n**当你需要对更新的内容进行**精细的控制时，**GetX()** 可以帮助你。\n\n如果你不需要 \"unique IDs\"，比如当你执行一个操作时，你的所有变量都会被修改，那么就使用`GetBuilder`。\n因为它是一个简单的状态更新器(以块为单位，比如`setState()`)，只用几行代码就能完成。\n它做得很简单，对CPU的影响最小，只是为了完成一个单一的目的（一个_State_ Rebuild），并尽可能地花费最少的资源。\n\n如果你需要一个**强大的**状态管理器，用**GetX**是不会错的。\n\n它不能和变量一起工作，除了 __flows__ ，它里面的东西本质都是`Streams`。\n你可以将 _rxDart_ 与它结合使用，因为所有的东西都是`Streams`。\n你可以监听每个\" _Rx_ 变量 \"的 \"事件\"。\n因为里面的所有东西都是 \"Streams\"。\n\n这实际上是一种 _BLoC_ 方法，比 _MobX_ 更容易，而且没有代码生成器或装饰。\n你可以把**任何东西**变成一个 _\"Observable\"_ ，只需要在它末尾加上`.obs`。\n\n### 最高性能\n\n除了有一个智能的算法来实现最小化的重建，**GetX**还使用了比较器以确保状态已经改变。\n\n如果你的应用程序中遇到错误，并发送重复的状态变更，**GetX**将确保它不会崩溃。\n\n使用**GetX**，只有当`value`改变时，状态才会改变。\n这就是**GetX**，和使用MobX _的_ `computed`的主要区别。\n当加入两个 __observable__ ，其中一个发生变化时，该 _observable_ 的监听器也会发生变化。\n\n使用**GetX**，如果你连接了两个变量，`GetX()`(类似于`Observer()`)只有在它的状态真正变化时才会重建。\n\n### 声明一个响应式变量\n\n你有3种方法可以把一个变量变成是 \"可观察的\"。\n\n\n1 - 第一种是使用 **`Rx{Type}`**。\n\n```dart\n// 建议使用初始值，但不是强制性的\nfinal name = RxString('');\nfinal isLogged = RxBool(false);\nfinal count = RxInt(0);\nfinal balance = RxDouble(0.0);\nfinal items = RxList<String>([]);\nfinal myMap = RxMap<String, int>({});\n```\n\n2 - 第二种是使用 **`Rx`**，规定泛型 `Rx<Type>`。\n\n```dart\nfinal name = Rx<String>('');\nfinal isLogged = Rx<Bool>(false);\nfinal count = Rx<Int>(0);\nfinal balance = Rx<Double>(0.0);\nfinal number = Rx<Num>(0)\nfinal items = Rx<List<String>>([]);\nfinal myMap = Rx<Map<String, int>>({});\n\n// 自定义类 - 可以是任何类\nfinal user = Rx<User>();\n```\n\n3 - 第三种更实用、更简单、更可取的方法，只需添加 **`.obs`** 作为`value`的属性。\n\n```dart\nfinal name = ''.obs;\nfinal isLogged = false.obs;\nfinal count = 0.obs;\nfinal balance = 0.0.obs;\nfinal number = 0.obs;\nfinal items = <String>[].obs;\nfinal myMap = <String, int>{}.obs;\n\n// 自定义类 - 可以是任何类\nfinal user = User().obs;\n```\n\n##### 有一个反应的状态，很容易。\n\n我们知道， _Dart_ 现在正朝着 _null safety_ 的方向发展。\n为了做好准备，从现在开始，你应该总是用一个**初始值**来开始你的 _Rx_ 变量。\n\n> 用**GetX**将一个变量转化为一个 _observable_ + _initial value_ 是最简单，也是最实用的方法。\n\n你只需在变量的末尾添加一个\"`.obs`\"，即可把它变成可观察的变量，\n然后它的`.value`就是 _初始值_ )。\n\n\n### 使用视图中的值\n\n```dart\n// controller\nfinal count1 = 0.obs;\nfinal count2 = 0.obs;\nint get sum => count1.value + count2.value;\n```\n\n```dart\n// 视图\nGetX<Controller>(\n  builder: (controller) {\n    print(\"count 1 rebuild\");\n    return Text('${controller.count1.value}');\n  },\n),\nGetX<Controller>(\n  builder: (controller) {\n    print(\"count 2 rebuild\");\n    return Text('${controller.count2.value}');\n  },\n),\nGetX<Controller>(\n  builder: (controller) {\n    print(\"count 3 rebuild\");\n    return Text('${controller.sum}');\n  },\n),\n```\n\n如果我们把`count1.value++`递增，就会打印出来：\n- `count 1 rebuild` \n- `count 3 rebuild`\n\n\n如果我们改变`count2.value++`，就会打印出来。\n- `count 2 rebuild` \n- `count 3 rebuild`\n\n因为`count2.value`改变了，`sum`的结果现在是`2`。\n\n- 注意：默认情况下，第一个事件将重建小组件，即使是相同的`值`。\n 这种行为是由于布尔变量而存在的。\n\n想象一下你这样做。\n\n```dart\nvar isLogged = false.obs;\n```\n\n然后，你检查用户是否 \"登录\"，以触发`ever`的事件。\n\n```dart\n@override\nonInit(){\n  ever(isLogged, fireRoute);\n  isLogged.value = await Preferences.hasToken();\n}\n\nfireRoute(logged) {\n  if (logged) {\n   Get.off(Home());\n  } else {\n   Get.off(Login());\n  }\n}\n```\n\n如果 \"hasToken \"是 \"false\"，\"isLogged \"就不会有任何变化，所以 \"ever() \"永远不会被调用。\n为了避免这种问题，_observable_的第一次变化将总是触发一个事件，即使它包含相同的`.value`。\n\n如果你想删除这种行为，你可以使用：\n`isLogged.firstRebuild = false;`。\n\n### 什么时候重建\n\n此外，Get还提供了精细的状态控制。你可以根据特定的条件对一个事件进行条件控制（比如将一个对象添加到List中）。\n\n```dart\n// 第一个参数：条件，必须返回true或false。\n// 第二个参数：如果条件为真，则为新的值。\nlist.addIf(item < limit, item);\n```\n\n没有装饰，没有代码生成器，没有复杂的程序: 爽歪歪！\n\n你知道Flutter的计数器应用吗？你的Controller类可能是这样的。\n\n```dart\nclass CountController extends GetxController {\n  final count = 0.obs;\n}\n```\n\n用一个简单的。\n\n```dart\ncontroller.count.value++\n```\n\n你可以在你的UI中更新计数器变量，不管它存储在哪里。\n\n### 可以使用.obs的地方\n\n你可以在 obs 上转换任何东西，这里有两种方法：\n\n* 可以将你的类值转换为 obs\n```dart\nclass RxUser {\n  final name = \"Camila\".obs;\n  final age = 18.obs;\n}\n```\n\n* 或者可以将整个类转换为一个可观察的类。\n```dart\nclass User {\n  User({String name, int age});\n  var name;\n  var age;\n}\n\n//实例化时。\nfinal user = User(name: \"Camila\", age: 18).obs;\n```\n\n### 关于List的说明\n\nList和它里面的对象一样，是完全可以观察的。这样一来，如果你在List中添加一个值，它会自动重建使用它的widget。\n\n你也不需要在List中使用\".value\"，神奇的dart api允许我们删除它。\n不幸的是，像String和int这样的原始类型不能被扩展，使得.value的使用是强制性的，但是如果你使用get和setter来处理这些类型，这将不是一个问题。\n\n```dart\n// controller\nfinal String title = 'User Info:'.obs\nfinal list = List<User>().obs;\n\n// view\nText(controller.title.value), // 字符串后面需要有.value。\nListView.builder (\n  itemCount: controller.list.length // List不需要它\n)\n```\n\n当你在使自己的类可观察时，有另外一种方式来更新它们：\n\n```dart\n// model\n// 我们将使整个类成为可观察的，而不是每个属性。\nclass User{\n    User({this.name = '', this.age = 0});\n    String name;\n    int age;\n}\n\n// controller\nfinal user = User().obs;\n//当你需要更新user变量时。\nuser.update( (user) { // 这个参数是你要更新的类本身。\n    user.name = 'Jonny';\n    user.age = 18;\n});\n// 更新user变量的另一种方式。\nuser(User(name: 'João', age: 35));\n\n// view\nObx(()=> Text(\"Name ${user.value.name}: Age: ${user.value.age}\"));\n// 你也可以不使用.value来访问模型值。\nuser().name; // 注意是user变量，而不是类变量（首字母是小写的）。\n```\n\n你可以使用 \"assign \"和\" assignAll \"。\n\"assign \"会清除你的List，并添加一个单个对象。\n\"assignAll \"将清除现有的List，并添加任何可迭代对象。\n\n### 为什么使用.value\n\n我们可以通过一个简单的装饰和代码生成器来消除使用\"String \"和 \"int \"的值的义务，但这个库的目的正是为了避免外部依赖。我们希望提供一个准备好的编程的环境（路由、依赖和状态的管理），以一种简单、轻量级和高性能的方式，而不需要一个外部包。\n\n你可以在你的pubspec中添加3个字母（get）和一个冒号，然后开始编程。从路由管理到状态管理，所有的解决方案都是默认的，目的是为了方便、高效和高性能。\n\n这个库的总大小还不如一个状态管理器，尽管它是一个完整的解决方案。\n\n如果你被`.value`困扰，喜欢代码生成器，MobX是一个很好的选择，也可以和Get一起使用。对于那些想在pubspec中添加一个单一的依赖，然后开始编程，而不用担心一个包的版本与另一个包不兼容，也不用担心状态更新的错误来自于状态管理器或依赖，还是不想担心控制器的可用性，get都是刚刚好。\n\n如果你对MobX代码生成器或者BLoC模板熟悉，你可以直接用Get来做路由，而忘记它有状态管理器。如果有一个项目有90多个控制器，MobX代码生成器在标准机器上进行Flutter Clean后，需要30多分钟才能完成任务。如果你的项目有5个、10个、15个控制器，任何一个状态管理器都能很好的满足你。如果你的项目大得离谱，代码生成器对你来说是个问题，但你已经获得了Get这个解决方案。\n\n显然，如果有人想为项目做贡献，创建一个代码生成器，或者类似的东西，我将在这个readme中链接，作为一个替代方案，我的需求并不是所有开发者的需求，但现在我要说的是，已经有很好的解决方案，比如MobX。\n\n### Obx()\n\n在Get中使用Bindings的类型是不必要的。你可以使用Obx widget代替GetX，GetX只接收创建widget的匿名函数。\n如果你不使用类型，你将需要有一个控制器的实例来使用变量，或者使用`Get.find<Controller>()`.value或Controller.to.value来检索值。\n\n### Workers\n\nWorkers将协助你在事件发生时触发特定的回调。\n\n```dart\n///每次`count1`变化时调用。\never(count1, (_) => print(\"$_ has been changed\"));\n\n///只有在变量$_第一次被改变时才会被调用。\nonce(count1, (_) => print(\"$_ was changed once\"));\n\n///防DDos - 每当用户停止输入1秒时调用，例如。\ndebounce(count1, (_) => print(\"debouce$_\"), time: Duration(seconds: 1));\n\n///忽略1秒内的所有变化。\ninterval(count1, (_) => print(\"interval $_\"), time: Duration(seconds: 1));\n```\n所有Workers(除 \"debounce \"外)都有一个名为 \"condition\"的参数，它可以是一个 \"bool \"或一个返回 \"bool \"的回调。\n这个`condition`定义了`callback`函数何时执行。\n\n所有worker都会返回一个`Worker`实例，你可以用它来取消（通过`dispose()`）worker。\n\n- **`ever`**\n 每当 _Rx_ 变量发出一个新的值时，就会被调用。\n\n- **`everAll`**\n 和 \"ever \"很像，但它需要一个 _Rx_ 值的 \"List\"，每次它的变量被改变时都会被调用。就是这样。\n\n\n- **`once`**\n'once'只在变量第一次被改变时被调用。\n\n- **`debounce`**\n'debounce'在搜索函数中非常有用，你只希望API在用户完成输入时被调用。如果用户输入 \"Jonny\"，你将在API中进行5次搜索，分别是字母J、o、n、n和y。使用Get不会发生这种情况，因为你将有一个 \"debounce \"Worker，它只会在输入结束时触发。\n\n- **`interval`**\n'interval'与debouce不同，debouce如果用户在1秒内对一个变量进行了1000次修改，他将在规定的计时器（默认为800毫秒）后只发送最后一次修改。Interval则会忽略规定时间内的所有用户操作。如果你发送事件1分钟，每秒1000个，那么当用户停止DDOS事件时，debounce将只发送最后一个事件。建议这样做是为了避免滥用，在用户可以快速点击某样东西并获得一些好处的功能中（想象一下，用户点击某样东西可以赚取硬币，如果他在同一分钟内点击300次，他就会有300个硬币，使用间隔，你可以设置时间范围为3秒，无论是点击300次或100万次，1分钟内他最多获得20个硬币）。debounce适用于防DDOS，适用于搜索等功能，每次改变onChange都会调用你的api进行查询。Debounce会等待用户停止输入名称，进行请求。如果在上面提到的投币场景中使用它，用户只会赢得1个硬币，因为只有当用户 \"暂停 \"到既定时间时，它才会被执行。\n\n- 注意：Worker应该总是在启动Controller或Class时使用，所以应该总是在onInit(推荐)、Class构造函数或StatefulWidget的initState(大多数情况下不推荐这种做法，但应该不会有任何副作用)。\n\n## 简单状态管理器\n\nGet有一个极其轻巧简单的状态管理器，它不使用ChangeNotifier，可以满足特别是对Flutter新手的需求，而且不会给大型应用带来问题。\n\nGetBuilder正是针对多状态控制的。想象一下，你在购物车中添加了30个产品，你点击删除一个，同时List更新了，价格更新了，购物车中的徽章也更新为更小的数字。这种类型的方法使GetBuilder成为杀手锏，因为它将状态分组并一次性改变，而无需为此进行任何 \"计算逻辑\"。GetBuilder就是考虑到这种情况而创建的，因为对于短暂的状态变化，你可以使用setState，而不需要状态管理器。\n\n这样一来，如果你想要一个单独的控制器，你可以为其分配ID，或者使用GetX。这取决于你，记住你有越多的 \"单独 \"部件，GetX的性能就越突出，而当有多个状态变化时，GetBuilder的性能应该更优越。\n\n### 优点\n\n1. 只更新需要的小部件。\n\n2. 不使用changeNotifier，状态管理器使用较少的内存（接近0mb）。\n\n3. 忘掉StatefulWidget! 使用Get你永远不会需要它。对于其他的状态管理器，你可能需要使用StatefulWidget来获取你的Provider、BLoC、MobX控制器等的实例。但是你有没有停下来想一想，你的appBar，你的脚手架，以及你的类中的大部分widget都是无状态的？那么如果你只能保存有状态的Widget的状态，为什么要保存整个类的状态呢？Get也解决了这个问题。创建一个无状态类，让一切都成为无状态。如果你需要更新单个组件，就用GetBuilder把它包起来，它的状态就会被维护。\n\n4. 真正的解耦你的项目! 控制器一定不要在你的UI中，把你的TextEditController，或者你使用的任何控制器放在你的Controller类中。\n\n5. 你是否需要触发一个事件来更新一个widget，一旦它被渲染？GetBuilder有一个属性 \"initState\"，就像StatefulWidget一样，你可以从你的控制器中调用事件，直接从控制器中调用，不需要再在你的initState中放置事件。\n\n6. 你是否需要触发一个动作，比如关闭流、定时器等？GetBuilder也有dispose属性，只要该widget被销毁，你就可以调用事件。\n\n7. 仅在必要时使用流。你可以在你的控制器里面正常使用你的StreamControllers，也可以正常使用StreamBuilder，但是请记住，一个流消耗合理的内存，响应式编程很美，但是你不应该滥用它。30个流同时打开会比changeNotifier更糟糕（而且changeNotifier非常糟糕）。\n\n8. 更新widgets而不需要为此花费ram。Get只存储GetBuilder的创建者ID，必要时更新该GetBuilder。get ID存储在内存中的消耗非常低，即使是成千上万的GetBuilders。当你创建一个新的GetBuilder时，你实际上是在共享拥有创建者ID的GetBuilder的状态。不会为每个GetBuilder创建一个新的状态，这为大型应用节省了大量的内存。基本上你的应用程序将是完全无状态的，而少数有状态的Widgets(在GetBuilder内)将有一个单一的状态，因此更新一个状态将更新所有的状态。状态只是一个。\n\n9. Get是全知全能的，在大多数情况下，它很清楚地知道从内存中取出一个控制器的时机，你不需要担心什么时候移除一个控制器，Get知道最佳的时机。\n\n### 用法\n\n```dart\n// 创建控制器类并扩展GetxController。\nclass Controller extends GetxController {\n  int counter = 0;\n  void increment() {\n    counter++;\n    update(); // 当调用增量时，使用update()来更新用户界面上的计数器变量。\n  }\n}\n// 在你的Stateless/Stateful类中，当调用increment时，使用GetBuilder来更新Text。\nGetBuilder<Controller>(\n  init: Controller(), // 首次启动\n  builder: (_) => Text(\n    '${_.counter}',\n  ),\n)\n//只在第一次时初始化你的控制器。第二次使用ReBuilder时，不要再使用同一控制器。一旦将控制器标记为 \"init \"的部件部署完毕，你的控制器将自动从内存中移除。你不必担心这个问题，Get会自动做到这一点，只是要确保你不要两次启动同一个控制器。\n```\n\n**完成！**\n\n- 你已经学会了如何使用Get管理状态。\n\n- 注意：你可能想要一个更大的规模，而不是使用init属性。为此，你可以创建一个类并扩展Bindings类，并在其中添加将在该路由中创建的控制器。控制器不会在那个时候被创建，相反，这只是一个声明，这样你第一次使用Controller时，Get就会知道去哪里找。Get会保持懒加载，当不再需要Controller时，会自动移除它们。请看pub.dev的例子来了解它是如何工作的。\n\n如果你导航了很多路由，并且需要之前使用的Controller中的数据，你只需要再用一次GetBuilder（没有init）。\n\n```dart\nclass OtherClass extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      body: Center(\n        child: GetBuilder<Controller>(\n          builder: (s) => Text('${s.counter}'),\n        ),\n      ),\n    );\n  }\n\n```\n\n如果你需要在许多其他地方使用你的控制器，并且在GetBuilder之外，只需在你的控制器中创建一个get，就可以轻松地拥有它。(或者使用`Get.find<Controller>()`)\n\n```dart\nclass Controller extends GetxController {\n\n  /// 你不需要这个，我推荐使用它只是为了方便语法。\n  /// 用静态方法：Controller.to.increment()。\n  /// 没有静态方法的情况下：Get.find<Controller>().increment();\n  /// 使用这两种语法在性能上没有区别，也没有任何副作用。一个不需要类型，另一个IDE会自动完成。\n  static Controller get to => Get.find(); // 添加这一行\n\n  int counter = 0;\n  void increment() {\n    counter++;\n    update();\n  }\n}\n```\n\n然后你可以直接访问你的控制器，这样：\n\n```dart\nFloatingActionButton(\n  onPressed: () {\n    Controller.to.increment(),\n  } // 是不是贼简单！\n  child: Text(\"${Controller.to.counter}\"),\n),\n```\n\n当你按下FloatingActionButton时，所有监听'counter'变量的widget都会自动更新。\n\n### 如何处理controller\n\n比方说，我们有这样的情况。\n\n`Class a => Class B (has controller X) => Class C (has controller X)`\n\n在A类中，控制器还没有进入内存，因为你还没有使用它（Get是懒加载）。在类B中，你使用了控制器，并且它进入了内存。在C类中，你使用了与B类相同的控制器，Get会将控制器B的状态与控制器C共享，同一个控制器还在内存中。如果你关闭C屏和B屏，Get会自动将控制器X从内存中移除，释放资源，因为a类没有使用该控制器。如果你再次导航到B，控制器X将再次进入内存，如果你没有去C类，而是再次回到a类，Get将以同样的方式将控制器从内存中移除。如果类C没有使用控制器，你把类B从内存中移除，就没有类在使用控制器X，同样也会被处理掉。唯一能让Get乱了阵脚的例外情况，是如果你意外地从路由中删除了B，并试图使用C中的控制器，在这种情况下，B中的控制器的创建者ID被删除了，Get被设计为从内存中删除每一个没有创建者ID的控制器。如果你打算这样做，在B类的GetBuilder中添加 \"autoRemove: false \"标志，并在C类的GetBuilder中使用adopID = true；\n\n### 无需StatefulWidgets\n\n使用StatefulWidgets意味着不必要地存储整个界面的状态，甚至因为如果你需要最小化地重建一个widget，你会把它嵌入一个Consumer/Observer/BlocProvider/GetBuilder/GetX/Obx中，这将是另一个StatefulWidget。\nStatefulWidget类是一个比StatelessWidget大的类，它将分配更多的RAM，只使用一两个类之间可能不会有明显的区别，但当你有100个类时，它肯定会有区别!\n除非你需要使用混合器，比如TickerProviderStateMixin，否则完全没有必要使用StatefulWidget与Get。\n\n你可以直接从GetBuilder中调用StatefulWidget的所有方法。\n例如，如果你需要调用initState()或dispose()方法，你可以直接调用它们。\n\n```dart\nGetBuilder<Controller>(\n  initState: (_) => Controller.to.fetchApi(),\n  dispose: (_) => Controller.to.closeStreams(),\n  builder: (s) => Text('${s.username}'),\n),\n```\n\n比这更好的方法是直接从控制器中使用onInit()和onClose()方法。\n\n```dart\n@override\nvoid onInit() {\n  fetchApi();\n  super.onInit();\n}\n```\n\n- 注意：如果你想在控制器第一次被调用的那一刻启动一个方法，你不需要为此使用构造函数，使用像Get这样面向性能的包，这样做反而是糟糕的做法，因为它偏离了控制器被创建或分配的逻辑（如果你创建了这个控制器的实例，构造函数会立即被调用，你会在控制器还没有被使用之前就填充了一个控制器，你在没有被使用的情况下就分配了内存，这绝对违背这个库的原则）。onInit();和onClose();方法就是为此而创建的，它们会在Controller被创建，或者第一次使用时被调用，这取决于你是否使用Get.lazyPut。例如，如果你想调用你的API来填充数据，你可以忘掉老式的initState/dispose方法，只需在onInit中开始调用api，如果你需要执行任何命令，如关闭流，使用onClose()来实现。\n\n### 为什么它存在\n\n这个包的目的正是为了给你提供一个完整的解决方案，用于导航路线，管理依赖和状态，使用尽可能少的依赖，高度解耦。Get将所有高低级别的Flutter API都纳入自身，以确保你在工作中尽可能减少耦合。我们将所有的东西集中在一个包中，以确保你在你的项目中没有任何形式的耦合。这样一来，你就可以只在视图中放置小组件，而让你的团队中负责业务逻辑的那部分人自由地工作，不需要依赖视图中的任何元素来处理业务逻辑。这样就提供了一个更加干净的工作环境，这样你的团队中的一部分人只用widget工作，而不用担心将数据发送到你的controller，你的团队中的一部分人只用业务逻辑工作，而不依赖于视图的任何元素。\n\n所以为了简化这个问题。\n你不需要在initState中调用方法，然后通过参数发送给你的控制器，也不需要使用你的控制器构造函数，你有onInit()方法，在合适的时间被调用，以启动你的服务。\n你不需要调用设备，你有onClose()方法，它将在确切的时刻被调用，当你的控制器不再需要时，将从内存中删除。这样一来，只给widget留下视图，不要从中进行任何形式的业务逻辑。\n\n不要在GetxController里面调用dispose方法，它不会有任何作用，记住控制器不是Widget，你不应该 \"dispose \"它，它会被Get自动智能地从内存中删除。如果你在上面使用了任何流，想关闭它，只要把它插入到close方法中就可以了。例如\n\n```dart\nclass Controller extends GetxController {\n  StreamController<User> user = StreamController<User>();\n  StreamController<String> name = StreamController<String>();\n\n  ///关闭流用onClose方法，而不是dispose\n  @override\n  void onClose() {\n    user.close();\n    name.close();\n    super.onClose();\n  }\n}\n```\n\n控制器的生命周期。\n\n- onInit()是创建控制器的地方。\n- onClose()，关闭控制器，为删除方法做准备。\n- deleted: 你不能访问这个API，因为它实际上是将控制器从内存中删除。它真的被删除了，不留任何痕迹。\n\n### 其他使用方法\n\n你可以直接在GetBuilder值上使用Controller实例。\n\n```dart\nGetBuilder<Controller>(\n  init: Controller(),\n  builder: (value) => Text(\n    '${value.counter}', //here\n  ),\n),\n```\n\n你可能还需要在GetBuilder之外的控制器实例，你可以使用这些方法来实现。\n\n```dart\nclass Controller extends GetxController {\n  static Controller get to => Get.find();\n[...]\n}\n//view\nGetBuilder<Controller>(  \n  init: Controller(), // 每个控制器只用一次\n  builder: (_) => Text(\n    '${Controller.to.counter}', //here\n  )\n),\n```\n\n或者\n\n```dart\nclass Controller extends GetxController {\n // static Controller get to => Get.find(); // with no static get\n[...]\n}\n// on stateful/stateless class\nGetBuilder<Controller>(  \n  init: Controller(), // 每个控制器只用一次\n  builder: (_) => Text(\n    '${Get.find<Controller>().counter}', //here\n  ),\n),\n```\n\n- 你可以使用 \"非规范 \"的方法来做这件事。如果你正在使用一些其他的依赖管理器，比如get_it、modular等，并且只想交付控制器实例，你可以这样做。\n\n```dart\nController controller = Controller();\n[...]\nGetBuilder<Controller>(\n  init: controller, //here\n  builder: (_) => Text(\n    '${controller.counter}', // here\n  ),\n),\n\n```\n\n### 唯一的ID\n\n如果你想用GetBuilder完善一个widget的更新控件，你可以给它们分配唯一的ID。\n\n```dart\nGetBuilder<Controller>(\n  id: 'text', //这里\n  init: Controller(), // 每个控制器只用一次\n  builder: (_) => Text(\n    '${Get.find<Controller>().counter}', //here\n  ),\n),\n```\n\n并更新它：\n\n```dart\nupdate(['text']);\n```\n\n您还可以为更新设置条件。\n\n```dart\nupdate(['text'], counter < 10);\n```\n\nGetX会自动进行重建，并且只重建使用被更改的变量的小组件，如果您将一个变量更改为与之前相同的变量，并且不意味着状态的更改，GetX不会重建小组件以节省内存和CPU周期（界面上正在显示3，而您再次将变量更改为3。在大多数状态管理器中，这将导致一个新的重建，但在GetX中，如果事实上他的状态已经改变，那么widget将只被再次重建）\n\n## 与其他状态管理器混用\n\n有人开了一个功能请求，因为他们只想使用一种类型的响应式变量，而其他的则手动去更新，需要为此在GetBuilder中插入一个Obx。思来想去，MixinBuilder应运而生。它既可以通过改变\".obs \"变量进行响应式改变，也可以通过update()进行手动更新。然而，在4个widget中，他是消耗资源最多的一个，因为除了有一个Subscription来接收来自他的子代的变化事件外，他还订阅了他的控制器的update方法。\n\n扩展GetxController是很重要的，因为它们有生命周期，可以在它们的onInit()和onClose()方法中 \"开始 \"和 \"结束 \"事件。你可以使用任何类来实现这一点，但我强烈建议你使用GetxController类来放置你的变量，无论它们是否是可观察的。\n\n\n## GetBuilder vs GetX vs Obx vs MixinBuilder\n\n在十年的编程工作中，我能够学到一些宝贵的经验。\n\n我第一次接触到响应式编程的时候，是那么的 \"哇，这太不可思议了\"，事实上响应式编程是不可思议的。\n但是，它并不适合所有情况。通常情况下，你需要的是同时改变2、3个widget的状态，或者是短暂的状态变化，这种情况下，响应式编程不是不好，而是不适合。\n\n响应式编程对RAM的消耗比较大，可以通过单独的工作流来弥补，这样可以保证只有一个widget被重建，而且是在必要的时候，但是创建一个有80个对象的List，每个对象都有几个流，这不是一个好的想法。打开dart inspect，查看一个StreamBuilder的消耗量，你就会明白我想告诉你什么。\n\n考虑到这一点，我创建了简单的状态管理器。它很简单，这正是你应该对它提出的要求：以一种简单的方式，并且以最高效的方式更新块中的状态。\n\nGetBuilder在RAM中是非常高效的，几乎没有比他更高效的方法（至少我无法想象，如果存在，请告诉我们）。\n\n然而，GetBuilder仍然是一个手动的状态管理器，你需要调用update()，就像你需要调用Provider的notifyListeners()一样。\n\n还有一些情况下，响应式编程真的很有趣，不使用它就等于重新发明轮子。考虑到这一点，GetX的创建是为了提供状态管理器中最现代和先进的一切。它只在必要的时候更新必要的东西，如果你出现了错误，同时发送了300个状态变化，GetX只在状态真正发生变化时才会过滤并更新界面。\n\nGetX比其他响应式状态管理器还是比较高效的，但它比GetBuilder多消耗一点内存。思前想后，以最大限度地消耗资源为目标，Obx应运而生。与GetX和GetBuilder不同的是，你将无法在Obx内部初始化一个控制器，它只是一个带有StreamSubscription的Widget，接收来自你的子代的变化事件，仅此而已。它比GetX更高效，但输给了GetBuilder，这是意料之中的，因为它是响应式的，而且GetBuilder有最简单的方法，即存储widget的hashcode和它的StateSetter。使用Obx，你不需要写你的控制器类型，你可以从多个不同的控制器中监听到变化，但它需要在之前进行初始化，或者使用本readme开头的示例方法，或者使用Bindings类。\n"
  },
  {
    "path": "example/.gitignore",
    "content": "# Miscellaneous\n*.class\n*.log\n*.pyc\n*.swp\n.DS_Store\n.atom/\n.buildlog/\n.history\n.svn/\n\n# IntelliJ related\n*.iml\n*.ipr\n*.iws\n.idea/\n\n# The .vscode folder contains launch configuration and tasks you configure in\n# VS Code which you may wish to be included in version control, so this line\n# is commented out by default.\n#.vscode/\n\n# Flutter/Dart/Pub related\n**/doc/api/\n**/ios/Flutter/.last_build_id\n.dart_tool/\n.flutter-plugins\n.flutter-plugins-dependencies\n.packages\n.pub-cache/\n.pub/\n/linux/\n/ios/\n/android/\n/web/\n/macos/\n/windows/\n\n# Web related\n\n# Symbolication related\napp.*.symbols\n\n# Obfuscation related\napp.*.map.json\n"
  },
  {
    "path": "example/.metadata",
    "content": "# This file tracks properties of this Flutter project.\n# Used by Flutter tool to assess capabilities and perform upgrades etc.\n#\n# This file should be version controlled and should not be manually edited.\n\nversion:\n  revision: \"35c388afb57ef061d06a39b537336c87e0e3d1b1\"\n  channel: \"stable\"\n\nproject_type: app\n\n# Tracks metadata for the flutter migrate command\nmigration:\n  platforms:\n    - platform: root\n      create_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1\n      base_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1\n    - platform: web\n      create_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1\n      base_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1\n\n  # User provided section\n\n  # List of Local paths (relative to this file) that should be\n  # ignored by the migrate tool.\n  #\n  # Files that are not part of the templates will be ignored by default.\n  unmanaged_files:\n    - 'lib/main.dart'\n    - 'ios/Runner.xcodeproj/project.pbxproj'\n"
  },
  {
    "path": "example/README.md",
    "content": "# example\n\nA new Flutter project.\n\n## Getting Started\n\nThis project is a starting point for a Flutter application.\n\nA few resources to get you started if this is your first Flutter project:\n\n- [Lab: Write your first Flutter app](https://flutter.dev/documentation/get-started/codelab)\n- [Cookbook: Useful Flutter samples](https://flutter.dev/documentation/cookbook)\n\nFor help getting started with Flutter, view our\n[online documentation](https://flutter.dev/docs), which offers tutorials,\nsamples, guidance on mobile development, and a full API reference.\n"
  },
  {
    "path": "example/analysis_options.yaml",
    "content": "# This file configures the analyzer, which statically analyzes Dart code to\n# check for errors, warnings, and lints.\n#\n# The issues identified by the analyzer are surfaced in the UI of Dart-enabled\n# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be\n# invoked from the command line by running `flutter analyze`.\n\n# The following line activates a set of recommended lints for Flutter apps,\n# packages, and plugins designed to encourage good coding practices.\n\nlinter:\n  # The lint rules applied to this project can be customized in the\n  # section below to disable rules from the `package:flutter_lints/flutter.yaml`\n  # included above or to enable additional rules. A list of all available lints\n  # and their documentation is published at\n  # https://dart-lang.github.io/linter/lints/index.html.\n  #\n  # Instead of disabling a lint rule for the entire project in the\n  # section below, it can also be suppressed for a single line of code\n  # or a specific dart file by using the `// ignore: name_of_lint` and\n  # `// ignore_for_file: name_of_lint` syntax on the line or in the file\n  # producing the lint.\n  rules:\n    camel_case_types: false\n    constant_identifier_names: false\n    # avoid_print: false  # Uncomment to disable the `avoid_print` rule\n    # prefer_single_quotes: true  # Uncomment to enable the `prefer_single_quotes` rule\n\n# Additional information about this file can be found at\n# https://dart.dev/guides/language/analysis-options\n"
  },
  {
    "path": "example/example.md",
    "content": "# GetX codelab\n\nIn this example you will learn the basics of GetX. You will see how much easier it is to code with this framework, and you will know what problems GetX proposes to solve.\n\nIf the default Flutter application were rewritten with Getx, it would have only a few lines of code. The Getx state manager is easier than using setState. You just need to add a \".obs\" at the end of your variable, and wrap the widget you want to change within a Obx().\n\n```dart\nvoid main() => runApp(MaterialApp(home: Home()));\n\nclass Home extends StatelessWidget {\n  var count = 0.obs;\n  @override\n  Widget build(context) => Scaffold(\n      appBar: AppBar(title: Text(\"counter\")),\n      body: Center(\n        child: Obx(() => Text(\"$count\")),\n      ),\n      floatingActionButton: FloatingActionButton(\n        child: Icon(Icons.add),\n        onPressed: () => count ++,\n      ));\n}\n```\nHowever, this simple example deals with ephemeral state management. If you need to access this data in several places in your application, you will need global state management.\nThe most common way to do this is to separate the business logic from its visualization. I know, you've heard this concept before, and it might have been scary for you, but with Getx, it's stupidly simple.\nGetx provides you with a class capable of initializing data, and removing it when it is no longer needed, and its use is very simple:\nJust create a class by extending GetxController and insert ALL your variables and functions there.\n\n```dart\nclass Controller extends GetxController {\n  var count = 0;\n  void increment() {\n    count++;\n    update();\n  }\n}\n```\nHere you can choose between simple state management, or reactive state management.\nThe simple one will update its variable on the screen whenever update() is called. It is used with a widget called \"GetBuilder\".\n\n```dart\nclass Home extends StatelessWidget {\n  final controller = Get.put(Controller());\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(title: Text(\"counter\")),\n      body: Center(\n        child: Column(\n          mainAxisAlignment: MainAxisAlignment.center,\n          children: [\n            GetBuilder<Controller>(\n                builder: (_) => Text(\n                      'clicks: ${controller.count}',\n                    )),\n            ElevatedButton(\n              child: Text('Next Route'),\n              onPressed: () {\n                Get.to(Second());\n              },\n            ),\n          ],\n        ),\n      ),\n      floatingActionButton: FloatingActionButton(\n          child: Icon(Icons.add),\n          onPressed: controller.increment(),  \n          ),\n    );\n  }\n}\nclass Second extends StatelessWidget {\n  final Controller ctrl = Get.find();\n  @override\n  Widget build(context){\n     return Scaffold(body: Center(child: Text(\"${ctrl.count}\")));\n  }\n}\n```\nWhen instantiating your controller, you may have noticed that we use `Get.put(Controller())`. This is enough to make your controller available to other pages as long as it is in memory.\nYou may have noticed that you have a new button using `Get.to(Second())`. This is enough to navigate to another page. You don't need a \n\n```dart\nNavigator.of(context).push(context, \n MaterialPageRoute(context, builder: (context){\n    return Second();\n },\n);\n``` \nall that huge code, it's reduced to a simple `Get.to(Second())`. Isn't that incredible?\n\nYou may also have noticed that on the other page you simply used Get.find (), and the framework knows which controller you registered previously, and returns it effortlessly, you don't need to type the find with `Get.find<Controller>()` so that he knows what you need.\n\nHowever, this is simple state management. You may want to control the output of each change of state, you may want to use and manipulate streams, you may want a variable to only be changed on the screen, when it definitely changes, you may need a debounce on changing the state, and to these and other needs, Getx has powerful, intelligent, and lightweight state management that can address any need, regardless of the size of your project. And its use is even easier than the previous one.\n\nIn your controller, you can remove the update method, Getx is reactive, so when a variable changes, it will automatically change on the screen.\nYou just need to add a \".obs\" in front of your variable, and that's it, it's already reactive.\n\n```dart\nclass Controller extends GetxController {\n  var count = 0.obs;\n  void increment() {\n    count++;\n  }\n}\n```\nNow you just need to change GetBuilder for GetX and that's it\n```dart\nclass Home extends StatelessWidget {\n  final controller = Get.put(Controller());\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(title: Text(\"counter\")),\n      body: Center(\n        child: Column(\n          mainAxisAlignment: MainAxisAlignment.center,\n          children: [\n            GetX<Controller>(\n                builder: (_) => Text(\n                      'clicks: ${controller.count}',\n                    )),\n            ElevatedButton(\n              child: Text('Next Route'),\n              onPressed: () {\n                Get.to(Second());\n              },\n            ),\n          ],\n        ),\n      ),\n      floatingActionButton: FloatingActionButton(\n          child: Icon(Icons.add),\n          onPressed: controller.increment(),  \n          ),\n    );\n  }\n}\nclass Second extends StatelessWidget {\n  final Controller ctrl = Get.find();\n  @override\n  Widget build(context){\n     return Scaffold(body: Center(child: Text(\"${ctrl.count}\")));\n  }\n}\n```\n\nGetX is a useful widget when you want to inject the controller into the init property, or when you want to retrieve an instance of the controller within the widget itself. In other cases, you can insert your widget into an Obx, which receives a widget function. This looks much easier and clearer, just like the first example\n\n```dart\nclass Home extends StatelessWidget {\n  final controller = Get.put(Controller());\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(title: Text(\"counter\")),\n      body: Center(\n        child: Column(\n          mainAxisAlignment: MainAxisAlignment.center,\n          children: [\n            Obx(() => Text(\n                      'clicks: ${controller.count}',\n                    )),\n            ElevatedButton(\n              child: Text('Next Route'),\n              onPressed: () {\n                Get.to(Second());\n              },\n            ),\n          ],\n        ),\n      ),\n      floatingActionButton: FloatingActionButton(\n          child: Icon(Icons.add),\n          onPressed: controller.increment(),  \n          ),\n    );\n  }\n}\nclass Second extends StatelessWidget {\n  final Controller ctrl = Get.find();\n  @override\n  Widget build(context){\n     return Scaffold(body: Center(child: Text(\"${ctrl.count}\")));\n  }\n}\n```\nIf you are a more demanding user, you must have said: BLoC separates the View from the business logic. But what about the presentation logic? Will I be obliged to attach it to the visualization? Will I be totally dependent on the context for everything I want to do? Will I have to insert a bunch of variables, TextEditingControllers in my view? If I need to hear the Scroll on my screen, do I need to insert an initState and a function into my view? If I need to trigger an action when this scroll reaches the end, do I insert it into the view, or in the bloc/changeNotifier class? Well, these are common architectural questions, and most of the time the solution to them is ugly.\nWith Getx you have no doubts when your architecture, if you need a function, it must be on your Controller, if you need to trigger an event, it needs to be on your controller, your view is generally a StatelessWidget free from any dirt.\nThis means that if someone has already done something you’re looking for, you can copy the controller entirely from someone else, and it will work for you, this level of standardization is what Flutter lacked, and it’s because of this that Getx has become so popular in the last few days. Flutter is amazing, and has minor one-off problems. Getx came to solve these specific problems. Flutter provides powerful APIs, and we turn them into an easy, clean, clear, and concise API for you to build applications in a fast, performance and highly scalable way.\nIf you have already asked yourself some of these questions above, you have certainly found the solution to your problems. Getx is able to completely separate any logic, be it presentation or business, and you will only have pure widgets in your visualization layer. No variables, no functions, just widgets. This will facilitate the work of your team working with the UI, as well as your team working with your logic. They won't depend on initState to do anything, their controller has onInit. Your code can be tested in isolation, the way it is.\nBut what about dependency injection? Will I have it attached to my visualization?\nIf you've used any state manager, you've probably heard of \"multiAnything\", or something like that.\nYou have probably already inserted dozens of ChangeNotifier or Blocs classes in a widget, just to have it all over the tree.\nThis level of coupling is yet another problem that Getx came to solve. For this, in this ecosystem we use BINDINGS.\nBindings are dependency injection classes. They are completely outside your widget tree, making your code cleaner, more organized, and allowing you to access it anywhere without context.\nYou can initialize dozens of controllers in your Bindings, when you need to know what is being injected into your view, just open the Bindings file on your page and that's it, you can clearly see what has been prepared to be initialized in your View.\nBindings is the first step towards having a scalable application, you can visualize what will be injected into your page, and decouple the dependency injection from your visualization layer.\n\nTo create a Binding, simply create a class and implement Bindings\n\n```dart\nclass SampleBind extends Binding {\n  @override\n  List<Bind> dependencies() {\n    return [\n      Bind.lazyPut<Controller>(() => Controller()),\n      Bind.lazyPut<Controller2>(() => Controller2()),\n      Bind.lazyPut<Controller3>(() => Controller3()),\n    ];\n  }\n}\n```\nYou can use with named routes (preferred)\n```dart\nvoid main() {\n  runApp(GetMaterialApp(\n    initialRoute: '/home',\n    getPages: [\n      GetPage(name: '/home', page: () => First(), binding: SampleBind()),\n    ],\n  ));\n}\n```\n\nOr unnamed\n```dart\nGet.to(Second(), binding: SampleBind());\n```\n\nThere is a trick that can clear your View even more.\nInstead of extending StatelessWidget, you can extend GetView, which is a StatelessWidget with a \"controller\" property.\n\nSee the example and see how clean your code can be using this approach.\nThe standard Flutter counter has almost 100 lines, it would be summarized to:\n\non main.dart\n```dart\nvoid main() {\n  runApp(GetMaterialApp(\n    initialRoute: '/home',\n    getPages: [\n      GetPage(name: '/home', page: () => HomeView(), binding: HomeBinding()),\n    ],\n  ));\n}\n```\non home_bindings.dart\n```dart\nclass HomeBinding implements Bindings {\n  @override\n  void dependencies() {\n    Get.lazyPut(() => HomeController());\n  }\n}\n```\n\non home_controller.dart\n```dart\nclass HomeController extends GetxController {\n  var count = 0.obs;\n  void increment() => count++;\n}\n```\non home_view.dart\n```dart\nclass Home extends GetView<Controller> {\n  @override\n  Widget build(context) => Scaffold(\n      appBar: AppBar(title: Text(\"counter\")),\n      body: Center(\n        child: Obx(() => Text(\"${controller.counter}\")),\n      ),\n      floatingActionButton: FloatingActionButton(\n        child: Icon(Icons.add),\n        onPressed: controller.increment,\n      ));\n}\n```\nWhat did you do:\nHe built an example of the counter, (with less code than the original), decoupling its visualization, its business logic, its dependency injection, in a clean, scalable way, facilitating code maintenance and reusability. If you need an accountant on another project, or your developer friend does, you can just share the content of the controller file with him, and everything will work perfectly.\nAs the view has only widgets, you can use a view for android, and another for iOS, taking advantage of 100% of your business logic, your view has only widgets! you can change them however you want, without affecting your application in any way.\n\nHowever, some examples like internationalization, Snackbars without context, validators, responsiveness and other Getx resources, were not explored (and it would not even be possible to explore all resources in such a simple example), so below is an example not very complete, but trying demonstrate how to use internationalization, reactive custom classes, reactive lists, snackbars contextless, workers etc.\n\n```dart\nimport 'dart:ui';\nimport 'package:flutter/material.dart';\nimport 'package:get/get.dart';\n\nvoid main() {\n  runApp(GetMaterialApp(\n    // It is not mandatory to use named routes, but dynamic urls are interesting.\n    initialRoute: '/home',\n    defaultTransition: Transition.native,\n    translations: MyTranslations(),\n    locale: Locale('pt', 'BR'),\n    getPages: [\n      //Simple GetPage\n      GetPage(name: '/home', page: () => First()),\n      // GetPage with custom transitions and bindings\n      GetPage(\n        name: '/second',\n        page: () => Second(),\n        customTransition: SizeTransitions(),\n        binding: SampleBind(),\n      ),\n      // GetPage with default transitions\n      GetPage(\n        name: '/third',\n        transition: Transition.cupertino,\n        page: () => Third(),\n      ),\n    ],\n  ));\n}\n\nclass MyTranslations extends Translations {\n  @override\n  Map<String, Map<String, String>> get keys => {\n        'en': {\n          'title': 'Hello World %s',\n        },\n        'en_US': {\n          'title': 'Hello World from US',\n        },\n        'pt': {\n          'title': 'Olá de Portugal',\n        },\n        'pt_BR': {\n          'title': 'Olá do Brasil',\n        },\n      };\n}\n\nclass Controller extends GetxController {\n  int count = 0;\n  void increment() {\n    count++;\n    // use update method to update all count variables\n    update();\n  }\n}\n\nclass First extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        leading: IconButton(\n          icon: Icon(Icons.add),\n          onPressed: () {\n            Get.snackbar(\"Hi\", \"I'm modern snackbar\");\n          },\n        ),\n        title: Text(\"title\".trArgs(['John'])),\n      ),\n      body: Center(\n        child: Column(\n          mainAxisAlignment: MainAxisAlignment.center,\n          children: [\n            GetBuilder<Controller>(\n                init: Controller(),\n                // You can initialize your controller here the first time. Don't use init in your other GetBuilders of same controller\n                builder: (_) => Text(\n                      'clicks: ${_.count}',\n                    )),\n            ElevatedButton(\n              child: Text('Next Route'),\n              onPressed: () {\n                Get.toNamed('/second');\n              },\n            ),\n            ElevatedButton(\n              child: Text('Change locale to English'),\n              onPressed: () {\n                Get.updateLocale(Locale('en', 'UK'));\n              },\n            ),\n          ],\n        ),\n      ),\n      floatingActionButton: FloatingActionButton(\n          child: Icon(Icons.add),\n          onPressed: () {\n            Get.find<Controller>().increment();\n          }),\n    );\n  }\n}\n\nclass Second extends GetView<ControllerX> {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: Text('second Route'),\n      ),\n      body: Center(\n        child: Column(\n          mainAxisAlignment: MainAxisAlignment.center,\n          children: [\n            Obx(\n              () {\n                print(\"count1 rebuild\");\n                return Text('${controller.count1}');\n              },\n            ),\n            Obx(\n              () {\n                print(\"count2 rebuild\");\n                return Text('${controller.count2}');\n              },\n            ),\n            Obx(() {\n              print(\"sum rebuild\");\n              return Text('${controller.sum}');\n            }),\n            Obx(\n              () => Text('Name: ${controller.user.value?.name}'),\n            ),\n            Obx(\n              () => Text('Age: ${controller.user.value?.age}'),\n            ),\n            ElevatedButton(\n              child: Text(\"Go to last page\"),\n              onPressed: () {\n                Get.toNamed('/third', arguments: 'arguments of second');\n              },\n            ),\n            ElevatedButton(\n              child: Text(\"Back page and open snackbar\"),\n              onPressed: () {\n                Get.back();\n                Get.snackbar(\n                  'User 123',\n                  'Successfully created',\n                );\n              },\n            ),\n            ElevatedButton(\n              child: Text(\"Increment\"),\n              onPressed: () {\n                controller.increment();\n              },\n            ),\n            ElevatedButton(\n              child: Text(\"Increment\"),\n              onPressed: () {\n                controller.increment2();\n              },\n            ),\n            ElevatedButton(\n              child: Text(\"Update name\"),\n              onPressed: () {\n                controller.updateUser();\n              },\n            ),\n            ElevatedButton(\n              child: Text(\"Dispose worker\"),\n              onPressed: () {\n                controller.disposeWorker();\n              },\n            ),\n          ],\n        ),\n      ),\n    );\n  }\n}\n\nclass Third extends GetView<ControllerX> {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      floatingActionButton: FloatingActionButton(onPressed: () {\n        controller.incrementList();\n      }),\n      appBar: AppBar(\n        title: Text(\"Third ${Get.arguments}\"),\n      ),\n      body: Center(\n          child: Obx(() => ListView.builder(\n              itemCount: controller.list.length,\n              itemBuilder: (context, index) {\n                return Text(\"${controller.list[index]}\");\n              }))),\n    );\n  }\n}\n\nclass SampleBind extends Binding {\n  @override\n  void dependencies() {\n    Get.lazyPut<ControllerX>(() => ControllerX());\n  }\n}\n\nclass User {\n  User({this.name = 'Name', this.age = 0});\n  String name;\n  int age;\n}\n\nclass ControllerX extends GetxController {\n  final count1 = 0.obs;\n  final count2 = 0.obs;\n  final list = [56].obs;\n  final user = User().obs;\n\n  updateUser() {\n    user.update((value) {\n      value!.name = 'Jose';\n      value.age = 30;\n    });\n  }\n\n  /// Once the controller has entered memory, onInit will be called.\n  /// It is preferable to use onInit instead of class constructors or initState method.\n  /// Use onInit to trigger initial events like API searches, listeners registration\n  /// or Workers registration.\n  /// Workers are event handlers, they do not modify the final result,\n  /// but it allows you to listen to an event and trigger customized actions.\n  /// Here is an outline of how you can use them:\n\n  /// made this if you need cancel you worker\n  late Worker _ever;\n\n  @override\n  onInit() {\n    /// Called every time the variable $_ is changed\n    _ever = ever(count1, (_) => print(\"$_ has been changed (ever)\"));\n\n    everAll([count1, count2], (_) => print(\"$_ has been changed (everAll)\"));\n\n    /// Called first time the variable $_ is changed\n    once(count1, (_) => print(\"$_ was changed once (once)\"));\n\n    /// Anti DDos - Called every time the user stops typing for 1 second, for example.\n    debounce(count1, (_) => print(\"debouce$_ (debounce)\"),\n        time: Duration(seconds: 1));\n\n    /// Ignore all changes within 1 second.\n    interval(count1, (_) => print(\"interval $_ (interval)\"),\n        time: Duration(seconds: 1));\n  }\n\n  int get sum => count1.value + count2.value;\n\n  increment() => count1.value++;\n\n  increment2() => count2.value++;\n\n  disposeWorker() {\n    _ever.dispose();\n    // or _ever();\n  }\n\n  incrementList() => list.add(75);\n}\n\nclass SizeTransitions extends CustomTransition {\n  @override\n  Widget buildTransition(\n      BuildContext context,\n      Curve? curve,\n      Alignment? alignment,\n      Animation<double> animation,\n      Animation<double> secondaryAnimation,\n      Widget child) {\n    return Align(\n      alignment: Alignment.center,\n      child: SizeTransition(\n        sizeFactor: CurvedAnimation(\n          parent: animation,\n          curve: curve!,\n        ),\n        child: child,\n      ),\n    );\n  }\n}\n```\n"
  },
  {
    "path": "example/lib/lang/en_US.dart",
    "content": "// ignore_for_file: file_names\n\nconst Map<String, String> en_US = {\n  'update_language': 'Update language to Portuguese',\n  'number_of_prizes': 'Number of prizes',\n  'average_age_of_laureates': 'Average age of laureates',\n  'details': 'Details',\n  'nobel_by_country': 'Nobel by country',\n};\n"
  },
  {
    "path": "example/lib/lang/pt_BR.dart",
    "content": "// ignore_for_file: file_names\n\nconst Map<String, String> pt_BR = {\n  'update_language': 'Atualizar idioma para Inglês',\n  'number_of_prizes': 'Número de prêmios',\n  'average_age_of_laureates': 'Idade média dos laureados',\n  'details': 'Detalhes',\n  'nobel_by_country': 'Nobel por país',\n};\n"
  },
  {
    "path": "example/lib/lang/translation_service.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:get/get.dart';\n\nimport 'en_US.dart';\nimport 'pt_BR.dart';\n\nclass TranslationService extends Translations {\n  static Locale? get locale => Get.deviceLocale;\n  static const fallbackLocale = Locale('en', 'US');\n  @override\n  Map<String, Map<String, String>> get keys => {\n        'en_US': en_US,\n        'pt_BR': pt_BR,\n      };\n}\n"
  },
  {
    "path": "example/lib/main.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:get/get.dart';\n\n// import 'lang/translation_service.dart';\n// import 'routes/app_pages.dart';\n// import 'shared/logger/logger_utils.dart';\n\n// void main() {\n//   runApp(const MyApp());\n// }\n\n// class MyApp extends StatelessWidget {\n//   const MyApp({Key? key}) : super(key: key);\n\n//   @override\n//   Widget build(BuildContext context) {\n//     return GetMaterialApp(\n//       theme: ThemeData(useMaterial3: true),\n//       debugShowCheckedModeBanner: false,\n//       enableLog: true,\n//       logWriterCallback: Logger.write,\n//       initialRoute: AppPages.INITIAL,\n//       getPages: AppPages.routes,\n//       locale: TranslationService.locale,\n//       fallbackLocale: TranslationService.fallbackLocale,\n//       translations: TranslationService(),\n//     );\n//   }\n// }\n\n/// Nav 2 snippet\nvoid main() {\n  runApp(const MyApp());\n}\n\nclass MyApp extends StatelessWidget {\n  const MyApp({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    return GetMaterialApp(\n      getPages: [\n        GetPage(\n            participatesInRootNavigator: true,\n            name: '/first',\n            page: () => const First()),\n        GetPage(\n          name: '/second',\n          page: () => const Second(),\n          transition: Transition.downToUp,\n        ),\n        GetPage(\n          name: '/third',\n          page: () => const Third(),\n        ),\n        GetPage(\n          name: '/fourth',\n          page: () => const Fourth(),\n        ),\n      ],\n      debugShowCheckedModeBanner: false,\n    );\n  }\n}\n\nclass FirstController extends GetxController {\n  @override\n  void onClose() {\n    print('on close first');\n    super.onClose();\n  }\n}\n\nclass First extends StatelessWidget {\n  const First({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    print('First rebuild');\n    Get.put(FirstController());\n    return Scaffold(\n      appBar: AppBar(\n        title: const Text('page one'),\n        leading: IconButton(\n          icon: const Icon(Icons.more),\n          onPressed: () {\n            Get.snackbar(\n              'title',\n              \"message\",\n              mainButton:\n                  TextButton(onPressed: () {}, child: const Text('button')),\n              isDismissible: true,\n              duration: Duration(seconds: 5),\n              snackbarStatus: (status) => print(status),\n            );\n            // print('THEME CHANGED');\n            // Get.changeTheme(\n            //     Get.isDarkMode ? ThemeData.light() : ThemeData.dark());\n          },\n        ),\n      ),\n      body: Center(\n        child: SizedBox(\n          height: 300,\n          width: 300,\n          child: ElevatedButton(\n            onPressed: () {\n              Get.toNamed('/second?id=123');\n            },\n            child: const Text('next screen'),\n          ),\n        ),\n      ),\n    );\n  }\n}\n\nclass SecondController extends GetxController {\n  final textEdit = TextEditingController();\n  @override\n  void onClose() {\n    print('on close second');\n    textEdit.dispose();\n    super.onClose();\n  }\n}\n\nclass Second extends StatelessWidget {\n  const Second({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    final controller = Get.put(SecondController());\n    print('second rebuild');\n    return PopScope(\n      canPop: false,\n      onPopInvokedWithResult: (didPop, result) => print('pop invoked'),\n      child: Scaffold(\n        appBar: AppBar(\n          title: Text('page two ${Get.parameters[\"id\"]}'),\n        ),\n        body: Center(\n          child: Column(\n            children: [\n              Expanded(\n                  child: TextField(\n                controller: controller.textEdit,\n              )),\n              SizedBox(\n                height: 300,\n                width: 300,\n                child: ElevatedButton(\n                  onPressed: () {\n                    Get.toNamed('/third');\n                  },\n                  child: const Text('next screen'),\n                ),\n              ),\n            ],\n          ),\n        ),\n      ),\n    );\n  }\n}\n\nclass Third extends StatelessWidget {\n  const Third({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      backgroundColor: Colors.red,\n      appBar: AppBar(\n        title: const Text('page three'),\n      ),\n      body: Center(\n        child: SizedBox(\n          height: 300,\n          width: 300,\n          child: ElevatedButton(\n            onPressed: () {\n              Get.offNamedUntil('/fourth', (route) {\n                return Get.currentRoute == '/first';\n              });\n            },\n            child: const Text('go to first screen'),\n          ),\n        ),\n      ),\n    );\n  }\n}\n\nclass Fourth extends StatelessWidget {\n  const Fourth({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      backgroundColor: Colors.red,\n      appBar: AppBar(\n        title: const Text('page four'),\n      ),\n      body: Center(\n        child: SizedBox(\n          height: 300,\n          width: 300,\n          child: ElevatedButton(\n            onPressed: () {\n              Get.back();\n            },\n            child: const Text('go to first screen'),\n          ),\n        ),\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "example/lib/pages/home/bindings/details_binding.dart",
    "content": "import 'package:get/get.dart';\n\nimport '../presentation/controllers/details_controller.dart';\n\nclass DetailsBinding extends Binding {\n  @override\n  List<Bind> dependencies() {\n    return [\n      Bind.lazyPut(() => DetailsController(homeRepository: Get.find())),\n    ];\n  }\n}\n"
  },
  {
    "path": "example/lib/pages/home/bindings/home_binding.dart",
    "content": "import 'package:get/get.dart';\n\nimport '../data/home_api_provider.dart';\nimport '../data/home_repository.dart';\nimport '../domain/adapters/repository_adapter.dart';\nimport '../presentation/controllers/home_controller.dart';\n\nclass HomeBinding extends Binding {\n  @override\n  List<Bind> dependencies() {\n    return [\n      Bind.lazyPut<IHomeProvider>(() => HomeProvider()),\n      Bind.lazyPut<IHomeRepository>(() => HomeRepository(provider: Get.find())),\n      Bind.lazyPut(() => HomeController(homeRepository: Get.find())),\n    ];\n  }\n}\n"
  },
  {
    "path": "example/lib/pages/home/data/home_api_provider.dart",
    "content": "import 'package:get/get.dart';\n\nimport '../../../shared/constants/endpoints.dart';\nimport '../domain/entity/country_model.dart';\n\n// ignore: one_member_abstracts\nabstract class IHomeProvider {\n  Future<Response<List<CountriesItem>>> getCountries();\n\n  Future<Response<Country>> getCountry(String path);\n}\n\nclass HomeProvider extends GetConnect implements IHomeProvider {\n  @override\n  void onInit() {\n    httpClient.baseUrl = API_URL;\n\n    super.onInit();\n  }\n\n  @override\n  Future<Response<List<CountriesItem>>> getCountries() {\n    return get(\n      '/countries',\n      decoder: (data) =>\n          (data as List).map((item) => CountriesItem.fromJson(item)).toList(),\n    );\n  }\n\n  Future<Response<Country>> getCountry(String path) async {\n    return get('/country/$path', decoder: (data) => Country.fromJson(data));\n  }\n}\n"
  },
  {
    "path": "example/lib/pages/home/data/home_repository.dart",
    "content": "import '../domain/adapters/repository_adapter.dart';\nimport '../domain/entity/country_model.dart';\nimport 'home_api_provider.dart';\n\nclass HomeRepository implements IHomeRepository {\n  HomeRepository({required this.provider});\n  final IHomeProvider provider;\n\n  @override\n  Future<List<CountriesItem>> getCountries() async {\n    final cases = await provider.getCountries();\n    if (cases.status.hasError) {\n      return Future.error(cases.statusText!);\n    } else {\n      return cases.body!;\n    }\n  }\n\n  Future<Country> getCountry(String path) async {\n    final country = await provider.getCountry(path);\n    if (country.status.hasError) {\n      return Future.error(country.statusText!);\n    } else {\n      return country.body!;\n    }\n  }\n}\n"
  },
  {
    "path": "example/lib/pages/home/domain/adapters/repository_adapter.dart",
    "content": "// ignore: one_member_abstracts\nimport '../entity/country_model.dart';\n\nabstract class IHomeRepository {\n  Future<List<CountriesItem>> getCountries();\n\n  Future<Country> getCountry(String path);\n}\n"
  },
  {
    "path": "example/lib/pages/home/domain/entity/country_model.dart",
    "content": "// Models\nclass Country {\n  final String name;\n  final String countryCode;\n  final int numberOfPrizes;\n  final double averageAgeOfLaureates;\n\n  const Country({\n    required this.name,\n    required this.countryCode,\n    required this.numberOfPrizes,\n    required this.averageAgeOfLaureates,\n  });\n\n  factory Country.fromJson(Map<String, dynamic> json) {\n    return Country(\n      name: json['Country'],\n      countryCode: json['CountryCode'],\n      numberOfPrizes: json['Number of prizes'],\n      averageAgeOfLaureates: json['Average age of laureates'].toDouble(),\n    );\n  }\n}\n\nclass CountriesItem {\n  final String country;\n  final String countryCode;\n\n  const CountriesItem({\n    required this.country,\n    required this.countryCode,\n  });\n\n  factory CountriesItem.fromJson(Map<String, dynamic> json) {\n    return CountriesItem(\n      country: json['Country'],\n      countryCode: json['CountryCode'],\n    );\n  }\n}\n"
  },
  {
    "path": "example/lib/pages/home/presentation/controllers/details_controller.dart",
    "content": "import 'package:get/get.dart';\n\nimport '../../domain/adapters/repository_adapter.dart';\nimport '../../domain/entity/country_model.dart';\n\nclass DetailsController extends StateController<Country> {\n  DetailsController({required this.homeRepository});\n\n  final IHomeRepository homeRepository;\n  late CountriesItem? country;\n\n  @override\n  void onInit() {\n    super.onInit();\n    country = Get.arguments;\n    final countryName = country?.country;\n    if (countryName == null) {\n      change(GetStatus.error('Country not found'));\n    } else {\n      //Loading, Success, Error handle with 1 line of code\n      futurize(() => homeRepository.getCountry(countryName));\n    }\n  }\n}\n"
  },
  {
    "path": "example/lib/pages/home/presentation/controllers/home_controller.dart",
    "content": "import 'package:get/get.dart';\n\nimport '../../domain/adapters/repository_adapter.dart';\nimport '../../domain/entity/country_model.dart';\n\nclass HomeController extends StateController<List<CountriesItem>> {\n  HomeController({required this.homeRepository});\n\n  final IHomeRepository homeRepository;\n\n  @override\n  void onInit() {\n    super.onInit();\n    futurize(homeRepository.getCountries);\n  }\n\n  Future<Country> getCountryByName(String name) async {\n    final country = await homeRepository.getCountry(name);\n    return country;\n  }\n}\n"
  },
  {
    "path": "example/lib/pages/home/presentation/views/details_view.dart",
    "content": "import 'dart:ui';\n\nimport 'package:flutter/material.dart';\nimport 'package:get/get.dart';\nimport 'package:get_demo/pages/home/domain/entity/country_model.dart';\n\nimport '../controllers/details_controller.dart';\n\nclass DetailsView extends GetView<DetailsController> {\n  const DetailsView({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    final args = context.arguments as CountriesItem;\n    return controller.obx((country) {\n      return Container(\n        decoration: BoxDecoration(\n          gradient: LinearGradient(\n            colors: [Colors.blueAccent, Colors.lightBlueAccent],\n            begin: Alignment.topLeft,\n            end: Alignment.bottomRight,\n          ),\n          image: DecorationImage(\n            fit: BoxFit.cover,\n            colorFilter: ColorFilter.mode(\n              Colors.black.withValues(alpha: 0.2),\n              BlendMode.darken,\n            ),\n            image: NetworkImage(\n              \"https://flagpedia.net/data/flags/normal/${args.countryCode.toLowerCase()}.png\",\n            ),\n          ),\n        ),\n        child: BackdropFilter(\n          filter: ImageFilter.blur(sigmaX: 8.0, sigmaY: 8.0),\n          child: Scaffold(\n            backgroundColor: Colors.transparent,\n            appBar: AppBar(\n              title: Text(\n                args.country,\n                style: TextStyle(\n                  fontWeight: FontWeight.bold,\n                  fontSize: 24,\n                ),\n              ),\n              backgroundColor: Colors.transparent,\n              elevation: 0,\n              centerTitle: true,\n              toolbarHeight: 70,\n              shape: RoundedRectangleBorder(\n                borderRadius: BorderRadius.vertical(\n                  bottom: Radius.circular(30),\n                ),\n              ),\n            ),\n            body: SafeArea(\n              child: Center(\n                child: Card(\n                  elevation: 12,\n                  shape: RoundedRectangleBorder(\n                    borderRadius: BorderRadius.circular(25),\n                  ),\n                  shadowColor: Colors.blueAccent.withValues(alpha: 0.5),\n                  color: Colors.white.withValues(alpha: 0.85),\n                  child: Padding(\n                    padding: const EdgeInsets.all(32.0),\n                    child: Column(\n                      mainAxisSize: MainAxisSize.min,\n                      children: [\n                        InfoRow(\n                          label: 'number_of_prizes'.tr,\n                          value: '${country.numberOfPrizes}',\n                        ),\n                        SizedBox(height: 20),\n                        InfoRow(\n                          label: 'average_age_of_laureates'.tr,\n                          value: '${country.averageAgeOfLaureates}',\n                        ),\n                      ],\n                    ),\n                  ),\n                ),\n              ),\n            ),\n          ),\n        ),\n      );\n    });\n  }\n}\n\nclass InfoRow extends StatelessWidget {\n  const InfoRow({\n    super.key,\n    required this.label,\n    required this.value,\n  });\n\n  final String label;\n  final String value;\n\n  @override\n  Widget build(BuildContext context) {\n    return Column(\n      children: [\n        Text(\n          label,\n          style: TextStyle(\n            fontSize: 20,\n            color: Colors.blueGrey[700],\n            fontWeight: FontWeight.w200,\n          ),\n        ),\n        SizedBox(height: 6),\n        Text(\n          value,\n          style: TextStyle(\n            fontSize: 30,\n            fontWeight: FontWeight.w600,\n            color: Colors.blueGrey[900],\n          ),\n        ),\n      ],\n    );\n  }\n}\n"
  },
  {
    "path": "example/lib/pages/home/presentation/views/home_view.dart",
    "content": "import 'dart:ui';\n\nimport 'package:flutter/material.dart';\nimport 'package:get/get.dart';\n\nimport '../controllers/home_controller.dart';\n\nclass HomeView extends GetView<HomeController> {\n  const HomeView({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    return Material(\n      child: Container(\n        decoration: const BoxDecoration(\n          image: DecorationImage(\n            fit: BoxFit.cover,\n            image: NetworkImage(\n              \"https://upload.wikimedia.org/wikipedia/en/e/ed/Nobel_Prize.png\",\n            ),\n          ),\n        ),\n        child: BackdropFilter(\n          filter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0),\n          child: Scaffold(\n            backgroundColor: Colors.black.withValues(alpha: 0.6),\n            extendBodyBehindAppBar: true,\n            appBar: AppBar(\n              title: Text(\n                'nobel_by_country'.tr,\n                style: TextStyle(\n                  fontSize: 28,\n                  fontWeight: FontWeight.w200,\n                  color: Colors.white,\n                  letterSpacing: 1.2,\n                ),\n              ),\n              backgroundColor: Colors.transparent,\n              elevation: 0,\n              centerTitle: true,\n              leading: IconButton(\n                icon: const Icon(Icons.add, color: Colors.white, size: 28),\n                onPressed: () {\n                  Get.snackbar(\n                    'New Feature',\n                    'Coming soon!',\n                    snackPosition: SnackPosition.bottom,\n                    backgroundColor: Colors.white.withValues(alpha: 0.9),\n                    colorText: Colors.black,\n                    borderRadius: 10,\n                    duration: Duration(seconds: 3),\n                    animationDuration: Duration(milliseconds: 500),\n                    boxShadows: [\n                      BoxShadow(\n                        color: Colors.black.withValues(alpha: 0.2),\n                        spreadRadius: 1,\n                        blurRadius: 5,\n                        offset: Offset(0, 3),\n                      ),\n                    ],\n                  );\n                },\n              ),\n            ),\n            body: SafeArea(\n              child: Padding(\n                padding: const EdgeInsets.fromLTRB(16, 32, 16, 16),\n                child: Column(\n                  children: [\n                    ElevatedButton(\n                      style: ElevatedButton.styleFrom(\n                        foregroundColor: Colors.white,\n                        backgroundColor:\n                            Colors.blueAccent.withValues(alpha: 0.8),\n                        padding:\n                            EdgeInsets.symmetric(horizontal: 24, vertical: 16),\n                        shape: RoundedRectangleBorder(\n                          borderRadius: BorderRadius.circular(30),\n                        ),\n                        elevation: 8,\n                        shadowColor: Colors.blueAccent.withValues(alpha: 0.5),\n                      ),\n                      onPressed: () {\n                        Get.updateLocale(Get.locale?.languageCode == 'en'\n                            ? const Locale('pt', 'BR')\n                            : const Locale('en', 'EN'));\n                      },\n                      child: Text(\n                        'update_language'.tr,\n                        style: TextStyle(\n                          fontWeight: FontWeight.w200,\n                          fontSize: 18,\n                          letterSpacing: 1.1,\n                        ),\n                      ),\n                    ),\n                    const SizedBox(height: 32),\n                    Expanded(\n                      child: controller.obx(\n                        (state) {\n                          return ListView.builder(\n                            itemCount: state.length,\n                            itemBuilder: (context, index) {\n                              final country = state[index];\n                              return Card(\n                                elevation: 8,\n                                margin: EdgeInsets.symmetric(\n                                    vertical: 12, horizontal: 4),\n                                shape: RoundedRectangleBorder(\n                                  borderRadius: BorderRadius.circular(20),\n                                ),\n                                color: Colors.white.withValues(alpha: 0.9),\n                                child: ListTile(\n                                  onTap: () async {\n                                    final data = await Get.toNamed(\n                                        '/home/details',\n                                        arguments: country);\n                                    if (data != null) Get.log(data);\n                                  },\n                                  contentPadding: EdgeInsets.symmetric(\n                                      horizontal: 20, vertical: 16),\n                                  leading: Hero(\n                                    tag: 'flag_${country.countryCode}',\n                                    child: CircleAvatar(\n                                      radius: 32,\n                                      backgroundImage: NetworkImage(\n                                        \"https://flagpedia.net/data/flags/normal/${country.countryCode.toLowerCase()}.png\",\n                                      ),\n                                    ),\n                                  ),\n                                  title: Text(\n                                    country.country,\n                                    style: TextStyle(\n                                      fontWeight: FontWeight.w200,\n                                      fontSize: 20,\n                                      color: Colors.black87,\n                                    ),\n                                  ),\n                                  trailing: Icon(Icons.arrow_forward_ios,\n                                      color: Colors.blueAccent, size: 24),\n                                ),\n                              );\n                            },\n                          );\n                        },\n                        onLoading: Center(\n                          child: CircularProgressIndicator(\n                            color: Colors.white,\n                            strokeWidth: 3,\n                          ),\n                        ),\n                        onError: (error) => Center(\n                          child: Text(\n                            'Error: $error',\n                            style: TextStyle(\n                              color: Colors.white,\n                              fontSize: 18,\n                            ),\n                            textAlign: TextAlign.center,\n                          ),\n                        ),\n                      ),\n                    ),\n                  ],\n                ),\n              ),\n            ),\n          ),\n        ),\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "example/lib/routes/app_pages.dart",
    "content": "import 'package:get/get.dart';\nimport 'package:get_demo/pages/home/bindings/details_binding.dart';\n\nimport '../pages/home/bindings/home_binding.dart';\nimport '../pages/home/presentation/views/details_view.dart';\nimport '../pages/home/presentation/views/home_view.dart';\n\npart 'app_routes.dart';\n\n// ignore: avoid_classes_with_only_static_members\nclass AppPages {\n  static const INITIAL = Routes.HOME;\n\n  static final routes = [\n    GetPage(\n      name: Routes.HOME,\n      page: () => const HomeView(),\n      binding: HomeBinding(),\n      children: [\n        GetPage(\n            name: Routes.DETAILS,\n            page: () => const DetailsView(),\n            binding: DetailsBinding()),\n      ],\n    ),\n  ];\n}\n"
  },
  {
    "path": "example/lib/routes/app_routes.dart",
    "content": "part of 'app_pages.dart';\n\nabstract class Routes {\n  static const HOME = '/home';\n  static const COUNTRY = '/country';\n  static const DETAILS = '/details';\n\n  static const DASHBOARD = '/dashboard';\n  static const PROFILE = '/profile';\n  static const PRODUCTS = '/products';\n}\n"
  },
  {
    "path": "example/lib/shared/constants/endpoints.dart",
    "content": "const API_URL = 'https://nobels.jonatasdev.workers.dev';\n"
  },
  {
    "path": "example/lib/shared/logger/logger_utils.dart",
    "content": "mixin Logger {\n  // Sample of abstract logging function\n  static void write(String text, {bool isError = false}) {\n    // ignore: avoid_print\n    Future.microtask(() => print('** $text. isError: [$isError]'));\n  }\n}\n"
  },
  {
    "path": "example/pubspec.yaml",
    "content": "name: get_demo\ndescription: A new Flutter project.\n\n# The following line prevents the package from being accidentally published to\n# pub.dev using `pub publish`. This is preferred for private packages.\npublish_to: \"none\" # Remove this line if you wish to publish to pub.dev\n\n# The following defines the version and build number for your application.\n# A version number is three numbers separated by dots, like 1.2.43\n# followed by an optional build number separated by a +.\n# Both the version and the builder number may be overridden in flutter\n# build by specifying --build-name and --build-number, respectively.\n# In Android, build-name is used as versionName while build-number used as versionCode.\n# Read more about Android versioning at https://developer.android.com/studio/publish/versioning\n# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.\n# Read more about iOS versioning at\n# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html\nversion: 1.0.0+1\n\nenvironment:\n  sdk: \">=3.0.1 <4.0.0\"\n\ndependency_overrides:\n  get:\n    path: ../\n\ndependencies:\n  flutter:\n    sdk: flutter\n  google_fonts:\n\n  # The following adds the Cupertino Icons font to your application.\n  # Use with the CupertinoIcons class for iOS style icons.\n  get:\n    path: ../\n  #get_test: ^3.13.3\n\ndev_dependencies:\n  flutter_test:\n    sdk: flutter\n  get_test: 4.0.1\n  flutter_lints: ^2.0.1\n\n# For information on the generic Dart part of this file, see the\n# following page: https://dart.dev/tools/pub/pubspec\n\n# The following section is specific to Flutter.\nflutter:\n  # The following line ensures that the Material Icons font is\n  # included with your application, so that you can use the icons in\n  # the material Icons class.\n  uses-material-design: true\n  # To add assets to your application, add an assets section, like this:\n  # assets:\n  #   - images/a_dot_burr.jpeg\n  #   - images/a_dot_ham.jpeg\n  # An image asset can refer to one or more resolution-specific \"variants\", see\n  # https://flutter.dev/assets-and-images/#resolution-aware.\n  # For details regarding adding assets from package dependencies, see\n  # https://flutter.dev/assets-and-images/#from-packages\n  # To add custom fonts to your application, add a fonts section here,\n  # in this \"flutter\" section. Each entry in this list should have a\n  # \"family\" key with the font family name, and a \"fonts\" key with a\n  # list giving the asset and other descriptors for the font. For\n  # example:\n  # fonts:\n  #   - family: Schyler\n  #     fonts:\n  #       - asset: fonts/Schyler-Regular.ttf\n  #       - asset: fonts/Schyler-Italic.ttf\n  #         style: italic\n  #   - family: Trajan Pro\n  #     fonts:\n  #       - asset: fonts/TrajanPro.ttf\n  #       - asset: fonts/TrajanPro_Bold.ttf\n  #         weight: 700\n  #\n  # For details regarding fonts from package dependencies,\n  # see https://flutter.dev/custom-fonts/#from-packages\n"
  },
  {
    "path": "example/test/main_test.dart",
    "content": "import 'dart:io';\n\nimport 'package:flutter/material.dart';\nimport 'package:flutter_test/flutter_test.dart';\nimport 'package:get/get.dart';\nimport 'package:get/get_navigation/src/routes/test_kit.dart';\nimport 'package:get_demo/pages/home/domain/adapters/repository_adapter.dart';\nimport 'package:get_demo/pages/home/domain/entity/country_model.dart';\nimport 'package:get_demo/pages/home/presentation/controllers/details_controller.dart';\nimport 'package:get_demo/pages/home/presentation/controllers/home_controller.dart';\n\n// Mock data\nconst country1 = CountriesItem(\n  country: 'Lalaland',\n  countryCode: 'LA',\n);\n\nconst country2 = CountriesItem(\n  country: 'Lololand',\n  countryCode: 'LO',\n);\n\n// Mock repository for success\nclass MockRepositorySuccess implements IHomeRepository {\n  @override\n  Future<List<CountriesItem>> getCountries() async => [country1, country2];\n\n  @override\n  Future<Country> getCountry(String path) async => Country(\n        name: 'Lalaland',\n        countryCode: 'LA',\n        numberOfPrizes: 3,\n        averageAgeOfLaureates: 4,\n      );\n}\n\n// Mock repository for failure\nclass MockRepositoryFailure implements IHomeRepository {\n  @override\n  Future<List<CountriesItem>> getCountries() async =>\n      Future.error(FetchException('Failed to load countries'));\n\n  @override\n  Future<Country> getCountry(String path) async =>\n      Future.error(FetchException('Failed to load country'));\n}\n\nclass FetchException implements Exception {\n  final String message;\n  FetchException(this.message);\n}\n\n// Custom bindings\nclass TestHomeBinding extends Binding {\n  final IHomeRepository repository;\n  TestHomeBinding({required this.repository});\n\n  @override\n  List<Bind> dependencies() => [\n        Bind.lazyPut<IHomeRepository>(() => repository),\n        Bind.lazyPut<HomeController>(\n          () => HomeController(homeRepository: Get.find()),\n        ),\n      ];\n}\n\nclass TestDetailsBinding extends Binding {\n  final IHomeRepository repository;\n  TestDetailsBinding({required this.repository});\n\n  @override\n  List<Bind> dependencies() => [\n        Bind.lazyPut<IHomeRepository>(() => repository),\n        Bind.lazyPut<DetailsController>(\n          () => DetailsController(homeRepository: Get.find()),\n        ),\n      ];\n}\n\nvoid main() {\n  WidgetsFlutterBinding.ensureInitialized();\n  setUpAll(() {\n    HttpOverrides.global = null;\n    GetTestMode.active = true;\n  });\n\n  setUp(() => Get.reset());\n\n  group('HomeController Tests', () {\n    test('Success Scenario', () async {\n      TestHomeBinding(repository: MockRepositorySuccess()).dependencies();\n      final controller = Get.find<HomeController>();\n\n      expect(controller.initialized, isTrue);\n\n      await Future.delayed(const Duration(milliseconds: 200));\n\n      expect(controller.status.isSuccess, isTrue);\n      expect(controller.state.length, 2);\n      expect(controller.state, containsAll([country1, country2]));\n    });\n\n    test('Failure Scenario', () async {\n      TestHomeBinding(repository: MockRepositoryFailure()).dependencies();\n      final controller = Get.find<HomeController>();\n\n      expect(controller.initialized, isTrue);\n\n      await Future.delayed(const Duration(milliseconds: 200));\n\n      expect(controller.status.isError, isTrue);\n      expect(controller.status.error, isA<FetchException>());\n    });\n  });\n\n  group('DetailsController Tests', () {\n    test('Success Scenario', () async {\n      TestDetailsBinding(repository: MockRepositorySuccess()).dependencies();\n      GetTestMode.setTestArguments(country1);\n      final controller = Get.find<DetailsController>();\n\n      expect(controller.initialized, isTrue);\n\n      await Future.delayed(const Duration(milliseconds: 200));\n\n      expect(controller.status.isSuccess, isTrue);\n      expect(controller.state.name, 'Lalaland');\n      expect(controller.state.countryCode, 'LA');\n      expect(controller.state.numberOfPrizes, 3);\n      expect(controller.state.averageAgeOfLaureates, 4);\n    });\n\n    test('Failure Scenario', () async {\n      TestDetailsBinding(repository: MockRepositoryFailure()).dependencies();\n      GetTestMode.setTestArguments(country1);\n      final controller = Get.find<DetailsController>();\n\n      expect(controller.initialized, isTrue);\n\n      await Future.delayed(const Duration(milliseconds: 200));\n\n      expect(controller.status.isError, isTrue);\n      expect(controller.status.error, isA<FetchException>());\n    });\n  });\n}\n"
  },
  {
    "path": "example/test/widget_test.dart",
    "content": "// This is a basic Flutter widget test.\n//\n// To perform an interaction with a widget in your test, use the WidgetTester\n// utility in the flutter_test package. For example, you can send tap and scroll\n// gestures. You can also use WidgetTester to find child widgets in the widget\n// tree, read text, and verify that the values of widget properties are correct.\n\nimport 'package:flutter/material.dart';\nimport 'package:flutter_test/flutter_test.dart';\n\nimport 'package:get_demo/main.dart';\n\nvoid main() {\n  testWidgets('Counter increments smoke test', (WidgetTester tester) async {\n    // Build our app and trigger a frame.\n    await tester.pumpWidget(const MyApp());\n\n    // Verify that our counter starts at 0.\n    expect(find.text('0'), findsOneWidget);\n    expect(find.text('1'), findsNothing);\n\n    // Tap the '+' icon and trigger a frame.\n    await tester.tap(find.byIcon(Icons.add));\n    await tester.pump();\n\n    // Verify that our counter has incremented.\n    expect(find.text('0'), findsNothing);\n    expect(find.text('1'), findsOneWidget);\n  });\n}\n"
  },
  {
    "path": "example_nav2/.gitignore",
    "content": "# Miscellaneous\n*.class\n*.log\n*.pyc\n*.swp\n.DS_Store\n.atom/\n.buildlog/\n.history\n.svn/\n\n# IntelliJ related\n*.iml\n*.ipr\n*.iws\n.idea/\n\n# The .vscode folder contains launch configuration and tasks you configure in\n# VS Code which you may wish to be included in version control, so this line\n# is commented out by default.\n#.vscode/\n\n# Flutter/Dart/Pub related\n**/doc/api/\n**/ios/Flutter/.last_build_id\n.dart_tool/\n.flutter-plugins\n.flutter-plugins-dependencies\n.packages\n.pub-cache/\n.pub/\n/build/\n\n# Web related\nlib/generated_plugin_registrant.dart\n\n# Symbolication related\napp.*.symbols\n\n# Obfuscation related\napp.*.map.json\n\n# Android Studio will place build artifacts here\n/android/app/debug\n/android/app/profile\n/android/app/release\n"
  },
  {
    "path": "example_nav2/.metadata",
    "content": "# This file tracks properties of this Flutter project.\n# Used by Flutter tool to assess capabilities and perform upgrades etc.\n#\n# This file should be version controlled and should not be manually edited.\n\nversion:\n  revision: \"5f77df9269acb57aea28082203b62b7e16d38c29\"\n  channel: \"master\"\n\nproject_type: app\n\n# Tracks metadata for the flutter migrate command\nmigration:\n  platforms:\n    - platform: root\n      create_revision: 5f77df9269acb57aea28082203b62b7e16d38c29\n      base_revision: 5f77df9269acb57aea28082203b62b7e16d38c29\n    - platform: android\n      create_revision: 5f77df9269acb57aea28082203b62b7e16d38c29\n      base_revision: 5f77df9269acb57aea28082203b62b7e16d38c29\n\n  # User provided section\n\n  # List of Local paths (relative to this file) that should be\n  # ignored by the migrate tool.\n  #\n  # Files that are not part of the templates will be ignored by default.\n  unmanaged_files:\n    - 'lib/main.dart'\n    - 'ios/Runner.xcodeproj/project.pbxproj'\n"
  },
  {
    "path": "example_nav2/README.md",
    "content": "# example_nav2\n\nA new Flutter project.\n\n## Getting Started\n\nThis project is a starting point for a Flutter application.\n\nA few resources to get you started if this is your first Flutter project:\n\n- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab)\n- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook)\n\nFor help getting started with Flutter, view our\n[online documentation](https://flutter.dev/docs), which offers tutorials,\nsamples, guidance on mobile development, and a full API reference.\n"
  },
  {
    "path": "example_nav2/analysis_options.yaml",
    "content": "# This file configures the analyzer, which statically analyzes Dart code to\n# check for errors, warnings, and lints.\n#\n# The issues identified by the analyzer are surfaced in the UI of Dart-enabled\n# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be\n# invoked from the command line by running `flutter analyze`.\n\n# The following line activates a set of recommended lints for Flutter apps,\n# packages, and plugins designed to encourage good coding practices.\ninclude: package:flutter_lints/flutter.yaml\n\nlinter:\n  # The lint rules applied to this project can be customized in the\n  # section below to disable rules from the `package:flutter_lints/flutter.yaml`\n  # included above or to enable additional rules. A list of all available lints\n  # and their documentation is published at\n  # https://dart-lang.github.io/linter/lints/index.html.\n  #\n  # Instead of disabling a lint rule for the entire project in the\n  # section below, it can also be suppressed for a single line of code\n  # or a specific dart file by using the `// ignore: name_of_lint` and\n  # `// ignore_for_file: name_of_lint` syntax on the line or in the file\n  # producing the lint.\n  rules:\n    # avoid_print: false  # Uncomment to disable the `avoid_print` rule\n    # prefer_single_quotes: true  # Uncomment to enable the `prefer_single_quotes` rule\n\n# Additional information about this file can be found at\n# https://dart.dev/guides/language/analysis-options\n"
  },
  {
    "path": "example_nav2/android/.gitignore",
    "content": "gradle-wrapper.jar\n/.gradle\n/captures/\n/gradlew\n/gradlew.bat\n/local.properties\nGeneratedPluginRegistrant.java\n.cxx/\n\n# Remember to never publicly share your keystore.\n# See https://flutter.dev/to/reference-keystore\nkey.properties\n**/*.keystore\n**/*.jks\n"
  },
  {
    "path": "example_nav2/android/app/build.gradle.kts",
    "content": "plugins {\n    id(\"com.android.application\")\n    id(\"kotlin-android\")\n    // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.\n    id(\"dev.flutter.flutter-gradle-plugin\")\n}\n\nandroid {\n    namespace = \"com.example.example_nav2\"\n    compileSdk = flutter.compileSdkVersion\n    ndkVersion = flutter.ndkVersion\n\n    compileOptions {\n        sourceCompatibility = JavaVersion.VERSION_11\n        targetCompatibility = JavaVersion.VERSION_11\n    }\n\n    kotlinOptions {\n        jvmTarget = JavaVersion.VERSION_11.toString()\n    }\n\n    defaultConfig {\n        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).\n        applicationId = \"com.example.example_nav2\"\n        // You can update the following values to match your application needs.\n        // For more information, see: https://flutter.dev/to/review-gradle-config.\n        minSdk = flutter.minSdkVersion\n        targetSdk = flutter.targetSdkVersion\n        versionCode = flutter.versionCode\n        versionName = flutter.versionName\n    }\n\n    buildTypes {\n        release {\n            // TODO: Add your own signing config for the release build.\n            // Signing with the debug keys for now, so `flutter run --release` works.\n            signingConfig = signingConfigs.getByName(\"debug\")\n        }\n    }\n}\n\nflutter {\n    source = \"../..\"\n}\n"
  },
  {
    "path": "example_nav2/android/app/src/debug/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <!-- The INTERNET permission is required for development. Specifically,\n         the Flutter tool needs it to communicate with the running application\n         to allow setting breakpoints, to provide hot reload, etc.\n    -->\n    <uses-permission android:name=\"android.permission.INTERNET\"/>\n</manifest>\n"
  },
  {
    "path": "example_nav2/android/app/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <application\n        android:label=\"example_nav2\"\n        android:name=\"${applicationName}\"\n        android:icon=\"@mipmap/ic_launcher\">\n        <activity\n            android:name=\".MainActivity\"\n            android:exported=\"true\"\n            android:launchMode=\"singleTop\"\n            android:taskAffinity=\"\"\n            android:theme=\"@style/LaunchTheme\"\n            android:configChanges=\"orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode\"\n            android:hardwareAccelerated=\"true\"\n            android:windowSoftInputMode=\"adjustResize\">\n            <!-- Specifies an Android theme to apply to this Activity as soon as\n                 the Android process has started. This theme is visible to the user\n                 while the Flutter UI initializes. After that, this theme continues\n                 to determine the Window background behind the Flutter UI. -->\n            <meta-data\n              android:name=\"io.flutter.embedding.android.NormalTheme\"\n              android:resource=\"@style/NormalTheme\"\n              />\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\"/>\n                <category android:name=\"android.intent.category.LAUNCHER\"/>\n            </intent-filter>\n        </activity>\n        <!-- Don't delete the meta-data below.\n             This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->\n        <meta-data\n            android:name=\"flutterEmbedding\"\n            android:value=\"2\" />\n    </application>\n    <!-- Required to query activities that can process text, see:\n         https://developer.android.com/training/package-visibility and\n         https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.\n\n         In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->\n    <queries>\n        <intent>\n            <action android:name=\"android.intent.action.PROCESS_TEXT\"/>\n            <data android:mimeType=\"text/plain\"/>\n        </intent>\n    </queries>\n</manifest>\n"
  },
  {
    "path": "example_nav2/android/app/src/main/kotlin/com/example/example_nav2/MainActivity.kt",
    "content": "package com.example.example_nav2\n\nimport io.flutter.embedding.android.FlutterActivity\n\nclass MainActivity : FlutterActivity()\n"
  },
  {
    "path": "example_nav2/android/app/src/main/res/drawable/launch_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Modify this file to customize your launch splash screen -->\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:drawable=\"@android:color/white\" />\n\n    <!-- You can insert your own image assets here -->\n    <!-- <item>\n        <bitmap\n            android:gravity=\"center\"\n            android:src=\"@mipmap/launch_image\" />\n    </item> -->\n</layer-list>\n"
  },
  {
    "path": "example_nav2/android/app/src/main/res/drawable-v21/launch_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Modify this file to customize your launch splash screen -->\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:drawable=\"?android:colorBackground\" />\n\n    <!-- You can insert your own image assets here -->\n    <!-- <item>\n        <bitmap\n            android:gravity=\"center\"\n            android:src=\"@mipmap/launch_image\" />\n    </item> -->\n</layer-list>\n"
  },
  {
    "path": "example_nav2/android/app/src/main/res/values/styles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->\n    <style name=\"LaunchTheme\" parent=\"@android:style/Theme.Light.NoTitleBar\">\n        <!-- Show a splash screen on the activity. Automatically removed when\n             the Flutter engine draws its first frame -->\n        <item name=\"android:windowBackground\">@drawable/launch_background</item>\n    </style>\n    <!-- Theme applied to the Android Window as soon as the process has started.\n         This theme determines the color of the Android Window while your\n         Flutter UI initializes, as well as behind your Flutter UI while its\n         running.\n\n         This Theme is only used starting with V2 of Flutter's Android embedding. -->\n    <style name=\"NormalTheme\" parent=\"@android:style/Theme.Light.NoTitleBar\">\n        <item name=\"android:windowBackground\">?android:colorBackground</item>\n    </style>\n</resources>\n"
  },
  {
    "path": "example_nav2/android/app/src/main/res/values-night/styles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->\n    <style name=\"LaunchTheme\" parent=\"@android:style/Theme.Black.NoTitleBar\">\n        <!-- Show a splash screen on the activity. Automatically removed when\n             the Flutter engine draws its first frame -->\n        <item name=\"android:windowBackground\">@drawable/launch_background</item>\n    </style>\n    <!-- Theme applied to the Android Window as soon as the process has started.\n         This theme determines the color of the Android Window while your\n         Flutter UI initializes, as well as behind your Flutter UI while its\n         running.\n\n         This Theme is only used starting with V2 of Flutter's Android embedding. -->\n    <style name=\"NormalTheme\" parent=\"@android:style/Theme.Black.NoTitleBar\">\n        <item name=\"android:windowBackground\">?android:colorBackground</item>\n    </style>\n</resources>\n"
  },
  {
    "path": "example_nav2/android/app/src/profile/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <!-- The INTERNET permission is required for development. Specifically,\n         the Flutter tool needs it to communicate with the running application\n         to allow setting breakpoints, to provide hot reload, etc.\n    -->\n    <uses-permission android:name=\"android.permission.INTERNET\"/>\n</manifest>\n"
  },
  {
    "path": "example_nav2/android/build.gradle.kts",
    "content": "allprojects {\n    repositories {\n        google()\n        mavenCentral()\n    }\n}\n\nval newBuildDir: Directory = rootProject.layout.buildDirectory.dir(\"../../build\").get()\nrootProject.layout.buildDirectory.value(newBuildDir)\n\nsubprojects {\n    val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)\n    project.layout.buildDirectory.value(newSubprojectBuildDir)\n}\nsubprojects {\n    project.evaluationDependsOn(\":app\")\n}\n\ntasks.register<Delete>(\"clean\") {\n    delete(rootProject.layout.buildDirectory)\n}\n"
  },
  {
    "path": "example_nav2/android/gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-8.10.2-all.zip\n"
  },
  {
    "path": "example_nav2/android/gradle.properties",
    "content": "org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError\nandroid.useAndroidX=true\nandroid.enableJetifier=true\n"
  },
  {
    "path": "example_nav2/android/local.properties",
    "content": "sdk.dir=/Users/jonatasborges/Library/Android/sdk\nflutter.sdk=/Users/jonatasborges/flutter\nflutter.buildMode=debug\nflutter.versionName=1.0.0\nflutter.versionCode=1"
  },
  {
    "path": "example_nav2/android/settings.gradle.kts",
    "content": "pluginManagement {\n    val flutterSdkPath = run {\n        val properties = java.util.Properties()\n        file(\"local.properties\").inputStream().use { properties.load(it) }\n        val flutterSdkPath = properties.getProperty(\"flutter.sdk\")\n        require(flutterSdkPath != null) { \"flutter.sdk not set in local.properties\" }\n        flutterSdkPath\n    }\n\n    includeBuild(\"$flutterSdkPath/packages/flutter_tools/gradle\")\n\n    repositories {\n        google()\n        mavenCentral()\n        gradlePluginPortal()\n    }\n}\n\nplugins {\n    id(\"dev.flutter.flutter-plugin-loader\") version \"1.0.0\"\n    id(\"com.android.application\") version \"8.7.0\" apply false\n    id(\"org.jetbrains.kotlin.android\") version \"1.8.22\" apply false\n}\n\ninclude(\":app\")\n"
  },
  {
    "path": "example_nav2/ios/.gitignore",
    "content": "*.mode1v3\n*.mode2v3\n*.moved-aside\n*.pbxuser\n*.perspectivev3\n**/*sync/\n.sconsign.dblite\n.tags*\n**/.vagrant/\n**/DerivedData/\nIcon?\n**/Pods/\n**/.symlinks/\nprofile\nxcuserdata\n**/.generated/\nFlutter/App.framework\nFlutter/Flutter.framework\nFlutter/Flutter.podspec\nFlutter/Generated.xcconfig\nFlutter/ephemeral/\nFlutter/app.flx\nFlutter/app.zip\nFlutter/flutter_assets/\nFlutter/flutter_export_environment.sh\nServiceDefinitions.json\nRunner/GeneratedPluginRegistrant.*\n\n# Exceptions to above rules.\n!default.mode1v3\n!default.mode2v3\n!default.pbxuser\n!default.perspectivev3\n"
  },
  {
    "path": "example_nav2/ios/Flutter/AppFrameworkInfo.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n  <key>CFBundleDevelopmentRegion</key>\n  <string>en</string>\n  <key>CFBundleExecutable</key>\n  <string>App</string>\n  <key>CFBundleIdentifier</key>\n  <string>io.flutter.flutter.app</string>\n  <key>CFBundleInfoDictionaryVersion</key>\n  <string>6.0</string>\n  <key>CFBundleName</key>\n  <string>App</string>\n  <key>CFBundlePackageType</key>\n  <string>FMWK</string>\n  <key>CFBundleShortVersionString</key>\n  <string>1.0</string>\n  <key>CFBundleSignature</key>\n  <string>????</string>\n  <key>CFBundleVersion</key>\n  <string>1.0</string>\n  <key>MinimumOSVersion</key>\n  <string>11.0</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "example_nav2/ios/Flutter/Debug.xcconfig",
    "content": "#include \"Generated.xcconfig\"\n"
  },
  {
    "path": "example_nav2/ios/Flutter/Generated.xcconfig",
    "content": "// This is a generated file; do not edit or check into version control.\nFLUTTER_ROOT=/Users/jonatasborges/flutter\nFLUTTER_APPLICATION_PATH=/Users/jonatasborges/newgetx/getx/example_nav2\nCOCOAPODS_PARALLEL_CODE_SIGN=true\nFLUTTER_TARGET=lib/main.dart\nFLUTTER_BUILD_DIR=build\nFLUTTER_BUILD_NAME=1.0.0\nFLUTTER_BUILD_NUMBER=1\nEXCLUDED_ARCHS[sdk=iphonesimulator*]=i386\nEXCLUDED_ARCHS[sdk=iphoneos*]=armv7\nDART_OBFUSCATION=false\nTRACK_WIDGET_CREATION=true\nTREE_SHAKE_ICONS=false\nPACKAGE_CONFIG=.dart_tool/package_config.json\n"
  },
  {
    "path": "example_nav2/ios/Flutter/Release.xcconfig",
    "content": "#include \"Generated.xcconfig\"\n"
  },
  {
    "path": "example_nav2/ios/Flutter/flutter_export_environment.sh",
    "content": "#!/bin/sh\n# This is a generated file; do not edit or check into version control.\nexport \"FLUTTER_ROOT=/Users/jonatasborges/flutter\"\nexport \"FLUTTER_APPLICATION_PATH=/Users/jonatasborges/newgetx/getx/example_nav2\"\nexport \"COCOAPODS_PARALLEL_CODE_SIGN=true\"\nexport \"FLUTTER_TARGET=lib/main.dart\"\nexport \"FLUTTER_BUILD_DIR=build\"\nexport \"FLUTTER_BUILD_NAME=1.0.0\"\nexport \"FLUTTER_BUILD_NUMBER=1\"\nexport \"DART_OBFUSCATION=false\"\nexport \"TRACK_WIDGET_CREATION=true\"\nexport \"TREE_SHAKE_ICONS=false\"\nexport \"PACKAGE_CONFIG=.dart_tool/package_config.json\"\n"
  },
  {
    "path": "example_nav2/ios/Runner/AppDelegate.swift",
    "content": "import UIKit\nimport Flutter\n\n@UIApplicationMain\n@objc class AppDelegate: FlutterAppDelegate {\n  override func application(\n    _ application: UIApplication,\n    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?\n  ) -> Bool {\n    GeneratedPluginRegistrant.register(with: self)\n    return super.application(application, didFinishLaunchingWithOptions: launchOptions)\n  }\n}\n"
  },
  {
    "path": "example_nav2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"size\" : \"20x20\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-20x20@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"20x20\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-20x20@3x.png\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-29x29@1x.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-29x29@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-29x29@3x.png\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"size\" : \"40x40\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-40x40@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"40x40\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-40x40@3x.png\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"size\" : \"60x60\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-60x60@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"60x60\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-60x60@3x.png\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"size\" : \"20x20\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-20x20@1x.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"20x20\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-20x20@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-29x29@1x.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-29x29@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"40x40\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-40x40@1x.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"40x40\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-40x40@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"76x76\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-76x76@1x.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"76x76\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-76x76@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"83.5x83.5\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-83.5x83.5@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"1024x1024\",\n      \"idiom\" : \"ios-marketing\",\n      \"filename\" : \"Icon-App-1024x1024@1x.png\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}\n"
  },
  {
    "path": "example_nav2/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"LaunchImage.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"LaunchImage@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"LaunchImage@3x.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}\n"
  },
  {
    "path": "example_nav2/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md",
    "content": "# Launch Screen Assets\n\nYou can customize the launch screen with your own desired assets by replacing the image files in this directory.\n\nYou can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images."
  },
  {
    "path": "example_nav2/ios/Runner/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"12121\" systemVersion=\"16G29\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" colorMatched=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"12089\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"Ydg-fD-yQy\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"xbc-2k-c8Z\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <imageView opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"center\" image=\"LaunchImage\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"YRO-k0-Ey4\">\n                            </imageView>\n                        </subviews>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <constraints>\n                            <constraint firstItem=\"YRO-k0-Ey4\" firstAttribute=\"centerX\" secondItem=\"Ze5-6b-2t3\" secondAttribute=\"centerX\" id=\"1a2-6s-vTC\"/>\n                            <constraint firstItem=\"YRO-k0-Ey4\" firstAttribute=\"centerY\" secondItem=\"Ze5-6b-2t3\" secondAttribute=\"centerY\" id=\"4X2-HB-R7a\"/>\n                        </constraints>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <image name=\"LaunchImage\" width=\"168\" height=\"185\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "example_nav2/ios/Runner/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"10117\" systemVersion=\"15F34\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" initialViewController=\"BYZ-38-t0r\">\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"10085\"/>\n    </dependencies>\n    <scenes>\n        <!--Flutter View Controller-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController id=\"BYZ-38-t0r\" customClass=\"FlutterViewController\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"y3c-jy-aDJ\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"wfy-db-euE\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"600\" height=\"600\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "example_nav2/ios/Runner/GeneratedPluginRegistrant.h",
    "content": "//\n//  Generated file. Do not edit.\n//\n\n// clang-format off\n\n#ifndef GeneratedPluginRegistrant_h\n#define GeneratedPluginRegistrant_h\n\n#import <Flutter/Flutter.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface GeneratedPluginRegistrant : NSObject\n+ (void)registerWithRegistry:(NSObject<FlutterPluginRegistry>*)registry;\n@end\n\nNS_ASSUME_NONNULL_END\n#endif /* GeneratedPluginRegistrant_h */\n"
  },
  {
    "path": "example_nav2/ios/Runner/GeneratedPluginRegistrant.m",
    "content": "//\n//  Generated file. Do not edit.\n//\n\n// clang-format off\n\n#import \"GeneratedPluginRegistrant.h\"\n\n@implementation GeneratedPluginRegistrant\n\n+ (void)registerWithRegistry:(NSObject<FlutterPluginRegistry>*)registry {\n}\n\n@end\n"
  },
  {
    "path": "example_nav2/ios/Runner/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>example_nav2</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>$(FLUTTER_BUILD_NAME)</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(FLUTTER_BUILD_NUMBER)</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations~ipad</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>UIViewControllerBasedStatusBarAppearance</key>\n\t<false/>\n\t<key>CADisableMinimumFrameDurationOnPhone</key>\n\t<true/>\n\t<key>UIApplicationSupportsIndirectInputEvents</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "example_nav2/ios/Runner/Runner-Bridging-Header.h",
    "content": "#import \"GeneratedPluginRegistrant.h\"\n"
  },
  {
    "path": "example_nav2/ios/Runner.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 54;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };\n\t\t3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };\n\t\t74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };\n\t\t97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };\n\t\t97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };\n\t\t97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXCopyFilesBuildPhase section */\n\t\t9705A1C41CF9048500538489 /* Embed Frameworks */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = \"\";\n\t\t\tdstSubfolderSpec = 10;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tname = \"Embed Frameworks\";\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXCopyFilesBuildPhase section */\n\n/* Begin PBXFileReference section */\n\t\t1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = \"<group>\"; };\n\t\t1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = \"<group>\"; };\n\t\t3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = \"<group>\"; };\n\t\t74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = \"Runner-Bridging-Header.h\"; sourceTree = \"<group>\"; };\n\t\t74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\t7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = \"<group>\"; };\n\t\t9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = \"<group>\"; };\n\t\t9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = \"<group>\"; };\n\t\t97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\t97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\t97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = \"<group>\"; };\n\t\t97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t97C146EB1CF9000F007C117D /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t9740EEB11CF90186004384FC /* Flutter */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,\n\t\t\t\t9740EEB21CF90195004384FC /* Debug.xcconfig */,\n\t\t\t\t7AFA3C8E1D35360C0083082E /* Release.xcconfig */,\n\t\t\t\t9740EEB31CF90195004384FC /* Generated.xcconfig */,\n\t\t\t);\n\t\t\tname = Flutter;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t97C146E51CF9000F007C117D = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t9740EEB11CF90186004384FC /* Flutter */,\n\t\t\t\t97C146F01CF9000F007C117D /* Runner */,\n\t\t\t\t97C146EF1CF9000F007C117D /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t97C146EF1CF9000F007C117D /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t97C146EE1CF9000F007C117D /* Runner.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t97C146F01CF9000F007C117D /* Runner */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t97C146FA1CF9000F007C117D /* Main.storyboard */,\n\t\t\t\t97C146FD1CF9000F007C117D /* Assets.xcassets */,\n\t\t\t\t97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,\n\t\t\t\t97C147021CF9000F007C117D /* Info.plist */,\n\t\t\t\t1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,\n\t\t\t\t1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,\n\t\t\t\t74858FAE1ED2DC5600515810 /* AppDelegate.swift */,\n\t\t\t\t74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,\n\t\t\t);\n\t\t\tpath = Runner;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t97C146ED1CF9000F007C117D /* Runner */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget \"Runner\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t9740EEB61CF901F6004384FC /* Run Script */,\n\t\t\t\t97C146EA1CF9000F007C117D /* Sources */,\n\t\t\t\t97C146EB1CF9000F007C117D /* Frameworks */,\n\t\t\t\t97C146EC1CF9000F007C117D /* Resources */,\n\t\t\t\t9705A1C41CF9048500538489 /* Embed Frameworks */,\n\t\t\t\t3B06AD1E1E4923F5004D2608 /* Thin Binary */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = Runner;\n\t\t\tproductName = Runner;\n\t\t\tproductReference = 97C146EE1CF9000F007C117D /* Runner.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t97C146E61CF9000F007C117D /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastUpgradeCheck = 1430;\n\t\t\t\tORGANIZATIONNAME = \"\";\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t97C146ED1CF9000F007C117D = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 7.3.1;\n\t\t\t\t\t\tLastSwiftMigration = 1100;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject \"Runner\" */;\n\t\t\tcompatibilityVersion = \"Xcode 9.3\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 97C146E51CF9000F007C117D;\n\t\t\tproductRefGroup = 97C146EF1CF9000F007C117D /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t97C146ED1CF9000F007C117D /* Runner */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t97C146EC1CF9000F007C117D /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,\n\t\t\t\t3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,\n\t\t\t\t97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,\n\t\t\t\t97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXShellScriptBuildPhase section */\n\t\t3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\talwaysOutOfDate = 1;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}\",\n\t\t\t);\n\t\t\tname = \"Thin Binary\";\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"/bin/sh \\\"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\\\" embed_and_thin\";\n\t\t};\n\t\t9740EEB61CF901F6004384FC /* Run Script */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\talwaysOutOfDate = 1;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = \"Run Script\";\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"/bin/sh \\\"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\\\" build\";\n\t\t};\n/* End PBXShellScriptBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t97C146EA1CF9000F007C117D /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,\n\t\t\t\t1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXVariantGroup section */\n\t\t97C146FA1CF9000F007C117D /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t97C146FB1CF9000F007C117D /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t97C147001CF9000F007C117D /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\t249021D3217E4FDB00AE95B9 /* Profile */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 11.0;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSUPPORTED_PLATFORMS = iphoneos;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Profile;\n\t\t};\n\t\t249021D4217E4FDB00AE95B9 /* Profile */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCURRENT_PROJECT_VERSION = \"$(FLUTTER_BUILD_NUMBER)\";\n\t\t\t\tENABLE_BITCODE = NO;\n\t\t\t\tINFOPLIST_FILE = Runner/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.get.exampleNav2;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_OBJC_BRIDGING_HEADER = \"Runner/Runner-Bridging-Header.h\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t};\n\t\t\tname = Profile;\n\t\t};\n\t\t97C147031CF9000F007C117D /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 11.0;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t97C147041CF9000F007C117D /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 11.0;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSUPPORTED_PLATFORMS = iphoneos;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Owholemodule\";\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t97C147061CF9000F007C117D /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCURRENT_PROJECT_VERSION = \"$(FLUTTER_BUILD_NUMBER)\";\n\t\t\t\tENABLE_BITCODE = NO;\n\t\t\t\tINFOPLIST_FILE = Runner/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.get.exampleNav2;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_OBJC_BRIDGING_HEADER = \"Runner/Runner-Bridging-Header.h\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t97C147071CF9000F007C117D /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCURRENT_PROJECT_VERSION = \"$(FLUTTER_BUILD_NUMBER)\";\n\t\t\t\tENABLE_BITCODE = NO;\n\t\t\t\tINFOPLIST_FILE = Runner/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.get.exampleNav2;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_OBJC_BRIDGING_HEADER = \"Runner/Runner-Bridging-Header.h\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t97C146E91CF9000F007C117D /* Build configuration list for PBXProject \"Runner\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t97C147031CF9000F007C117D /* Debug */,\n\t\t\t\t97C147041CF9000F007C117D /* Release */,\n\t\t\t\t249021D3217E4FDB00AE95B9 /* Profile */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget \"Runner\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t97C147061CF9000F007C117D /* Debug */,\n\t\t\t\t97C147071CF9000F007C117D /* Release */,\n\t\t\t\t249021D4217E4FDB00AE95B9 /* Profile */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 97C146E61CF9000F007C117D /* Project object */;\n}\n"
  },
  {
    "path": "example_nav2/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "example_nav2/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>IDEDidComputeMac32BitWarning</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "example_nav2/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>PreviewsEnabled</key>\n\t<false/>\n</dict>\n</plist>\n"
  },
  {
    "path": "example_nav2/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1430\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"97C146ED1CF9000F007C117D\"\n               BuildableName = \"Runner.app\"\n               BlueprintName = \"Runner\"\n               ReferencedContainer = \"container:Runner.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n      </Testables>\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"97C146ED1CF9000F007C117D\"\n            BuildableName = \"Runner.app\"\n            BlueprintName = \"Runner\"\n            ReferencedContainer = \"container:Runner.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"97C146ED1CF9000F007C117D\"\n            BuildableName = \"Runner.app\"\n            BlueprintName = \"Runner\"\n            ReferencedContainer = \"container:Runner.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Profile\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"97C146ED1CF9000F007C117D\"\n            BuildableName = \"Runner.app\"\n            BlueprintName = \"Runner\"\n            ReferencedContainer = \"container:Runner.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "example_nav2/ios/Runner.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"group:Runner.xcodeproj\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "example_nav2/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>IDEDidComputeMac32BitWarning</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "example_nav2/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>PreviewsEnabled</key>\n\t<false/>\n</dict>\n</plist>\n"
  },
  {
    "path": "example_nav2/ios/RunnerTests/RunnerTests.swift",
    "content": "import Flutter\nimport UIKit\nimport XCTest\n\nclass RunnerTests: XCTestCase {\n\n  func testExample() {\n    // If you add code to the Runner application, consider adding tests here.\n    // See https://developer.apple.com/documentation/xctest for more information about using XCTest.\n  }\n\n}\n"
  },
  {
    "path": "example_nav2/lib/app/middleware/auth_middleware.dart",
    "content": "import 'package:get/get.dart';\r\n\r\nimport '../../services/auth_service.dart';\r\nimport '../routes/app_pages.dart';\r\n\r\nclass EnsureAuthMiddleware extends GetMiddleware {\r\n  @override\r\n  Future<RouteDecoder?> redirectDelegate(RouteDecoder route) async {\r\n    // you can do whatever you want here\r\n    // but it's preferable to make this method fast\r\n    // await Future.delayed(Duration(milliseconds: 500));\r\n\r\n    if (!AuthService.to.isLoggedInValue) {\r\n      final newRoute = Routes.LOGIN_THEN(route.pageSettings!.name);\r\n      return RouteDecoder.fromRoute(newRoute);\r\n    }\r\n    return await super.redirectDelegate(route);\r\n  }\r\n}\r\n\r\nclass EnsureNotAuthedMiddleware extends GetMiddleware {\r\n  @override\r\n  Future<RouteDecoder?> redirectDelegate(RouteDecoder route) async {\r\n    if (AuthService.to.isLoggedInValue) {\r\n      //NEVER navigate to auth screen, when user is already authed\r\n      return null;\r\n\r\n      //OR redirect user to another screen\r\n      //return RouteDecoder.fromRoute(Routes.PROFILE);\r\n    }\r\n    return await super.redirectDelegate(route);\r\n  }\r\n}\r\n"
  },
  {
    "path": "example_nav2/lib/app/modules/dashboard/bindings/dashboard_binding.dart",
    "content": "import 'package:get/get.dart';\n\nimport '../controllers/dashboard_controller.dart';\n\nclass DashboardBinding extends Binding {\n  @override\n  List<Bind> dependencies() {\n    return [\n      Bind.lazyPut<DashboardController>(\n        () => DashboardController(),\n      )\n    ];\n  }\n}\n"
  },
  {
    "path": "example_nav2/lib/app/modules/dashboard/controllers/dashboard_controller.dart",
    "content": "import 'dart:async';\n\nimport 'package:get/get.dart';\n\nclass DashboardController extends GetxController {\n  final now = DateTime.now().obs;\n  @override\n  void onReady() {\n    super.onReady();\n    Timer.periodic(\n      const Duration(seconds: 1),\n      (timer) {\n        now.value = DateTime.now();\n      },\n    );\n  }\n}\n"
  },
  {
    "path": "example_nav2/lib/app/modules/dashboard/views/dashboard_view.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:get/get.dart';\n\nimport '../controllers/dashboard_controller.dart';\n\nclass DashboardView extends GetView<DashboardController> {\n  const DashboardView({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      body: Center(\n        child: Obx(\n          () => Column(\n            mainAxisSize: MainAxisSize.min,\n            children: [\n              const Text(\n                'DashboardView is working',\n                style: TextStyle(fontSize: 20),\n              ),\n              Text('Time: ${controller.now.value.toString()}'),\n            ],\n          ),\n        ),\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "example_nav2/lib/app/modules/home/bindings/home_binding.dart",
    "content": "import 'package:get/get.dart';\n\nimport '../controllers/home_controller.dart';\n\nclass HomeBinding extends Binding {\n  @override\n  List<Bind> dependencies() {\n    return [\n      Bind.lazyPut<HomeController>(\n        () => HomeController(),\n      )\n    ];\n  }\n}\n"
  },
  {
    "path": "example_nav2/lib/app/modules/home/controllers/home_controller.dart",
    "content": "import 'package:get/get.dart';\n\nclass HomeController extends GetxController {}\n"
  },
  {
    "path": "example_nav2/lib/app/modules/home/views/home_view.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:get/get.dart';\n\nimport '../../../routes/app_pages.dart';\nimport '../controllers/home_controller.dart';\n\nclass HomeView extends GetView<HomeController> {\n  const HomeView({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Column(\n      children: [\n        Container(\n          color: Colors.yellow,\n          width: double.infinity,\n          height: 25,\n        ),\n        Expanded(\n          child: GetRouterOutlet.builder(\n            route: Routes.home,\n            builder: (context) {\n              return Scaffold(\n                body: GetRouterOutlet(\n                  initialRoute: Routes.dashboard,\n                  anchorRoute: Routes.home,\n                ),\n                bottomNavigationBar: IndexedRouteBuilder(\n                    routes: const [\n                      Routes.dashboard,\n                      Routes.profile,\n                      Routes.products\n                    ],\n                    builder: (context, routes, index) {\n                      final delegate = context.delegate;\n                      return BottomNavigationBar(\n                        currentIndex: index,\n                        onTap: (value) => delegate.toNamed(routes[value]),\n                        items: const [\n                          // _Paths.HOME + [Empty]\n                          BottomNavigationBarItem(\n                            icon: Icon(Icons.home),\n                            label: 'Home',\n                          ),\n                          // _Paths.HOME + Routes.PROFILE\n                          BottomNavigationBarItem(\n                            icon: Icon(Icons.account_box_rounded),\n                            label: 'Profile',\n                          ),\n                          // _Paths.HOME + _Paths.PRODUCTS\n                          BottomNavigationBarItem(\n                            icon: Icon(Icons.account_box_rounded),\n                            label: 'Products',\n                          ),\n                        ],\n                      );\n                    }),\n              );\n            },\n          ),\n        ),\n      ],\n    );\n  }\n}\n"
  },
  {
    "path": "example_nav2/lib/app/modules/login/bindings/login_binding.dart",
    "content": "import 'package:get/get.dart';\n\nimport '../controllers/login_controller.dart';\n\nclass LoginBinding extends Binding {\n  @override\n  List<Bind> dependencies() {\n    return [\n      Bind.lazyPut(() => LoginController()),\n    ];\n  }\n}\n"
  },
  {
    "path": "example_nav2/lib/app/modules/login/controllers/login_controller.dart",
    "content": "import 'package:get/get.dart';\n\nclass LoginController extends GetxController {}\n"
  },
  {
    "path": "example_nav2/lib/app/modules/login/views/login_view.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:get/get.dart';\n\nimport '../../../../services/auth_service.dart';\nimport '../../../routes/app_pages.dart';\nimport '../controllers/login_controller.dart';\n\nclass LoginView extends GetView<LoginController> {\n  const LoginView({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      body: Center(\n        child: Column(\n          mainAxisSize: MainAxisSize.min,\n          children: [\n            Obx(\n              () {\n                final isLoggedIn = AuthService.to.isLoggedInValue;\n                return Text(\n                  'You are currently:'\n                  ' ${isLoggedIn ? \"Logged In\" : \"Not Logged In\"}'\n                  \"\\nIt's impossible to enter this \"\n                  \"route when you are logged in!\",\n                );\n              },\n            ),\n            MaterialButton(\n              child: const Text(\n                'Do LOGIN !!',\n                style: TextStyle(color: Colors.blue, fontSize: 20),\n              ),\n              onPressed: () {\n                AuthService.to.login();\n                final thenTo = context.params['then'];\n                Get.offNamed(thenTo ?? Routes.home);\n              },\n            ),\n          ],\n        ),\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "example_nav2/lib/app/modules/product_details/bindings/product_details_binding.dart",
    "content": "import 'package:get/get.dart';\n\nimport '../controllers/product_details_controller.dart';\n\nclass ProductDetailsBinding extends Binding {\n  @override\n  List<Bind> dependencies() {\n    return [\n      Bind.spawn<ProductDetailsController>(\n        () => ProductDetailsController(\n          Get.parameters['productId'] ?? '',\n        ),\n      )\n    ];\n  }\n}\n"
  },
  {
    "path": "example_nav2/lib/app/modules/product_details/controllers/product_details_controller.dart",
    "content": "import 'package:get/get.dart';\n\nclass ProductDetailsController extends GetxController {\n  final String productId;\n\n  ProductDetailsController(this.productId);\n  @override\n  void onInit() {\n    super.onInit();\n    Get.log('ProductDetailsController created with id: $productId');\n  }\n\n  @override\n  void onClose() {\n    Get.log('ProductDetailsController close with id: $productId');\n\n    super.onClose();\n  }\n}\n"
  },
  {
    "path": "example_nav2/lib/app/modules/product_details/views/product_details_view.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:get/get.dart';\n\nimport '../controllers/product_details_controller.dart';\n\nclass ProductDetailsView extends GetWidget<ProductDetailsController> {\n  const ProductDetailsView({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      body: Center(\n        child: Column(\n          mainAxisSize: MainAxisSize.min,\n          children: [\n            const Text(\n              'ProductDetailsView is working',\n              style: TextStyle(fontSize: 20),\n            ),\n            Text('ProductId: ${controller.productId}')\n          ],\n        ),\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "example_nav2/lib/app/modules/products/bindings/products_binding.dart",
    "content": "import 'package:get/get.dart';\n\nimport '../controllers/products_controller.dart';\n\nclass ProductsBinding extends Binding {\n  @override\n  List<Bind> dependencies() {\n    return [\n      Bind.lazyPut<ProductsController>(\n        () => ProductsController(),\n      )\n    ];\n  }\n}\n"
  },
  {
    "path": "example_nav2/lib/app/modules/products/controllers/products_controller.dart",
    "content": "import 'package:get/get.dart';\n\nimport '../../../../models/demo_product.dart';\n\nclass ProductsController extends GetxController {\n  final products = <DemoProduct>[].obs;\n\n  void loadDemoProductsFromSomeWhere() {\n    products.add(\n      DemoProduct(\n        name: 'Product added on: ${DateTime.now().toString()}',\n        id: DateTime.now().millisecondsSinceEpoch.toString(),\n      ),\n    );\n  }\n\n  @override\n  void onReady() {\n    super.onReady();\n    loadDemoProductsFromSomeWhere();\n  }\n\n  @override\n  void onClose() {\n    Get.printInfo(info: 'Products: onClose');\n    super.onClose();\n  }\n}\n"
  },
  {
    "path": "example_nav2/lib/app/modules/products/views/products_view.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:get/get.dart';\n\nimport '../../../routes/app_pages.dart';\nimport '../controllers/products_controller.dart';\n\nclass ProductsView extends GetView<ProductsController> {\n  const ProductsView({super.key});\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      floatingActionButton: FloatingActionButton.extended(\n        onPressed: () => controller.loadDemoProductsFromSomeWhere(),\n        label: const Text('Add'),\n      ),\n      body: Column(\n        children: [\n          const Hero(\n            tag: 'heroLogo',\n            child: FlutterLogo(),\n          ),\n          Expanded(\n            child: Obx(\n              () => RefreshIndicator(\n                onRefresh: () async {\n                  controller.products.clear();\n                  controller.loadDemoProductsFromSomeWhere();\n                },\n                child: ListView.builder(\n                  itemCount: controller.products.length,\n                  itemBuilder: (context, index) {\n                    final item = controller.products[index];\n                    return ListTile(\n                      onTap: () {\n                        Get.toNamed(Routes.PRODUCT_DETAILS(item.id));\n                      },\n                      title: Text(item.name),\n                      subtitle: Text(item.id),\n                    );\n                  },\n                ),\n              ),\n            ),\n          ),\n        ],\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "example_nav2/lib/app/modules/profile/bindings/profile_binding.dart",
    "content": "import 'package:get/get.dart';\n\nimport '../controllers/profile_controller.dart';\n\nclass ProfileBinding extends Binding {\n  @override\n  List<Bind> dependencies() {\n    return [\n      Bind.lazyPut<ProfileController>(\n        () => ProfileController(),\n      )\n    ];\n  }\n}\n"
  },
  {
    "path": "example_nav2/lib/app/modules/profile/controllers/profile_controller.dart",
    "content": "import 'package:get/get.dart';\n\nclass ProfileController extends GetxController {}\n"
  },
  {
    "path": "example_nav2/lib/app/modules/profile/views/profile_view.dart",
    "content": "import 'package:flutter/material.dart';\r\nimport 'package:get/get.dart';\r\n\r\nimport '../../../routes/app_pages.dart';\r\nimport '../controllers/profile_controller.dart';\r\n\r\nclass ProfileView extends GetView<ProfileController> {\r\n  const ProfileView({super.key});\r\n\r\n  @override\r\n  Widget build(BuildContext context) {\r\n    return Scaffold(\r\n      backgroundColor: Colors.amber,\r\n      body: Center(\r\n        child: Column(\r\n          mainAxisSize: MainAxisSize.min,\r\n          children: [\r\n            const Text(\r\n              'ProfileView is working',\r\n              style: TextStyle(fontSize: 20),\r\n            ),\r\n            const Hero(\r\n              tag: 'heroLogo',\r\n              child: FlutterLogo(),\r\n            ),\r\n            MaterialButton(\r\n              child: const Text('Show a test dialog'),\r\n              onPressed: () {\r\n                //shows a dialog\r\n                Get.defaultDialog(\r\n                  title: 'Test Dialog !!',\r\n                  barrierDismissible: true,\r\n                );\r\n              },\r\n            ),\r\n            MaterialButton(\r\n              child: const Text('Show a test dialog in Home router outlet'),\r\n              onPressed: () {\r\n                //shows a dialog\r\n                Get.defaultDialog(\r\n                  title: 'Test Dialog In Home Outlet !!',\r\n                  barrierDismissible: true,\r\n                  id: Routes.home,\r\n                  // navigatorKey: Get.nestedKey(Routes.HOME),\r\n                );\r\n              },\r\n            )\r\n          ],\r\n        ),\r\n      ),\r\n    );\r\n  }\r\n}\r\n"
  },
  {
    "path": "example_nav2/lib/app/modules/root/bindings/root_binding.dart",
    "content": "import 'package:get/get.dart';\n\nimport '../controllers/root_controller.dart';\n\nclass RootBinding extends Binding {\n  @override\n  List<Bind> dependencies() {\n    return [\n      Bind.lazyPut<RootController>(\n        () => RootController(),\n      )\n    ];\n  }\n}\n"
  },
  {
    "path": "example_nav2/lib/app/modules/root/controllers/root_controller.dart",
    "content": "import 'package:get/get.dart';\n\nclass RootController extends GetxController {\n  final count = 0.obs;\n  @override\n  void onInit() {\n    super.onInit();\n  }\n\n  @override\n  void onClose() {}\n  void increment() => count.value++;\n}\n"
  },
  {
    "path": "example_nav2/lib/app/modules/root/views/drawer.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:get/get.dart';\n\nimport '../../../../services/auth_service.dart';\nimport '../../../routes/app_pages.dart';\n\nclass DrawerWidget extends StatelessWidget {\n  const DrawerWidget({\n    super.key,\n  });\n\n  @override\n  Widget build(BuildContext context) {\n    return Drawer(\n      child: Column(\n        children: [\n          Container(\n            height: 100,\n            color: Colors.red,\n          ),\n          ListTile(\n            title: const Text('Home'),\n            onTap: () {\n              Get.toNamed(Routes.home);\n              //to close the drawer\n\n              Navigator.of(context).pop();\n            },\n          ),\n          ListTile(\n            title: const Text('Settings'),\n            onTap: () {\n              Get.toNamed(Routes.settings);\n              //to close the drawer\n\n              Navigator.of(context).pop();\n            },\n          ),\n          if (AuthService.to.isLoggedInValue)\n            ListTile(\n              title: const Text(\n                'Logout',\n                style: TextStyle(\n                  color: Colors.red,\n                ),\n              ),\n              onTap: () {\n                AuthService.to.logout();\n                Get.toNamed(Routes.login);\n                //to close the drawer\n\n                Navigator.of(context).pop();\n              },\n            ),\n          if (!AuthService.to.isLoggedInValue)\n            ListTile(\n              title: const Text(\n                'Login',\n                style: TextStyle(\n                  color: Colors.blue,\n                ),\n              ),\n              onTap: () {\n                Get.toNamed(Routes.login);\n                //to close the drawer\n\n                Navigator.of(context).pop();\n              },\n            ),\n        ],\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "example_nav2/lib/app/modules/root/views/root_view.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:get/get.dart';\n\nimport '../../../routes/app_pages.dart';\nimport '../controllers/root_controller.dart';\nimport 'drawer.dart';\n\nclass RootView extends GetView<RootController> {\n  const RootView({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      drawer: const DrawerWidget(),\n      appBar: AppBar(\n        title: RouterListener(builder: (context) {\n          final title = context.location;\n          return Text(title);\n        }),\n        centerTitle: true,\n      ),\n      //body: HomeView(),\n\n      body: GetRouterOutlet(\n        initialRoute: Routes.home,\n        anchorRoute: '/',\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "example_nav2/lib/app/modules/settings/bindings/settings_binding.dart",
    "content": "import 'package:get/get.dart';\n\nimport '../controllers/settings_controller.dart';\n\nclass SettingsBinding extends Binding {\n  @override\n  List<Bind> dependencies() {\n    return [\n      Bind.lazyPut<SettingsController>(\n        () => SettingsController(),\n      )\n    ];\n  }\n}\n"
  },
  {
    "path": "example_nav2/lib/app/modules/settings/controllers/settings_controller.dart",
    "content": "import 'package:get/get.dart';\n\nclass SettingsController extends GetxController {\n  final count = 0.obs;\n  @override\n  void onInit() {\n    super.onInit();\n  }\n\n  @override\n  void onClose() {}\n  void increment() => count.value++;\n}\n"
  },
  {
    "path": "example_nav2/lib/app/modules/settings/views/settings_view.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:get/get.dart';\n\nimport '../controllers/settings_controller.dart';\n\nclass SettingsView extends GetView<SettingsController> {\n  const SettingsView({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return const Scaffold(\n      body: Center(\n        child: Text(\n          'SettingsView is working',\n          style: TextStyle(fontSize: 20),\n        ),\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "example_nav2/lib/app/routes/app_pages.dart",
    "content": "import 'dart:developer';\n\nimport 'package:flutter/material.dart';\nimport 'package:get/get.dart';\n\nimport '../middleware/auth_middleware.dart';\nimport '../modules/dashboard/bindings/dashboard_binding.dart';\nimport '../modules/dashboard/views/dashboard_view.dart';\nimport '../modules/home/bindings/home_binding.dart';\nimport '../modules/home/views/home_view.dart';\nimport '../modules/login/bindings/login_binding.dart';\nimport '../modules/login/views/login_view.dart';\nimport '../modules/product_details/bindings/product_details_binding.dart';\nimport '../modules/product_details/views/product_details_view.dart';\nimport '../modules/products/bindings/products_binding.dart';\nimport '../modules/products/views/products_view.dart';\nimport '../modules/profile/bindings/profile_binding.dart';\nimport '../modules/profile/views/profile_view.dart';\nimport '../modules/root/bindings/root_binding.dart';\nimport '../modules/root/views/root_view.dart';\nimport '../modules/settings/bindings/settings_binding.dart';\nimport '../modules/settings/views/settings_view.dart';\n\npart 'app_routes.dart';\n\nclass AppPages {\n  AppPages._();\n\n  static const initial = Routes.home;\n\n  static final routes = [\n    GetPage(\n      name: '/',\n      page: () => const RootView(),\n      bindings: [RootBinding()],\n      participatesInRootNavigator: true,\n      preventDuplicates: true,\n      children: [\n        GetPage(\n          middlewares: [\n            //only enter this route when not authed\n            EnsureNotAuthedMiddleware(),\n          ],\n          name: _Paths.login,\n          page: () => const LoginView(),\n          bindings: [LoginBinding()],\n        ),\n        GetPage(\n          preventDuplicates: true,\n          name: _Paths.home,\n          page: () => const HomeView(),\n          bindings: [\n            HomeBinding(),\n          ],\n          title: null,\n          children: [\n            GetPage(\n              name: _Paths.dashboard,\n              page: () => const DashboardView(),\n              bindings: [\n                DashboardBinding(),\n              ],\n            ),\n            GetPage(\n              middlewares: [\n                //only enter this route when authed\n                EnsureAuthMiddleware(),\n              ],\n              name: _Paths.profile,\n              page: () => const ProfileView(),\n              title: 'Profile',\n              transition: Transition.size,\n              bindings: [ProfileBinding()],\n            ),\n            GetPage(\n              name: _Paths.products,\n              page: () => const ProductsView(),\n              title: 'Products',\n              transition: Transition.cupertino,\n              showCupertinoParallax: true,\n              participatesInRootNavigator: false,\n              bindings: [ProductsBinding(), ProductDetailsBinding()],\n              children: [\n                GetPage(\n                  name: _Paths.productDetails,\n                  transition: Transition.cupertino,\n                  showCupertinoParallax: true,\n                  page: () => const ProductDetailsView(),\n                  bindings: const [],\n                  middlewares: [\n                    //only enter this route when authed\n                    EnsureAuthMiddleware(),\n                  ],\n                ),\n              ],\n            ),\n          ],\n        ),\n        GetPage(\n          name: _Paths.settings,\n          page: () => const SettingsView(),\n          bindings: [\n            SettingsBinding(),\n          ],\n        ),\n      ],\n    ),\n  ];\n}\n\nclass MainMiddleware extends GetMiddleware {\n  @override\n  void onPageDispose() {\n    log('MainMiddleware onPageDispose');\n    super.onPageDispose();\n  }\n\n  @override\n  Widget onPageBuilt(Widget page) {\n    log('MainMiddleware onPageBuilt');\n    return super.onPageBuilt(page);\n  }\n\n  @override\n  GetPage? onPageCalled(GetPage? page) {\n    log('MainMiddleware onPageCalled for route: ${page?.name}');\n    return super.onPageCalled(page);\n  }\n\n  @override\n  List<R>? onBindingsStart<R>(List<R>? bindings) {\n    log('MainMiddleware onBindingsStart');\n    return super.onBindingsStart(bindings);\n  }\n\n  @override\n  GetPageBuilder? onPageBuildStart(GetPageBuilder? page) {\n    log('MainMiddleware onPageBuildStart');\n\n    return super.onPageBuildStart(page);\n  }\n}\n"
  },
  {
    "path": "example_nav2/lib/app/routes/app_routes.dart",
    "content": "// ignore_for_file: non_constant_identifier_names\n\npart of 'app_pages.dart';\n// DO NOT EDIT. This is code generated via package:get_cli/get_cli.dart\n\nabstract class Routes {\n  static const home = _Paths.home;\n\n  static const profile = _Paths.home + _Paths.profile;\n  static const settings = _Paths.settings;\n\n  static const products = _Paths.home + _Paths.products;\n\n  static const login = _Paths.login;\n  static const dashboard = _Paths.home + _Paths.dashboard;\n  Routes._();\n  static String LOGIN_THEN(String afterSuccessfulLogin) =>\n      '$login?then=${Uri.encodeQueryComponent(afterSuccessfulLogin)}';\n  static String PRODUCT_DETAILS(String productId) => '$products/$productId';\n}\n\nabstract class _Paths {\n  static const home = '/home';\n  static const products = '/products';\n  static const profile = '/profile';\n  static const settings = '/settings';\n  static const productDetails = '/:productId';\n  static const login = '/login';\n  static const dashboard = '/dashboard';\n}\n"
  },
  {
    "path": "example_nav2/lib/main.dart",
    "content": "import 'package:flutter/material.dart';\r\nimport 'package:get/get.dart';\r\n\r\nimport './services/auth_service.dart';\r\nimport 'app/routes/app_pages.dart';\r\n\r\nvoid main() {\r\n  runApp(\r\n    GetMaterialApp(\r\n      title: \"Application\",\r\n      binds: [\r\n        Bind.put(AuthService()),\r\n      ],\r\n      getPages: AppPages.routes,\r\n      initialRoute: AppPages.initial,\r\n      // builder: (context, child) {\r\n      //   return FutureBuilder<void>(\r\n      //     key: ValueKey('initFuture'),\r\n      //     future: Get.find<SplashService>().init(),\r\n      //     builder: (context, snapshot) {\r\n      //       if (snapshot.connectionState == ConnectionState.done) {\r\n      //         return child ?? SizedBox.shrink();\r\n      //       }\r\n      //       return SplashView();\r\n      //     },\r\n      //   );\r\n      // },\r\n      // routeInformationParser: GetInformationParser(\r\n      //     // initialRoute: Routes.HOME,\r\n      //     ),\r\n      // routerDelegate: GetDelegate(\r\n      //   backButtonPopMode: PopMode.History,\r\n      //   preventDuplicateHandlingMode:\r\n      //       PreventDuplicateHandlingMode.ReorderRoutes,\r\n      // ),\r\n    ),\r\n  );\r\n}\r\n"
  },
  {
    "path": "example_nav2/lib/models/demo_product.dart",
    "content": "class DemoProduct {\r\n  final String name;\r\n  final String id;\r\n\r\n  DemoProduct({\r\n    required this.name,\r\n    required this.id,\r\n  });\r\n}\r\n"
  },
  {
    "path": "example_nav2/lib/services/auth_service.dart",
    "content": "import 'package:get/get.dart';\r\n\r\nclass AuthService extends GetxService {\r\n  static AuthService get to => Get.find();\r\n\r\n  /// Mocks a login process\r\n  final isLoggedIn = false.obs;\r\n  bool get isLoggedInValue => isLoggedIn.value;\r\n\r\n  void login() {\r\n    isLoggedIn.value = true;\r\n  }\r\n\r\n  void logout() {\r\n    isLoggedIn.value = false;\r\n  }\r\n}\r\n"
  },
  {
    "path": "example_nav2/linux/.gitignore",
    "content": "flutter/ephemeral\n"
  },
  {
    "path": "example_nav2/linux/CMakeLists.txt",
    "content": "# Project-level configuration.\ncmake_minimum_required(VERSION 3.10)\nproject(runner LANGUAGES CXX)\n\n# The name of the executable created for the application. Change this to change\n# the on-disk name of your application.\nset(BINARY_NAME \"example_nav2\")\n# The unique GTK application identifier for this application. See:\n# https://wiki.gnome.org/HowDoI/ChooseApplicationID\nset(APPLICATION_ID \"com.get.example_nav2\")\n\n# Explicitly opt in to modern CMake behaviors to avoid warnings with recent\n# versions of CMake.\ncmake_policy(SET CMP0063 NEW)\n\n# Load bundled libraries from the lib/ directory relative to the binary.\nset(CMAKE_INSTALL_RPATH \"$ORIGIN/lib\")\n\n# Root filesystem for cross-building.\nif(FLUTTER_TARGET_PLATFORM_SYSROOT)\n  set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT})\n  set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})\n  set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)\n  set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)\n  set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)\n  set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)\nendif()\n\n# Define build configuration options.\nif(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)\n  set(CMAKE_BUILD_TYPE \"Debug\" CACHE\n    STRING \"Flutter build mode\" FORCE)\n  set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS\n    \"Debug\" \"Profile\" \"Release\")\nendif()\n\n# Compilation settings that should be applied to most targets.\n#\n# Be cautious about adding new options here, as plugins use this function by\n# default. In most cases, you should add new options to specific targets instead\n# of modifying this function.\nfunction(APPLY_STANDARD_SETTINGS TARGET)\n  target_compile_features(${TARGET} PUBLIC cxx_std_14)\n  target_compile_options(${TARGET} PRIVATE -Wall -Werror)\n  target_compile_options(${TARGET} PRIVATE \"$<$<NOT:$<CONFIG:Debug>>:-O3>\")\n  target_compile_definitions(${TARGET} PRIVATE \"$<$<NOT:$<CONFIG:Debug>>:NDEBUG>\")\nendfunction()\n\n# Flutter library and tool build rules.\nset(FLUTTER_MANAGED_DIR \"${CMAKE_CURRENT_SOURCE_DIR}/flutter\")\nadd_subdirectory(${FLUTTER_MANAGED_DIR})\n\n# System-level dependencies.\nfind_package(PkgConfig REQUIRED)\npkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)\n\nadd_definitions(-DAPPLICATION_ID=\"${APPLICATION_ID}\")\n\n# Define the application target. To change its name, change BINARY_NAME above,\n# not the value here, or `flutter run` will no longer work.\n#\n# Any new source files that you add to the application should be added here.\nadd_executable(${BINARY_NAME}\n  \"main.cc\"\n  \"my_application.cc\"\n  \"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc\"\n)\n\n# Apply the standard set of build settings. This can be removed for applications\n# that need different build settings.\napply_standard_settings(${BINARY_NAME})\n\n# Add dependency libraries. Add any application-specific dependencies here.\ntarget_link_libraries(${BINARY_NAME} PRIVATE flutter)\ntarget_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)\n\n# Run the Flutter tool portions of the build. This must not be removed.\nadd_dependencies(${BINARY_NAME} flutter_assemble)\n\n# Only the install-generated bundle's copy of the executable will launch\n# correctly, since the resources must in the right relative locations. To avoid\n# people trying to run the unbundled copy, put it in a subdirectory instead of\n# the default top-level location.\nset_target_properties(${BINARY_NAME}\n  PROPERTIES\n  RUNTIME_OUTPUT_DIRECTORY \"${CMAKE_BINARY_DIR}/intermediates_do_not_run\"\n)\n\n# Generated plugin build rules, which manage building the plugins and adding\n# them to the application.\ninclude(flutter/generated_plugins.cmake)\n\n\n# === Installation ===\n# By default, \"installing\" just makes a relocatable bundle in the build\n# directory.\nset(BUILD_BUNDLE_DIR \"${PROJECT_BINARY_DIR}/bundle\")\nif(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)\n  set(CMAKE_INSTALL_PREFIX \"${BUILD_BUNDLE_DIR}\" CACHE PATH \"...\" FORCE)\nendif()\n\n# Start with a clean build bundle directory every time.\ninstall(CODE \"\n  file(REMOVE_RECURSE \\\"${BUILD_BUNDLE_DIR}/\\\")\n  \" COMPONENT Runtime)\n\nset(INSTALL_BUNDLE_DATA_DIR \"${CMAKE_INSTALL_PREFIX}/data\")\nset(INSTALL_BUNDLE_LIB_DIR \"${CMAKE_INSTALL_PREFIX}/lib\")\n\ninstall(TARGETS ${BINARY_NAME} RUNTIME DESTINATION \"${CMAKE_INSTALL_PREFIX}\"\n  COMPONENT Runtime)\n\ninstall(FILES \"${FLUTTER_ICU_DATA_FILE}\" DESTINATION \"${INSTALL_BUNDLE_DATA_DIR}\"\n  COMPONENT Runtime)\n\ninstall(FILES \"${FLUTTER_LIBRARY}\" DESTINATION \"${INSTALL_BUNDLE_LIB_DIR}\"\n  COMPONENT Runtime)\n\nforeach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES})\n  install(FILES \"${bundled_library}\"\n    DESTINATION \"${INSTALL_BUNDLE_LIB_DIR}\"\n    COMPONENT Runtime)\nendforeach(bundled_library)\n\n# Fully re-copy the assets directory on each build to avoid having stale files\n# from a previous install.\nset(FLUTTER_ASSET_DIR_NAME \"flutter_assets\")\ninstall(CODE \"\n  file(REMOVE_RECURSE \\\"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\\\")\n  \" COMPONENT Runtime)\ninstall(DIRECTORY \"${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}\"\n  DESTINATION \"${INSTALL_BUNDLE_DATA_DIR}\" COMPONENT Runtime)\n\n# Install the AOT library on non-Debug builds only.\nif(NOT CMAKE_BUILD_TYPE MATCHES \"Debug\")\n  install(FILES \"${AOT_LIBRARY}\" DESTINATION \"${INSTALL_BUNDLE_LIB_DIR}\"\n    COMPONENT Runtime)\nendif()\n"
  },
  {
    "path": "example_nav2/linux/flutter/CMakeLists.txt",
    "content": "# This file controls Flutter-level build steps. It should not be edited.\ncmake_minimum_required(VERSION 3.10)\n\nset(EPHEMERAL_DIR \"${CMAKE_CURRENT_SOURCE_DIR}/ephemeral\")\n\n# Configuration provided via flutter tool.\ninclude(${EPHEMERAL_DIR}/generated_config.cmake)\n\n# TODO: Move the rest of this into files in ephemeral. See\n# https://github.com/flutter/flutter/issues/57146.\n\n# Serves the same purpose as list(TRANSFORM ... PREPEND ...),\n# which isn't available in 3.10.\nfunction(list_prepend LIST_NAME PREFIX)\n    set(NEW_LIST \"\")\n    foreach(element ${${LIST_NAME}})\n        list(APPEND NEW_LIST \"${PREFIX}${element}\")\n    endforeach(element)\n    set(${LIST_NAME} \"${NEW_LIST}\" PARENT_SCOPE)\nendfunction()\n\n# === Flutter Library ===\n# System-level dependencies.\nfind_package(PkgConfig REQUIRED)\npkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)\npkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0)\npkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0)\n\nset(FLUTTER_LIBRARY \"${EPHEMERAL_DIR}/libflutter_linux_gtk.so\")\n\n# Published to parent scope for install step.\nset(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)\nset(FLUTTER_ICU_DATA_FILE \"${EPHEMERAL_DIR}/icudtl.dat\" PARENT_SCOPE)\nset(PROJECT_BUILD_DIR \"${PROJECT_DIR}/build/\" PARENT_SCOPE)\nset(AOT_LIBRARY \"${PROJECT_DIR}/build/lib/libapp.so\" PARENT_SCOPE)\n\nlist(APPEND FLUTTER_LIBRARY_HEADERS\n  \"fl_basic_message_channel.h\"\n  \"fl_binary_codec.h\"\n  \"fl_binary_messenger.h\"\n  \"fl_dart_project.h\"\n  \"fl_engine.h\"\n  \"fl_json_message_codec.h\"\n  \"fl_json_method_codec.h\"\n  \"fl_message_codec.h\"\n  \"fl_method_call.h\"\n  \"fl_method_channel.h\"\n  \"fl_method_codec.h\"\n  \"fl_method_response.h\"\n  \"fl_plugin_registrar.h\"\n  \"fl_plugin_registry.h\"\n  \"fl_standard_message_codec.h\"\n  \"fl_standard_method_codec.h\"\n  \"fl_string_codec.h\"\n  \"fl_value.h\"\n  \"fl_view.h\"\n  \"flutter_linux.h\"\n)\nlist_prepend(FLUTTER_LIBRARY_HEADERS \"${EPHEMERAL_DIR}/flutter_linux/\")\nadd_library(flutter INTERFACE)\ntarget_include_directories(flutter INTERFACE\n  \"${EPHEMERAL_DIR}\"\n)\ntarget_link_libraries(flutter INTERFACE \"${FLUTTER_LIBRARY}\")\ntarget_link_libraries(flutter INTERFACE\n  PkgConfig::GTK\n  PkgConfig::GLIB\n  PkgConfig::GIO\n)\nadd_dependencies(flutter flutter_assemble)\n\n# === Flutter tool backend ===\n# _phony_ is a non-existent file to force this command to run every time,\n# since currently there's no way to get a full input/output list from the\n# flutter tool.\nadd_custom_command(\n  OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}\n    ${CMAKE_CURRENT_BINARY_DIR}/_phony_\n  COMMAND ${CMAKE_COMMAND} -E env\n    ${FLUTTER_TOOL_ENVIRONMENT}\n    \"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh\"\n      ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE}\n  VERBATIM\n)\nadd_custom_target(flutter_assemble DEPENDS\n  \"${FLUTTER_LIBRARY}\"\n  ${FLUTTER_LIBRARY_HEADERS}\n)\n"
  },
  {
    "path": "example_nav2/linux/flutter/generated_plugin_registrant.cc",
    "content": "//\n//  Generated file. Do not edit.\n//\n\n// clang-format off\n\n#include \"generated_plugin_registrant.h\"\n\n\nvoid fl_register_plugins(FlPluginRegistry* registry) {\n}\n"
  },
  {
    "path": "example_nav2/linux/flutter/generated_plugin_registrant.h",
    "content": "//\n//  Generated file. Do not edit.\n//\n\n// clang-format off\n\n#ifndef GENERATED_PLUGIN_REGISTRANT_\n#define GENERATED_PLUGIN_REGISTRANT_\n\n#include <flutter_linux/flutter_linux.h>\n\n// Registers Flutter plugins.\nvoid fl_register_plugins(FlPluginRegistry* registry);\n\n#endif  // GENERATED_PLUGIN_REGISTRANT_\n"
  },
  {
    "path": "example_nav2/linux/flutter/generated_plugins.cmake",
    "content": "#\n# Generated file, do not edit.\n#\n\nlist(APPEND FLUTTER_PLUGIN_LIST\n)\n\nlist(APPEND FLUTTER_FFI_PLUGIN_LIST\n)\n\nset(PLUGIN_BUNDLED_LIBRARIES)\n\nforeach(plugin ${FLUTTER_PLUGIN_LIST})\n  add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin})\n  target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)\n  list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)\n  list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})\nendforeach(plugin)\n\nforeach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})\n  add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin})\n  list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})\nendforeach(ffi_plugin)\n"
  },
  {
    "path": "example_nav2/linux/main.cc",
    "content": "#include \"my_application.h\"\n\nint main(int argc, char** argv) {\n  g_autoptr(MyApplication) app = my_application_new();\n  return g_application_run(G_APPLICATION(app), argc, argv);\n}\n"
  },
  {
    "path": "example_nav2/linux/my_application.cc",
    "content": "#include \"my_application.h\"\n\n#include <flutter_linux/flutter_linux.h>\n#ifdef GDK_WINDOWING_X11\n#include <gdk/gdkx.h>\n#endif\n\n#include \"flutter/generated_plugin_registrant.h\"\n\nstruct _MyApplication {\n  GtkApplication parent_instance;\n  char** dart_entrypoint_arguments;\n};\n\nG_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION)\n\n// Implements GApplication::activate.\nstatic void my_application_activate(GApplication* application) {\n  MyApplication* self = MY_APPLICATION(application);\n  GtkWindow* window =\n      GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));\n\n  // Use a header bar when running in GNOME as this is the common style used\n  // by applications and is the setup most users will be using (e.g. Ubuntu\n  // desktop).\n  // If running on X and not using GNOME then just use a traditional title bar\n  // in case the window manager does more exotic layout, e.g. tiling.\n  // If running on Wayland assume the header bar will work (may need changing\n  // if future cases occur).\n  gboolean use_header_bar = TRUE;\n#ifdef GDK_WINDOWING_X11\n  GdkScreen* screen = gtk_window_get_screen(window);\n  if (GDK_IS_X11_SCREEN(screen)) {\n    const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen);\n    if (g_strcmp0(wm_name, \"GNOME Shell\") != 0) {\n      use_header_bar = FALSE;\n    }\n  }\n#endif\n  if (use_header_bar) {\n    GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new());\n    gtk_widget_show(GTK_WIDGET(header_bar));\n    gtk_header_bar_set_title(header_bar, \"example_nav2\");\n    gtk_header_bar_set_show_close_button(header_bar, TRUE);\n    gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));\n  } else {\n    gtk_window_set_title(window, \"example_nav2\");\n  }\n\n  gtk_window_set_default_size(window, 1280, 720);\n  gtk_widget_show(GTK_WIDGET(window));\n\n  g_autoptr(FlDartProject) project = fl_dart_project_new();\n  fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments);\n\n  FlView* view = fl_view_new(project);\n  gtk_widget_show(GTK_WIDGET(view));\n  gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view));\n\n  fl_register_plugins(FL_PLUGIN_REGISTRY(view));\n\n  gtk_widget_grab_focus(GTK_WIDGET(view));\n}\n\n// Implements GApplication::local_command_line.\nstatic gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) {\n  MyApplication* self = MY_APPLICATION(application);\n  // Strip out the first argument as it is the binary name.\n  self->dart_entrypoint_arguments = g_strdupv(*arguments + 1);\n\n  g_autoptr(GError) error = nullptr;\n  if (!g_application_register(application, nullptr, &error)) {\n     g_warning(\"Failed to register: %s\", error->message);\n     *exit_status = 1;\n     return TRUE;\n  }\n\n  g_application_activate(application);\n  *exit_status = 0;\n\n  return TRUE;\n}\n\n// Implements GObject::dispose.\nstatic void my_application_dispose(GObject* object) {\n  MyApplication* self = MY_APPLICATION(object);\n  g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev);\n  G_OBJECT_CLASS(my_application_parent_class)->dispose(object);\n}\n\nstatic void my_application_class_init(MyApplicationClass* klass) {\n  G_APPLICATION_CLASS(klass)->activate = my_application_activate;\n  G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line;\n  G_OBJECT_CLASS(klass)->dispose = my_application_dispose;\n}\n\nstatic void my_application_init(MyApplication* self) {}\n\nMyApplication* my_application_new() {\n  return MY_APPLICATION(g_object_new(my_application_get_type(),\n                                     \"application-id\", APPLICATION_ID,\n                                     \"flags\", G_APPLICATION_NON_UNIQUE,\n                                     nullptr));\n}\n"
  },
  {
    "path": "example_nav2/linux/my_application.h",
    "content": "#ifndef FLUTTER_MY_APPLICATION_H_\n#define FLUTTER_MY_APPLICATION_H_\n\n#include <gtk/gtk.h>\n\nG_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION,\n                     GtkApplication)\n\n/**\n * my_application_new:\n *\n * Creates a new Flutter-based application.\n *\n * Returns: a new #MyApplication.\n */\nMyApplication* my_application_new();\n\n#endif  // FLUTTER_MY_APPLICATION_H_\n"
  },
  {
    "path": "example_nav2/linux/runner/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.13)\nproject(runner LANGUAGES CXX)\n\n# Define the application target. To change its name, change BINARY_NAME in the\n# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer\n# work.\n#\n# Any new source files that you add to the application should be added here.\nadd_executable(${BINARY_NAME}\n  \"main.cc\"\n  \"my_application.cc\"\n  \"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc\"\n)\n\n# Apply the standard set of build settings. This can be removed for applications\n# that need different build settings.\napply_standard_settings(${BINARY_NAME})\n\n# Add preprocessor definitions for the application ID.\nadd_definitions(-DAPPLICATION_ID=\"${APPLICATION_ID}\")\n\n# Add dependency libraries. Add any application-specific dependencies here.\ntarget_link_libraries(${BINARY_NAME} PRIVATE flutter)\ntarget_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)\n\ntarget_include_directories(${BINARY_NAME} PRIVATE \"${CMAKE_SOURCE_DIR}\")\n"
  },
  {
    "path": "example_nav2/linux/runner/main.cc",
    "content": "#include \"my_application.h\"\n\nint main(int argc, char** argv) {\n  g_autoptr(MyApplication) app = my_application_new();\n  return g_application_run(G_APPLICATION(app), argc, argv);\n}\n"
  },
  {
    "path": "example_nav2/linux/runner/my_application.cc",
    "content": "#include \"my_application.h\"\n\n#include <flutter_linux/flutter_linux.h>\n#ifdef GDK_WINDOWING_X11\n#include <gdk/gdkx.h>\n#endif\n\n#include \"flutter/generated_plugin_registrant.h\"\n\nstruct _MyApplication {\n  GtkApplication parent_instance;\n  char** dart_entrypoint_arguments;\n};\n\nG_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION)\n\n// Implements GApplication::activate.\nstatic void my_application_activate(GApplication* application) {\n  MyApplication* self = MY_APPLICATION(application);\n  GtkWindow* window =\n      GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));\n\n  // Use a header bar when running in GNOME as this is the common style used\n  // by applications and is the setup most users will be using (e.g. Ubuntu\n  // desktop).\n  // If running on X and not using GNOME then just use a traditional title bar\n  // in case the window manager does more exotic layout, e.g. tiling.\n  // If running on Wayland assume the header bar will work (may need changing\n  // if future cases occur).\n  gboolean use_header_bar = TRUE;\n#ifdef GDK_WINDOWING_X11\n  GdkScreen* screen = gtk_window_get_screen(window);\n  if (GDK_IS_X11_SCREEN(screen)) {\n    const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen);\n    if (g_strcmp0(wm_name, \"GNOME Shell\") != 0) {\n      use_header_bar = FALSE;\n    }\n  }\n#endif\n  if (use_header_bar) {\n    GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new());\n    gtk_widget_show(GTK_WIDGET(header_bar));\n    gtk_header_bar_set_title(header_bar, \"example_nav2\");\n    gtk_header_bar_set_show_close_button(header_bar, TRUE);\n    gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));\n  } else {\n    gtk_window_set_title(window, \"example_nav2\");\n  }\n\n  gtk_window_set_default_size(window, 1280, 720);\n  gtk_widget_show(GTK_WIDGET(window));\n\n  g_autoptr(FlDartProject) project = fl_dart_project_new();\n  fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments);\n\n  FlView* view = fl_view_new(project);\n  gtk_widget_show(GTK_WIDGET(view));\n  gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view));\n\n  fl_register_plugins(FL_PLUGIN_REGISTRY(view));\n\n  gtk_widget_grab_focus(GTK_WIDGET(view));\n}\n\n// Implements GApplication::local_command_line.\nstatic gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) {\n  MyApplication* self = MY_APPLICATION(application);\n  // Strip out the first argument as it is the binary name.\n  self->dart_entrypoint_arguments = g_strdupv(*arguments + 1);\n\n  g_autoptr(GError) error = nullptr;\n  if (!g_application_register(application, nullptr, &error)) {\n     g_warning(\"Failed to register: %s\", error->message);\n     *exit_status = 1;\n     return TRUE;\n  }\n\n  g_application_activate(application);\n  *exit_status = 0;\n\n  return TRUE;\n}\n\n// Implements GApplication::startup.\nstatic void my_application_startup(GApplication* application) {\n  //MyApplication* self = MY_APPLICATION(object);\n\n  // Perform any actions required at application startup.\n\n  G_APPLICATION_CLASS(my_application_parent_class)->startup(application);\n}\n\n// Implements GApplication::shutdown.\nstatic void my_application_shutdown(GApplication* application) {\n  //MyApplication* self = MY_APPLICATION(object);\n\n  // Perform any actions required at application shutdown.\n\n  G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application);\n}\n\n// Implements GObject::dispose.\nstatic void my_application_dispose(GObject* object) {\n  MyApplication* self = MY_APPLICATION(object);\n  g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev);\n  G_OBJECT_CLASS(my_application_parent_class)->dispose(object);\n}\n\nstatic void my_application_class_init(MyApplicationClass* klass) {\n  G_APPLICATION_CLASS(klass)->activate = my_application_activate;\n  G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line;\n  G_APPLICATION_CLASS(klass)->startup = my_application_startup;\n  G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown;\n  G_OBJECT_CLASS(klass)->dispose = my_application_dispose;\n}\n\nstatic void my_application_init(MyApplication* self) {}\n\nMyApplication* my_application_new() {\n  // Set the program name to the application ID, which helps various systems\n  // like GTK and desktop environments map this running application to its\n  // corresponding .desktop file. This ensures better integration by allowing\n  // the application to be recognized beyond its binary name.\n  g_set_prgname(APPLICATION_ID);\n\n  return MY_APPLICATION(g_object_new(my_application_get_type(),\n                                     \"application-id\", APPLICATION_ID,\n                                     \"flags\", G_APPLICATION_NON_UNIQUE,\n                                     nullptr));\n}\n"
  },
  {
    "path": "example_nav2/linux/runner/my_application.h",
    "content": "#ifndef FLUTTER_MY_APPLICATION_H_\n#define FLUTTER_MY_APPLICATION_H_\n\n#include <gtk/gtk.h>\n\nG_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION,\n                     GtkApplication)\n\n/**\n * my_application_new:\n *\n * Creates a new Flutter-based application.\n *\n * Returns: a new #MyApplication.\n */\nMyApplication* my_application_new();\n\n#endif  // FLUTTER_MY_APPLICATION_H_\n"
  },
  {
    "path": "example_nav2/macos/.gitignore",
    "content": "# Flutter-related\n**/Flutter/ephemeral/\n**/Pods/\n\n# Xcode-related\n**/dgph\n**/xcuserdata/\n"
  },
  {
    "path": "example_nav2/macos/Flutter/Flutter-Debug.xcconfig",
    "content": "#include \"ephemeral/Flutter-Generated.xcconfig\"\n"
  },
  {
    "path": "example_nav2/macos/Flutter/Flutter-Release.xcconfig",
    "content": "#include \"ephemeral/Flutter-Generated.xcconfig\"\n"
  },
  {
    "path": "example_nav2/macos/Flutter/GeneratedPluginRegistrant.swift",
    "content": "//\n//  Generated file. Do not edit.\n//\n\nimport FlutterMacOS\nimport Foundation\n\n\nfunc RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {\n}\n"
  },
  {
    "path": "example_nav2/macos/Runner/AppDelegate.swift",
    "content": "import Cocoa\nimport FlutterMacOS\n\n@main\nclass AppDelegate: FlutterAppDelegate {\n  override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {\n    return true\n  }\n}\n"
  },
  {
    "path": "example_nav2/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"size\" : \"16x16\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"app_icon_16.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"16x16\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"app_icon_32.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"32x32\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"app_icon_32.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"32x32\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"app_icon_64.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"128x128\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"app_icon_128.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"128x128\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"app_icon_256.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"256x256\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"app_icon_256.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"256x256\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"app_icon_512.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"512x512\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"app_icon_512.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"512x512\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"app_icon_1024.png\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}\n"
  },
  {
    "path": "example_nav2/macos/Runner/Base.lproj/MainMenu.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"14490.70\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"14490.70\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"NSApplication\">\n            <connections>\n                <outlet property=\"delegate\" destination=\"Voe-Tx-rLC\" id=\"GzC-gU-4Uq\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <customObject id=\"Voe-Tx-rLC\" customClass=\"AppDelegate\" customModule=\"Runner\" customModuleProvider=\"target\">\n            <connections>\n                <outlet property=\"applicationMenu\" destination=\"uQy-DD-JDr\" id=\"XBo-yE-nKs\"/>\n                <outlet property=\"mainFlutterWindow\" destination=\"QvC-M9-y7g\" id=\"gIp-Ho-8D9\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"YLy-65-1bz\" customClass=\"NSFontManager\"/>\n        <menu title=\"Main Menu\" systemMenu=\"main\" id=\"AYu-sK-qS6\">\n            <items>\n                <menuItem title=\"APP_NAME\" id=\"1Xt-HY-uBw\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"APP_NAME\" systemMenu=\"apple\" id=\"uQy-DD-JDr\">\n                        <items>\n                            <menuItem title=\"About APP_NAME\" id=\"5kV-Vb-QxS\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"orderFrontStandardAboutPanel:\" target=\"-1\" id=\"Exp-CZ-Vem\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"VOq-y0-SEH\"/>\n                            <menuItem title=\"Preferences…\" keyEquivalent=\",\" id=\"BOF-NM-1cW\"/>\n                            <menuItem isSeparatorItem=\"YES\" id=\"wFC-TO-SCJ\"/>\n                            <menuItem title=\"Services\" id=\"NMo-om-nkz\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Services\" systemMenu=\"services\" id=\"hz9-B4-Xy5\"/>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"4je-JR-u6R\"/>\n                            <menuItem title=\"Hide APP_NAME\" keyEquivalent=\"h\" id=\"Olw-nP-bQN\">\n                                <connections>\n                                    <action selector=\"hide:\" target=\"-1\" id=\"PnN-Uc-m68\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Hide Others\" keyEquivalent=\"h\" id=\"Vdr-fp-XzO\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"hideOtherApplications:\" target=\"-1\" id=\"VT4-aY-XCT\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Show All\" id=\"Kd2-mp-pUS\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"unhideAllApplications:\" target=\"-1\" id=\"Dhg-Le-xox\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"kCx-OE-vgT\"/>\n                            <menuItem title=\"Quit APP_NAME\" keyEquivalent=\"q\" id=\"4sb-4s-VLi\">\n                                <connections>\n                                    <action selector=\"terminate:\" target=\"-1\" id=\"Te7-pn-YzF\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n                <menuItem title=\"Edit\" id=\"5QF-Oa-p0T\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"Edit\" id=\"W48-6f-4Dl\">\n                        <items>\n                            <menuItem title=\"Undo\" keyEquivalent=\"z\" id=\"dRJ-4n-Yzg\">\n                                <connections>\n                                    <action selector=\"undo:\" target=\"-1\" id=\"M6e-cu-g7V\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Redo\" keyEquivalent=\"Z\" id=\"6dh-zS-Vam\">\n                                <connections>\n                                    <action selector=\"redo:\" target=\"-1\" id=\"oIA-Rs-6OD\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"WRV-NI-Exz\"/>\n                            <menuItem title=\"Cut\" keyEquivalent=\"x\" id=\"uRl-iY-unG\">\n                                <connections>\n                                    <action selector=\"cut:\" target=\"-1\" id=\"YJe-68-I9s\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Copy\" keyEquivalent=\"c\" id=\"x3v-GG-iWU\">\n                                <connections>\n                                    <action selector=\"copy:\" target=\"-1\" id=\"G1f-GL-Joy\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Paste\" keyEquivalent=\"v\" id=\"gVA-U4-sdL\">\n                                <connections>\n                                    <action selector=\"paste:\" target=\"-1\" id=\"UvS-8e-Qdg\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Paste and Match Style\" keyEquivalent=\"V\" id=\"WeT-3V-zwk\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"pasteAsPlainText:\" target=\"-1\" id=\"cEh-KX-wJQ\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Delete\" id=\"pa3-QI-u2k\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"delete:\" target=\"-1\" id=\"0Mk-Ml-PaM\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Select All\" keyEquivalent=\"a\" id=\"Ruw-6m-B2m\">\n                                <connections>\n                                    <action selector=\"selectAll:\" target=\"-1\" id=\"VNm-Mi-diN\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"uyl-h8-XO2\"/>\n                            <menuItem title=\"Find\" id=\"4EN-yA-p0u\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Find\" id=\"1b7-l0-nxx\">\n                                    <items>\n                                        <menuItem title=\"Find…\" tag=\"1\" keyEquivalent=\"f\" id=\"Xz5-n4-O0W\">\n                                            <connections>\n                                                <action selector=\"performFindPanelAction:\" target=\"-1\" id=\"cD7-Qs-BN4\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Find and Replace…\" tag=\"12\" keyEquivalent=\"f\" id=\"YEy-JH-Tfz\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"performFindPanelAction:\" target=\"-1\" id=\"WD3-Gg-5AJ\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Find Next\" tag=\"2\" keyEquivalent=\"g\" id=\"q09-fT-Sye\">\n                                            <connections>\n                                                <action selector=\"performFindPanelAction:\" target=\"-1\" id=\"NDo-RZ-v9R\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Find Previous\" tag=\"3\" keyEquivalent=\"G\" id=\"OwM-mh-QMV\">\n                                            <connections>\n                                                <action selector=\"performFindPanelAction:\" target=\"-1\" id=\"HOh-sY-3ay\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Use Selection for Find\" tag=\"7\" keyEquivalent=\"e\" id=\"buJ-ug-pKt\">\n                                            <connections>\n                                                <action selector=\"performFindPanelAction:\" target=\"-1\" id=\"U76-nv-p5D\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Jump to Selection\" keyEquivalent=\"j\" id=\"S0p-oC-mLd\">\n                                            <connections>\n                                                <action selector=\"centerSelectionInVisibleArea:\" target=\"-1\" id=\"IOG-6D-g5B\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Spelling and Grammar\" id=\"Dv1-io-Yv7\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Spelling\" id=\"3IN-sU-3Bg\">\n                                    <items>\n                                        <menuItem title=\"Show Spelling and Grammar\" keyEquivalent=\":\" id=\"HFo-cy-zxI\">\n                                            <connections>\n                                                <action selector=\"showGuessPanel:\" target=\"-1\" id=\"vFj-Ks-hy3\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Check Document Now\" keyEquivalent=\";\" id=\"hz2-CU-CR7\">\n                                            <connections>\n                                                <action selector=\"checkSpelling:\" target=\"-1\" id=\"fz7-VC-reM\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"bNw-od-mp5\"/>\n                                        <menuItem title=\"Check Spelling While Typing\" id=\"rbD-Rh-wIN\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleContinuousSpellChecking:\" target=\"-1\" id=\"7w6-Qz-0kB\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Check Grammar With Spelling\" id=\"mK6-2p-4JG\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleGrammarChecking:\" target=\"-1\" id=\"muD-Qn-j4w\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Correct Spelling Automatically\" id=\"78Y-hA-62v\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleAutomaticSpellingCorrection:\" target=\"-1\" id=\"2lM-Qi-WAP\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Substitutions\" id=\"9ic-FL-obx\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Substitutions\" id=\"FeM-D8-WVr\">\n                                    <items>\n                                        <menuItem title=\"Show Substitutions\" id=\"z6F-FW-3nz\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"orderFrontSubstitutionsPanel:\" target=\"-1\" id=\"oku-mr-iSq\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"gPx-C9-uUO\"/>\n                                        <menuItem title=\"Smart Copy/Paste\" id=\"9yt-4B-nSM\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleSmartInsertDelete:\" target=\"-1\" id=\"3IJ-Se-DZD\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Smart Quotes\" id=\"hQb-2v-fYv\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleAutomaticQuoteSubstitution:\" target=\"-1\" id=\"ptq-xd-QOA\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Smart Dashes\" id=\"rgM-f4-ycn\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleAutomaticDashSubstitution:\" target=\"-1\" id=\"oCt-pO-9gS\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Smart Links\" id=\"cwL-P1-jid\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleAutomaticLinkDetection:\" target=\"-1\" id=\"Gip-E3-Fov\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Data Detectors\" id=\"tRr-pd-1PS\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleAutomaticDataDetection:\" target=\"-1\" id=\"R1I-Nq-Kbl\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Text Replacement\" id=\"HFQ-gK-NFA\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleAutomaticTextReplacement:\" target=\"-1\" id=\"DvP-Fe-Py6\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Transformations\" id=\"2oI-Rn-ZJC\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Transformations\" id=\"c8a-y6-VQd\">\n                                    <items>\n                                        <menuItem title=\"Make Upper Case\" id=\"vmV-6d-7jI\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"uppercaseWord:\" target=\"-1\" id=\"sPh-Tk-edu\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Make Lower Case\" id=\"d9M-CD-aMd\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"lowercaseWord:\" target=\"-1\" id=\"iUZ-b5-hil\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Capitalize\" id=\"UEZ-Bs-lqG\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"capitalizeWord:\" target=\"-1\" id=\"26H-TL-nsh\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Speech\" id=\"xrE-MZ-jX0\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Speech\" id=\"3rS-ZA-NoH\">\n                                    <items>\n                                        <menuItem title=\"Start Speaking\" id=\"Ynk-f8-cLZ\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"startSpeaking:\" target=\"-1\" id=\"654-Ng-kyl\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Stop Speaking\" id=\"Oyz-dy-DGm\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"stopSpeaking:\" target=\"-1\" id=\"dX8-6p-jy9\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n                <menuItem title=\"View\" id=\"H8h-7b-M4v\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"View\" id=\"HyV-fh-RgO\">\n                        <items>\n                            <menuItem title=\"Enter Full Screen\" keyEquivalent=\"f\" id=\"4J7-dP-txa\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"toggleFullScreen:\" target=\"-1\" id=\"dU3-MA-1Rq\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n                <menuItem title=\"Window\" id=\"aUF-d1-5bR\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"Window\" systemMenu=\"window\" id=\"Td7-aD-5lo\">\n                        <items>\n                            <menuItem title=\"Minimize\" keyEquivalent=\"m\" id=\"OY7-WF-poV\">\n                                <connections>\n                                    <action selector=\"performMiniaturize:\" target=\"-1\" id=\"VwT-WD-YPe\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Zoom\" id=\"R4o-n2-Eq4\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"performZoom:\" target=\"-1\" id=\"DIl-cC-cCs\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"eu3-7i-yIM\"/>\n                            <menuItem title=\"Bring All to Front\" id=\"LE2-aR-0XJ\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"arrangeInFront:\" target=\"-1\" id=\"DRN-fu-gQh\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n                <menuItem title=\"Help\" id=\"EPT-qC-fAb\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"Help\" systemMenu=\"help\" id=\"rJ0-wn-3NY\"/>\n                </menuItem>\n            </items>\n            <point key=\"canvasLocation\" x=\"142\" y=\"-258\"/>\n        </menu>\n        <window title=\"APP_NAME\" allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" releasedWhenClosed=\"NO\" animationBehavior=\"default\" id=\"QvC-M9-y7g\" customClass=\"MainFlutterWindow\" customModule=\"Runner\" customModuleProvider=\"target\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\" miniaturizable=\"YES\" resizable=\"YES\"/>\n            <rect key=\"contentRect\" x=\"335\" y=\"390\" width=\"800\" height=\"600\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"2560\" height=\"1577\"/>\n            <view key=\"contentView\" wantsLayer=\"YES\" id=\"EiT-Mj-1SZ\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"800\" height=\"600\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n            </view>\n        </window>\n    </objects>\n</document>\n"
  },
  {
    "path": "example_nav2/macos/Runner/Configs/AppInfo.xcconfig",
    "content": "// Application-level settings for the Runner target.\n//\n// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the\n// future. If not, the values below would default to using the project name when this becomes a\n// 'flutter create' template.\n\n// The application's name. By default this is also the title of the Flutter window.\nPRODUCT_NAME = example_nav2\n\n// The application's bundle identifier\nPRODUCT_BUNDLE_IDENTIFIER = com.get.exampleNav2\n\n// The copyright displayed in application information\nPRODUCT_COPYRIGHT = Copyright © 2023 com.get. All rights reserved.\n"
  },
  {
    "path": "example_nav2/macos/Runner/Configs/Debug.xcconfig",
    "content": "#include \"../../Flutter/Flutter-Debug.xcconfig\"\n#include \"Warnings.xcconfig\"\n"
  },
  {
    "path": "example_nav2/macos/Runner/Configs/Release.xcconfig",
    "content": "#include \"../../Flutter/Flutter-Release.xcconfig\"\n#include \"Warnings.xcconfig\"\n"
  },
  {
    "path": "example_nav2/macos/Runner/Configs/Warnings.xcconfig",
    "content": "WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings\nGCC_WARN_UNDECLARED_SELECTOR = YES\nCLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES\nCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE\nCLANG_WARN__DUPLICATE_METHOD_MATCH = YES\nCLANG_WARN_PRAGMA_PACK = YES\nCLANG_WARN_STRICT_PROTOTYPES = YES\nCLANG_WARN_COMMA = YES\nGCC_WARN_STRICT_SELECTOR_MATCH = YES\nCLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES\nCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES\nGCC_WARN_SHADOW = YES\nCLANG_WARN_UNREACHABLE_CODE = YES\n"
  },
  {
    "path": "example_nav2/macos/Runner/DebugProfile.entitlements",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>com.apple.security.app-sandbox</key>\n\t<true/>\n\t<key>com.apple.security.cs.allow-jit</key>\n\t<true/>\n\t<key>com.apple.security.network.server</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "example_nav2/macos/Runner/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIconFile</key>\n\t<string></string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>$(FLUTTER_BUILD_NAME)</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(FLUTTER_BUILD_NUMBER)</string>\n\t<key>LSMinimumSystemVersion</key>\n\t<string>$(MACOSX_DEPLOYMENT_TARGET)</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>$(PRODUCT_COPYRIGHT)</string>\n\t<key>NSMainNibFile</key>\n\t<string>MainMenu</string>\n\t<key>NSPrincipalClass</key>\n\t<string>NSApplication</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "example_nav2/macos/Runner/MainFlutterWindow.swift",
    "content": "import Cocoa\nimport FlutterMacOS\n\nclass MainFlutterWindow: NSWindow {\n  override func awakeFromNib() {\n    let flutterViewController = FlutterViewController.init()\n    let windowFrame = self.frame\n    self.contentViewController = flutterViewController\n    self.setFrame(windowFrame, display: true)\n\n    RegisterGeneratedPlugins(registry: flutterViewController)\n\n    super.awakeFromNib()\n  }\n}\n"
  },
  {
    "path": "example_nav2/macos/Runner/Release.entitlements",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>com.apple.security.app-sandbox</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "example_nav2/macos/Runner.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 54;\n\tobjects = {\n\n/* Begin PBXAggregateTarget section */\n\t\t33CC111A2044C6BA0003C045 /* Flutter Assemble */ = {\n\t\t\tisa = PBXAggregateTarget;\n\t\t\tbuildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget \"Flutter Assemble\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t33CC111E2044C6BF0003C045 /* ShellScript */,\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"Flutter Assemble\";\n\t\t\tproductName = FLX;\n\t\t};\n/* End PBXAggregateTarget section */\n\n/* Begin PBXBuildFile section */\n\t\t335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; };\n\t\t33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; };\n\t\t33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; };\n\t\t33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };\n\t\t33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\n\t\t33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 33CC10E52044A3C60003C045 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 33CC111A2044C6BA0003C045;\n\t\t\tremoteInfo = FLX;\n\t\t};\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXCopyFilesBuildPhase section */\n\t\t33CC110E2044A8840003C045 /* Bundle Framework */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = \"\";\n\t\t\tdstSubfolderSpec = 10;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tname = \"Bundle Framework\";\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXCopyFilesBuildPhase section */\n\n/* Begin PBXFileReference section */\n\t\t333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = \"<group>\"; };\n\t\t335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = \"<group>\"; };\n\t\t33CC10ED2044A3C60003C045 /* example_nav2.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = \"example_nav2.app\"; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\t33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = \"<group>\"; };\n\t\t33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = \"<group>\"; };\n\t\t33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = \"<group>\"; };\n\t\t33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = \"<group>\"; };\n\t\t33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"Flutter-Debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"Flutter-Release.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = \"Flutter-Generated.xcconfig\"; path = \"ephemeral/Flutter-Generated.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = \"<group>\"; };\n\t\t33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = \"<group>\"; };\n\t\t33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = \"<group>\"; };\n\t\t7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = \"<group>\"; };\n\t\t9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t33CC10EA2044A3C60003C045 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t33BA886A226E78AF003329D5 /* Configs */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t33E5194F232828860026EE4D /* AppInfo.xcconfig */,\n\t\t\t\t9740EEB21CF90195004384FC /* Debug.xcconfig */,\n\t\t\t\t7AFA3C8E1D35360C0083082E /* Release.xcconfig */,\n\t\t\t\t333000ED22D3DE5D00554162 /* Warnings.xcconfig */,\n\t\t\t);\n\t\t\tpath = Configs;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t33CC10E42044A3C60003C045 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t33FAB671232836740065AC1E /* Runner */,\n\t\t\t\t33CEB47122A05771004F2AC0 /* Flutter */,\n\t\t\t\t33CC10EE2044A3C60003C045 /* Products */,\n\t\t\t\tD73912EC22F37F3D000D13A0 /* Frameworks */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t33CC10EE2044A3C60003C045 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t33CC10ED2044A3C60003C045 /* example_nav2.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t33CC11242044D66E0003C045 /* Resources */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t33CC10F22044A3C60003C045 /* Assets.xcassets */,\n\t\t\t\t33CC10F42044A3C60003C045 /* MainMenu.xib */,\n\t\t\t\t33CC10F72044A3C60003C045 /* Info.plist */,\n\t\t\t);\n\t\t\tname = Resources;\n\t\t\tpath = ..;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t33CEB47122A05771004F2AC0 /* Flutter */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */,\n\t\t\t\t33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */,\n\t\t\t\t33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */,\n\t\t\t\t33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */,\n\t\t\t);\n\t\t\tpath = Flutter;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t33FAB671232836740065AC1E /* Runner */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t33CC10F02044A3C60003C045 /* AppDelegate.swift */,\n\t\t\t\t33CC11122044BFA00003C045 /* MainFlutterWindow.swift */,\n\t\t\t\t33E51913231747F40026EE4D /* DebugProfile.entitlements */,\n\t\t\t\t33E51914231749380026EE4D /* Release.entitlements */,\n\t\t\t\t33CC11242044D66E0003C045 /* Resources */,\n\t\t\t\t33BA886A226E78AF003329D5 /* Configs */,\n\t\t\t);\n\t\t\tpath = Runner;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tD73912EC22F37F3D000D13A0 /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t33CC10EC2044A3C60003C045 /* Runner */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget \"Runner\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t33CC10E92044A3C60003C045 /* Sources */,\n\t\t\t\t33CC10EA2044A3C60003C045 /* Frameworks */,\n\t\t\t\t33CC10EB2044A3C60003C045 /* Resources */,\n\t\t\t\t33CC110E2044A8840003C045 /* Bundle Framework */,\n\t\t\t\t3399D490228B24CF009A79C7 /* ShellScript */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t33CC11202044C79F0003C045 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = Runner;\n\t\t\tproductName = Runner;\n\t\t\tproductReference = 33CC10ED2044A3C60003C045 /* example_nav2.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t33CC10E52044A3C60003C045 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftUpdateCheck = 0920;\n\t\t\t\tLastUpgradeCheck = 1510;\n\t\t\t\tORGANIZATIONNAME = \"\";\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t33CC10EC2044A3C60003C045 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 9.2;\n\t\t\t\t\t\tLastSwiftMigration = 1100;\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t\tSystemCapabilities = {\n\t\t\t\t\t\t\tcom.apple.Sandbox = {\n\t\t\t\t\t\t\t\tenabled = 1;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t};\n\t\t\t\t\t};\n\t\t\t\t\t33CC111A2044C6BA0003C045 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 9.2;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject \"Runner\" */;\n\t\t\tcompatibilityVersion = \"Xcode 9.3\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 33CC10E42044A3C60003C045;\n\t\t\tproductRefGroup = 33CC10EE2044A3C60003C045 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t33CC10EC2044A3C60003C045 /* Runner */,\n\t\t\t\t33CC111A2044C6BA0003C045 /* Flutter Assemble */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t33CC10EB2044A3C60003C045 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */,\n\t\t\t\t33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXShellScriptBuildPhase section */\n\t\t3399D490228B24CF009A79C7 /* ShellScript */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\talwaysOutOfDate = 1;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\toutputFileListPaths = (\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"echo \\\"$PRODUCT_NAME.app\\\" > \\\"$PROJECT_DIR\\\"/Flutter/ephemeral/.app_filename && \\\"$FLUTTER_ROOT\\\"/packages/flutter_tools/bin/macos_assemble.sh embed\\n\";\n\t\t};\n\t\t33CC111E2044C6BF0003C045 /* ShellScript */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t\tFlutter/ephemeral/FlutterInputs.xcfilelist,\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\tFlutter/ephemeral/tripwire,\n\t\t\t);\n\t\t\toutputFileListPaths = (\n\t\t\t\tFlutter/ephemeral/FlutterOutputs.xcfilelist,\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"$FLUTTER_ROOT\\\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire\";\n\t\t};\n/* End PBXShellScriptBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t33CC10E92044A3C60003C045 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */,\n\t\t\t\t33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */,\n\t\t\t\t335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXTargetDependency section */\n\t\t33CC11202044C79F0003C045 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 33CC111A2044C6BA0003C045 /* Flutter Assemble */;\n\t\t\ttargetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */;\n\t\t};\n/* End PBXTargetDependency section */\n\n/* Begin PBXVariantGroup section */\n\t\t33CC10F42044A3C60003C045 /* MainMenu.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t33CC10F52044A3C60003C045 /* Base */,\n\t\t\t);\n\t\t\tname = MainMenu.xib;\n\t\t\tpath = Runner;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\t338D0CE9231458BD00FA5F75 /* Profile */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"-\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.14;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-O\";\n\t\t\t};\n\t\t\tname = Profile;\n\t\t};\n\t\t338D0CEA231458BD00FA5F75 /* Profile */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tINFOPLIST_FILE = Runner/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/../Frameworks\",\n\t\t\t\t);\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Profile;\n\t\t};\n\t\t338D0CEB231458BD00FA5F75 /* Profile */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = Profile;\n\t\t};\n\t\t33CC10F92044A3C60003C045 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"-\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.14;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t33CC10FA2044A3C60003C045 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"-\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.14;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-O\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t33CC10FC2044A3C60003C045 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tINFOPLIST_FILE = Runner/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/../Frameworks\",\n\t\t\t\t);\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t33CC10FD2044A3C60003C045 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tINFOPLIST_FILE = Runner/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/../Frameworks\",\n\t\t\t\t);\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t33CC111C2044C6BA0003C045 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t33CC111D2044C6BA0003C045 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t33CC10E82044A3C60003C045 /* Build configuration list for PBXProject \"Runner\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t33CC10F92044A3C60003C045 /* Debug */,\n\t\t\t\t33CC10FA2044A3C60003C045 /* Release */,\n\t\t\t\t338D0CE9231458BD00FA5F75 /* Profile */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget \"Runner\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t33CC10FC2044A3C60003C045 /* Debug */,\n\t\t\t\t33CC10FD2044A3C60003C045 /* Release */,\n\t\t\t\t338D0CEA231458BD00FA5F75 /* Profile */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget \"Flutter Assemble\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t33CC111C2044C6BA0003C045 /* Debug */,\n\t\t\t\t33CC111D2044C6BA0003C045 /* Release */,\n\t\t\t\t338D0CEB231458BD00FA5F75 /* Profile */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 33CC10E52044A3C60003C045 /* Project object */;\n}\n"
  },
  {
    "path": "example_nav2/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>IDEDidComputeMac32BitWarning</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "example_nav2/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1510\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"33CC10EC2044A3C60003C045\"\n               BuildableName = \"example_nav2.app\"\n               BlueprintName = \"Runner\"\n               ReferencedContainer = \"container:Runner.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"33CC10EC2044A3C60003C045\"\n            BuildableName = \"example_nav2.app\"\n            BlueprintName = \"Runner\"\n            ReferencedContainer = \"container:Runner.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <Testables>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"33CC10EC2044A3C60003C045\"\n            BuildableName = \"example_nav2.app\"\n            BlueprintName = \"Runner\"\n            ReferencedContainer = \"container:Runner.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Profile\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"33CC10EC2044A3C60003C045\"\n            BuildableName = \"example_nav2.app\"\n            BlueprintName = \"Runner\"\n            ReferencedContainer = \"container:Runner.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "example_nav2/macos/Runner.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"group:Runner.xcodeproj\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "example_nav2/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>IDEDidComputeMac32BitWarning</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "example_nav2/macos/RunnerTests/RunnerTests.swift",
    "content": "import Cocoa\nimport FlutterMacOS\nimport XCTest\n\nclass RunnerTests: XCTestCase {\n\n  func testExample() {\n    // If you add code to the Runner application, consider adding tests here.\n    // See https://developer.apple.com/documentation/xctest for more information about using XCTest.\n  }\n\n}\n"
  },
  {
    "path": "example_nav2/pubspec.yaml",
    "content": "name: example_nav2\nversion: 1.0.0+1\npublish_to: none\ndescription: A new Flutter project.\nenvironment:\n  sdk: \">=3.0.0 <4.0.0\"\n\ndependencies:\n  cupertino_icons: ^1.0.2\n  # get: ^4.1.4\n  get:\n    path: ../\n  flutter:\n    sdk: flutter\n  flutter_lints: ^5.0.0\n\ndev_dependencies:\n  flutter_test:\n    sdk: flutter\n\nflutter:\n  uses-material-design: true\n"
  },
  {
    "path": "example_nav2/test/widget_test.dart",
    "content": "// This is a basic Flutter widget test.\n//\n// To perform an interaction with a widget in your test, use the WidgetTester\n// utility in the flutter_test package. For example, you can send tap and scroll\n// gestures. You can also use WidgetTester to find child widgets in the widget\n// tree, read text, and verify that the values of widget properties are correct.\n\nimport 'package:flutter/material.dart';\nimport 'package:flutter_test/flutter_test.dart';\n\nvoid main() {\n  testWidgets('Counter increments smoke test', (WidgetTester tester) async {\n    // Build our app and trigger a frame.\n    // await tester.pumpWidget(const MyApp());\n\n    // Verify that our counter starts at 0.\n    expect(find.text('0'), findsOneWidget);\n    expect(find.text('1'), findsNothing);\n\n    // Tap the '+' icon and trigger a frame.\n    await tester.tap(find.byIcon(Icons.add));\n    await tester.pump();\n\n    // Verify that our counter has incremented.\n    expect(find.text('0'), findsNothing);\n    expect(find.text('1'), findsOneWidget);\n  });\n}\n"
  },
  {
    "path": "example_nav2/web/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n  <!--\n    If you are serving your web app in a path other than the root, change the\n    href value below to reflect the base path you are serving from.\n\n    The path provided below has to start and end with a slash \"/\" in order for\n    it to work correctly.\n\n    For more details:\n    * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base\n\n    This is a placeholder for base href that will be replaced by the value of\n    the `--base-href` argument provided to `flutter build`.\n  -->\n  <base href=\"$FLUTTER_BASE_HREF\">\n\n  <meta charset=\"UTF-8\">\n  <meta content=\"IE=Edge\" http-equiv=\"X-UA-Compatible\">\n  <meta name=\"description\" content=\"A new Flutter project.\">\n\n  <!-- iOS meta tags & icons -->\n  <meta name=\"apple-mobile-web-app-capable\" content=\"yes\">\n  <meta name=\"apple-mobile-web-app-status-bar-style\" content=\"black\">\n  <meta name=\"apple-mobile-web-app-title\" content=\"example_nav2\">\n  <link rel=\"apple-touch-icon\" href=\"icons/Icon-192.png\">\n\n  <!-- Favicon -->\n  <link rel=\"icon\" type=\"image/png\" href=\"favicon.png\"/>\n\n  <title>example_nav2</title>\n  <link rel=\"manifest\" href=\"manifest.json\">\n</head>\n<body>\n  <script src=\"flutter_bootstrap.js\" async></script>\n</body>\n</html>\n"
  },
  {
    "path": "example_nav2/web/manifest.json",
    "content": "{\n    \"name\": \"example_nav2\",\n    \"short_name\": \"example_nav2\",\n    \"start_url\": \".\",\n    \"display\": \"standalone\",\n    \"background_color\": \"#0175C2\",\n    \"theme_color\": \"#0175C2\",\n    \"description\": \"A new Flutter project.\",\n    \"orientation\": \"portrait-primary\",\n    \"prefer_related_applications\": false,\n    \"icons\": [\n        {\n            \"src\": \"icons/Icon-192.png\",\n            \"sizes\": \"192x192\",\n            \"type\": \"image/png\"\n        },\n        {\n            \"src\": \"icons/Icon-512.png\",\n            \"sizes\": \"512x512\",\n            \"type\": \"image/png\"\n        },\n        {\n            \"src\": \"icons/Icon-maskable-192.png\",\n            \"sizes\": \"192x192\",\n            \"type\": \"image/png\",\n            \"purpose\": \"maskable\"\n        },\n        {\n            \"src\": \"icons/Icon-maskable-512.png\",\n            \"sizes\": \"512x512\",\n            \"type\": \"image/png\",\n            \"purpose\": \"maskable\"\n        }\n    ]\n}\n"
  },
  {
    "path": "example_nav2/windows/.gitignore",
    "content": "flutter/ephemeral/\n\n# Visual Studio user-specific files.\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# Visual Studio build-related files.\nx64/\nx86/\n\n# Visual Studio cache files\n# files ending in .cache can be ignored\n*.[Cc]ache\n# but keep track of directories ending in .cache\n!*.[Cc]ache/\n"
  },
  {
    "path": "example_nav2/windows/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.15)\nproject(example_nav2 LANGUAGES CXX)\n\nset(BINARY_NAME \"example_nav2\")\n\ncmake_policy(SET CMP0063 NEW)\n\nset(CMAKE_INSTALL_RPATH \"$ORIGIN/lib\")\n\n# Configure build options.\nget_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)\nif(IS_MULTICONFIG)\n  set(CMAKE_CONFIGURATION_TYPES \"Debug;Profile;Release\"\n    CACHE STRING \"\" FORCE)\nelse()\n  if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)\n    set(CMAKE_BUILD_TYPE \"Debug\" CACHE\n      STRING \"Flutter build mode\" FORCE)\n    set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS\n      \"Debug\" \"Profile\" \"Release\")\n  endif()\nendif()\n\nset(CMAKE_EXE_LINKER_FLAGS_PROFILE \"${CMAKE_EXE_LINKER_FLAGS_RELEASE}\")\nset(CMAKE_SHARED_LINKER_FLAGS_PROFILE \"${CMAKE_SHARED_LINKER_FLAGS_RELEASE}\")\nset(CMAKE_C_FLAGS_PROFILE \"${CMAKE_C_FLAGS_RELEASE}\")\nset(CMAKE_CXX_FLAGS_PROFILE \"${CMAKE_CXX_FLAGS_RELEASE}\")\n\n# Use Unicode for all projects.\nadd_definitions(-DUNICODE -D_UNICODE)\n\n# Compilation settings that should be applied to most targets.\nfunction(APPLY_STANDARD_SETTINGS TARGET)\n  target_compile_features(${TARGET} PUBLIC cxx_std_17)\n  target_compile_options(${TARGET} PRIVATE /W4 /WX /wd\"4100\")\n  target_compile_options(${TARGET} PRIVATE /EHsc)\n  target_compile_definitions(${TARGET} PRIVATE \"_HAS_EXCEPTIONS=0\")\n  target_compile_definitions(${TARGET} PRIVATE \"$<$<CONFIG:Debug>:_DEBUG>\")\nendfunction()\n\nset(FLUTTER_MANAGED_DIR \"${CMAKE_CURRENT_SOURCE_DIR}/flutter\")\n\n# Flutter library and tool build rules.\nadd_subdirectory(${FLUTTER_MANAGED_DIR})\n\n# Application build\nadd_subdirectory(\"runner\")\n\n# Generated plugin build rules, which manage building the plugins and adding\n# them to the application.\ninclude(flutter/generated_plugins.cmake)\n\n\n# === Installation ===\n# Support files are copied into place next to the executable, so that it can\n# run in place. This is done instead of making a separate bundle (as on Linux)\n# so that building and running from within Visual Studio will work.\nset(BUILD_BUNDLE_DIR \"$<TARGET_FILE_DIR:${BINARY_NAME}>\")\n# Make the \"install\" step default, as it's required to run.\nset(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1)\nif(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)\n  set(CMAKE_INSTALL_PREFIX \"${BUILD_BUNDLE_DIR}\" CACHE PATH \"...\" FORCE)\nendif()\n\nset(INSTALL_BUNDLE_DATA_DIR \"${CMAKE_INSTALL_PREFIX}/data\")\nset(INSTALL_BUNDLE_LIB_DIR \"${CMAKE_INSTALL_PREFIX}\")\n\ninstall(TARGETS ${BINARY_NAME} RUNTIME DESTINATION \"${CMAKE_INSTALL_PREFIX}\"\n  COMPONENT Runtime)\n\ninstall(FILES \"${FLUTTER_ICU_DATA_FILE}\" DESTINATION \"${INSTALL_BUNDLE_DATA_DIR}\"\n  COMPONENT Runtime)\n\ninstall(FILES \"${FLUTTER_LIBRARY}\" DESTINATION \"${INSTALL_BUNDLE_LIB_DIR}\"\n  COMPONENT Runtime)\n\nif(PLUGIN_BUNDLED_LIBRARIES)\n  install(FILES \"${PLUGIN_BUNDLED_LIBRARIES}\"\n    DESTINATION \"${INSTALL_BUNDLE_LIB_DIR}\"\n    COMPONENT Runtime)\nendif()\n\n# Fully re-copy the assets directory on each build to avoid having stale files\n# from a previous install.\nset(FLUTTER_ASSET_DIR_NAME \"flutter_assets\")\ninstall(CODE \"\n  file(REMOVE_RECURSE \\\"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\\\")\n  \" COMPONENT Runtime)\ninstall(DIRECTORY \"${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}\"\n  DESTINATION \"${INSTALL_BUNDLE_DATA_DIR}\" COMPONENT Runtime)\n\n# Install the AOT library on non-Debug builds only.\ninstall(FILES \"${AOT_LIBRARY}\" DESTINATION \"${INSTALL_BUNDLE_DATA_DIR}\"\n  CONFIGURATIONS Profile;Release\n  COMPONENT Runtime)\n"
  },
  {
    "path": "example_nav2/windows/flutter/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.15)\n\nset(EPHEMERAL_DIR \"${CMAKE_CURRENT_SOURCE_DIR}/ephemeral\")\n\n# Configuration provided via flutter tool.\ninclude(${EPHEMERAL_DIR}/generated_config.cmake)\n\n# TODO: Move the rest of this into files in ephemeral. See\n# https://github.com/flutter/flutter/issues/57146.\nset(WRAPPER_ROOT \"${EPHEMERAL_DIR}/cpp_client_wrapper\")\n\n# === Flutter Library ===\nset(FLUTTER_LIBRARY \"${EPHEMERAL_DIR}/flutter_windows.dll\")\n\n# Published to parent scope for install step.\nset(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)\nset(FLUTTER_ICU_DATA_FILE \"${EPHEMERAL_DIR}/icudtl.dat\" PARENT_SCOPE)\nset(PROJECT_BUILD_DIR \"${PROJECT_DIR}/build/\" PARENT_SCOPE)\nset(AOT_LIBRARY \"${PROJECT_DIR}/build/windows/app.so\" PARENT_SCOPE)\n\nlist(APPEND FLUTTER_LIBRARY_HEADERS\n  \"flutter_export.h\"\n  \"flutter_windows.h\"\n  \"flutter_messenger.h\"\n  \"flutter_plugin_registrar.h\"\n  \"flutter_texture_registrar.h\"\n)\nlist(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND \"${EPHEMERAL_DIR}/\")\nadd_library(flutter INTERFACE)\ntarget_include_directories(flutter INTERFACE\n  \"${EPHEMERAL_DIR}\"\n)\ntarget_link_libraries(flutter INTERFACE \"${FLUTTER_LIBRARY}.lib\")\nadd_dependencies(flutter flutter_assemble)\n\n# === Wrapper ===\nlist(APPEND CPP_WRAPPER_SOURCES_CORE\n  \"core_implementations.cc\"\n  \"standard_codec.cc\"\n)\nlist(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND \"${WRAPPER_ROOT}/\")\nlist(APPEND CPP_WRAPPER_SOURCES_PLUGIN\n  \"plugin_registrar.cc\"\n)\nlist(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND \"${WRAPPER_ROOT}/\")\nlist(APPEND CPP_WRAPPER_SOURCES_APP\n  \"flutter_engine.cc\"\n  \"flutter_view_controller.cc\"\n)\nlist(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND \"${WRAPPER_ROOT}/\")\n\n# Wrapper sources needed for a plugin.\nadd_library(flutter_wrapper_plugin STATIC\n  ${CPP_WRAPPER_SOURCES_CORE}\n  ${CPP_WRAPPER_SOURCES_PLUGIN}\n)\napply_standard_settings(flutter_wrapper_plugin)\nset_target_properties(flutter_wrapper_plugin PROPERTIES\n  POSITION_INDEPENDENT_CODE ON)\nset_target_properties(flutter_wrapper_plugin PROPERTIES\n  CXX_VISIBILITY_PRESET hidden)\ntarget_link_libraries(flutter_wrapper_plugin PUBLIC flutter)\ntarget_include_directories(flutter_wrapper_plugin PUBLIC\n  \"${WRAPPER_ROOT}/include\"\n)\nadd_dependencies(flutter_wrapper_plugin flutter_assemble)\n\n# Wrapper sources needed for the runner.\nadd_library(flutter_wrapper_app STATIC\n  ${CPP_WRAPPER_SOURCES_CORE}\n  ${CPP_WRAPPER_SOURCES_APP}\n)\napply_standard_settings(flutter_wrapper_app)\ntarget_link_libraries(flutter_wrapper_app PUBLIC flutter)\ntarget_include_directories(flutter_wrapper_app PUBLIC\n  \"${WRAPPER_ROOT}/include\"\n)\nadd_dependencies(flutter_wrapper_app flutter_assemble)\n\n# === Flutter tool backend ===\n# _phony_ is a non-existent file to force this command to run every time,\n# since currently there's no way to get a full input/output list from the\n# flutter tool.\nset(PHONY_OUTPUT \"${CMAKE_CURRENT_BINARY_DIR}/_phony_\")\nset_source_files_properties(\"${PHONY_OUTPUT}\" PROPERTIES SYMBOLIC TRUE)\nadd_custom_command(\n  OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}\n    ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN}\n    ${CPP_WRAPPER_SOURCES_APP}\n    ${PHONY_OUTPUT}\n  COMMAND ${CMAKE_COMMAND} -E env\n    ${FLUTTER_TOOL_ENVIRONMENT}\n    \"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat\"\n      windows-x64 $<CONFIG>\n  VERBATIM\n)\nadd_custom_target(flutter_assemble DEPENDS\n  \"${FLUTTER_LIBRARY}\"\n  ${FLUTTER_LIBRARY_HEADERS}\n  ${CPP_WRAPPER_SOURCES_CORE}\n  ${CPP_WRAPPER_SOURCES_PLUGIN}\n  ${CPP_WRAPPER_SOURCES_APP}\n)\n"
  },
  {
    "path": "example_nav2/windows/flutter/generated_plugin_registrant.cc",
    "content": "//\n//  Generated file. Do not edit.\n//\n\n// clang-format off\n\n#include \"generated_plugin_registrant.h\"\n\n\nvoid RegisterPlugins(flutter::PluginRegistry* registry) {\n}\n"
  },
  {
    "path": "example_nav2/windows/flutter/generated_plugin_registrant.h",
    "content": "//\n//  Generated file. Do not edit.\n//\n\n// clang-format off\n\n#ifndef GENERATED_PLUGIN_REGISTRANT_\n#define GENERATED_PLUGIN_REGISTRANT_\n\n#include <flutter/plugin_registry.h>\n\n// Registers Flutter plugins.\nvoid RegisterPlugins(flutter::PluginRegistry* registry);\n\n#endif  // GENERATED_PLUGIN_REGISTRANT_\n"
  },
  {
    "path": "example_nav2/windows/flutter/generated_plugins.cmake",
    "content": "#\n# Generated file, do not edit.\n#\n\nlist(APPEND FLUTTER_PLUGIN_LIST\n)\n\nlist(APPEND FLUTTER_FFI_PLUGIN_LIST\n)\n\nset(PLUGIN_BUNDLED_LIBRARIES)\n\nforeach(plugin ${FLUTTER_PLUGIN_LIST})\n  add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin})\n  target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)\n  list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)\n  list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})\nendforeach(plugin)\n\nforeach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})\n  add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin})\n  list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})\nendforeach(ffi_plugin)\n"
  },
  {
    "path": "example_nav2/windows/runner/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.15)\nproject(runner LANGUAGES CXX)\n\nadd_executable(${BINARY_NAME} WIN32\n  \"flutter_window.cpp\"\n  \"main.cpp\"\n  \"run_loop.cpp\"\n  \"utils.cpp\"\n  \"win32_window.cpp\"\n  \"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc\"\n  \"Runner.rc\"\n  \"runner.exe.manifest\"\n)\napply_standard_settings(${BINARY_NAME})\ntarget_compile_definitions(${BINARY_NAME} PRIVATE \"NOMINMAX\")\ntarget_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app)\ntarget_include_directories(${BINARY_NAME} PRIVATE \"${CMAKE_SOURCE_DIR}\")\nadd_dependencies(${BINARY_NAME} flutter_assemble)\n"
  },
  {
    "path": "example_nav2/windows/runner/Runner.rc",
    "content": "// Microsoft Visual C++ generated resource script.\n//\n#pragma code_page(65001)\n#include \"resource.h\"\n\n#define APSTUDIO_READONLY_SYMBOLS\n/////////////////////////////////////////////////////////////////////////////\n//\n// Generated from the TEXTINCLUDE 2 resource.\n//\n#include \"winres.h\"\n\n/////////////////////////////////////////////////////////////////////////////\n#undef APSTUDIO_READONLY_SYMBOLS\n\n/////////////////////////////////////////////////////////////////////////////\n// English (United States) resources\n\n#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\nLANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\n\n#ifdef APSTUDIO_INVOKED\n/////////////////////////////////////////////////////////////////////////////\n//\n// TEXTINCLUDE\n//\n\n1 TEXTINCLUDE\nBEGIN\n    \"resource.h\\0\"\nEND\n\n2 TEXTINCLUDE\nBEGIN\n    \"#include \"\"winres.h\"\"\\r\\n\"\n    \"\\0\"\nEND\n\n3 TEXTINCLUDE\nBEGIN\n    \"\\r\\n\"\n    \"\\0\"\nEND\n\n#endif    // APSTUDIO_INVOKED\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// Icon\n//\n\n// Icon with lowest ID value placed first to ensure application icon\n// remains consistent on all systems.\nIDI_APP_ICON            ICON                    \"resources\\\\app_icon.ico\"\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// Version\n//\n\n#ifdef FLUTTER_BUILD_NUMBER\n#define VERSION_AS_NUMBER FLUTTER_BUILD_NUMBER\n#else\n#define VERSION_AS_NUMBER 1,0,0\n#endif\n\n#ifdef FLUTTER_BUILD_NAME\n#define VERSION_AS_STRING #FLUTTER_BUILD_NAME\n#else\n#define VERSION_AS_STRING \"1.0.0\"\n#endif\n\nVS_VERSION_INFO VERSIONINFO\n FILEVERSION VERSION_AS_NUMBER\n PRODUCTVERSION VERSION_AS_NUMBER\n FILEFLAGSMASK VS_FFI_FILEFLAGSMASK\n#ifdef _DEBUG\n FILEFLAGS VS_FF_DEBUG\n#else\n FILEFLAGS 0x0L\n#endif\n FILEOS VOS__WINDOWS32\n FILETYPE VFT_APP\n FILESUBTYPE 0x0L\nBEGIN\n    BLOCK \"StringFileInfo\"\n    BEGIN\n        BLOCK \"040904e4\"\n        BEGIN\n            VALUE \"CompanyName\", \"com.get\" \"\\0\"\n            VALUE \"FileDescription\", \"A new Flutter project.\" \"\\0\"\n            VALUE \"FileVersion\", VERSION_AS_STRING \"\\0\"\n            VALUE \"InternalName\", \"example_nav2\" \"\\0\"\n            VALUE \"LegalCopyright\", \"Copyright (C) 2021 com.get. All rights reserved.\" \"\\0\"\n            VALUE \"OriginalFilename\", \"example_nav2.exe\" \"\\0\"\n            VALUE \"ProductName\", \"example_nav2\" \"\\0\"\n            VALUE \"ProductVersion\", VERSION_AS_STRING \"\\0\"\n        END\n    END\n    BLOCK \"VarFileInfo\"\n    BEGIN\n        VALUE \"Translation\", 0x409, 1252\n    END\nEND\n\n#endif    // English (United States) resources\n/////////////////////////////////////////////////////////////////////////////\n\n\n\n#ifndef APSTUDIO_INVOKED\n/////////////////////////////////////////////////////////////////////////////\n//\n// Generated from the TEXTINCLUDE 3 resource.\n//\n\n\n/////////////////////////////////////////////////////////////////////////////\n#endif    // not APSTUDIO_INVOKED\n"
  },
  {
    "path": "example_nav2/windows/runner/flutter_window.cpp",
    "content": "#include \"flutter_window.h\"\n\n#include <optional>\n\n#include \"flutter/generated_plugin_registrant.h\"\n\nFlutterWindow::FlutterWindow(RunLoop* run_loop,\n                             const flutter::DartProject& project)\n    : run_loop_(run_loop), project_(project) {}\n\nFlutterWindow::~FlutterWindow() {}\n\nbool FlutterWindow::OnCreate() {\n  if (!Win32Window::OnCreate()) {\n    return false;\n  }\n\n  RECT frame = GetClientArea();\n\n  // The size here must match the window dimensions to avoid unnecessary surface\n  // creation / destruction in the startup path.\n  flutter_controller_ = std::make_unique<flutter::FlutterViewController>(\n      frame.right - frame.left, frame.bottom - frame.top, project_);\n  // Ensure that basic setup of the controller was successful.\n  if (!flutter_controller_->engine() || !flutter_controller_->view()) {\n    return false;\n  }\n  RegisterPlugins(flutter_controller_->engine());\n  run_loop_->RegisterFlutterInstance(flutter_controller_->engine());\n  SetChildContent(flutter_controller_->view()->GetNativeWindow());\n  return true;\n}\n\nvoid FlutterWindow::OnDestroy() {\n  if (flutter_controller_) {\n    run_loop_->UnregisterFlutterInstance(flutter_controller_->engine());\n    flutter_controller_ = nullptr;\n  }\n\n  Win32Window::OnDestroy();\n}\n\nLRESULT\nFlutterWindow::MessageHandler(HWND hwnd, UINT const message,\n                              WPARAM const wparam,\n                              LPARAM const lparam) noexcept {\n  // Give Flutter, including plugins, an opportunity to handle window messages.\n  if (flutter_controller_) {\n    std::optional<LRESULT> result =\n        flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam,\n                                                      lparam);\n    if (result) {\n      return *result;\n    }\n  }\n\n  switch (message) {\n    case WM_FONTCHANGE:\n      flutter_controller_->engine()->ReloadSystemFonts();\n      break;\n  }\n\n  return Win32Window::MessageHandler(hwnd, message, wparam, lparam);\n}\n"
  },
  {
    "path": "example_nav2/windows/runner/flutter_window.h",
    "content": "#ifndef RUNNER_FLUTTER_WINDOW_H_\n#define RUNNER_FLUTTER_WINDOW_H_\n\n#include <flutter/dart_project.h>\n#include <flutter/flutter_view_controller.h>\n\n#include <memory>\n\n#include \"run_loop.h\"\n#include \"win32_window.h\"\n\n// A window that does nothing but host a Flutter view.\nclass FlutterWindow : public Win32Window {\n public:\n  // Creates a new FlutterWindow driven by the |run_loop|, hosting a\n  // Flutter view running |project|.\n  explicit FlutterWindow(RunLoop* run_loop,\n                         const flutter::DartProject& project);\n  virtual ~FlutterWindow();\n\n protected:\n  // Win32Window:\n  bool OnCreate() override;\n  void OnDestroy() override;\n  LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam,\n                         LPARAM const lparam) noexcept override;\n\n private:\n  // The run loop driving events for this window.\n  RunLoop* run_loop_;\n\n  // The project to run.\n  flutter::DartProject project_;\n\n  // The Flutter instance hosted by this window.\n  std::unique_ptr<flutter::FlutterViewController> flutter_controller_;\n};\n\n#endif  // RUNNER_FLUTTER_WINDOW_H_\n"
  },
  {
    "path": "example_nav2/windows/runner/main.cpp",
    "content": "#include <flutter/dart_project.h>\n#include <flutter/flutter_view_controller.h>\n#include <windows.h>\n\n#include \"flutter_window.h\"\n#include \"run_loop.h\"\n#include \"utils.h\"\n\nint APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,\n                      _In_ wchar_t *command_line, _In_ int show_command) {\n  // Attach to console when present (e.g., 'flutter run') or create a\n  // new console when running with a debugger.\n  if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) {\n    CreateAndAttachConsole();\n  }\n\n  // Initialize COM, so that it is available for use in the library and/or\n  // plugins.\n  ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);\n\n  RunLoop run_loop;\n\n  flutter::DartProject project(L\"data\");\n\n  std::vector<std::string> command_line_arguments =\n      GetCommandLineArguments();\n\n  project.set_dart_entrypoint_arguments(std::move(command_line_arguments));\n\n  FlutterWindow window(&run_loop, project);\n  Win32Window::Point origin(10, 10);\n  Win32Window::Size size(1280, 720);\n  if (!window.CreateAndShow(L\"example_nav2\", origin, size)) {\n    return EXIT_FAILURE;\n  }\n  window.SetQuitOnClose(true);\n\n  run_loop.Run();\n\n  ::CoUninitialize();\n  return EXIT_SUCCESS;\n}\n"
  },
  {
    "path": "example_nav2/windows/runner/resource.h",
    "content": "//{{NO_DEPENDENCIES}}\n// Microsoft Visual C++ generated include file.\n// Used by Runner.rc\n//\n#define IDI_APP_ICON                    101\n\n// Next default values for new objects\n//\n#ifdef APSTUDIO_INVOKED\n#ifndef APSTUDIO_READONLY_SYMBOLS\n#define _APS_NEXT_RESOURCE_VALUE        102\n#define _APS_NEXT_COMMAND_VALUE         40001\n#define _APS_NEXT_CONTROL_VALUE         1001\n#define _APS_NEXT_SYMED_VALUE           101\n#endif\n#endif\n"
  },
  {
    "path": "example_nav2/windows/runner/run_loop.cpp",
    "content": "#include \"run_loop.h\"\n\n#include <windows.h>\n\n#include <algorithm>\n\nRunLoop::RunLoop() {}\n\nRunLoop::~RunLoop() {}\n\nvoid RunLoop::Run() {\n  bool keep_running = true;\n  TimePoint next_flutter_event_time = TimePoint::clock::now();\n  while (keep_running) {\n    std::chrono::nanoseconds wait_duration =\n        std::max(std::chrono::nanoseconds(0),\n                 next_flutter_event_time - TimePoint::clock::now());\n    ::MsgWaitForMultipleObjects(\n        0, nullptr, FALSE, static_cast<DWORD>(wait_duration.count() / 1000),\n        QS_ALLINPUT);\n    bool processed_events = false;\n    MSG message;\n    // All pending Windows messages must be processed; MsgWaitForMultipleObjects\n    // won't return again for items left in the queue after PeekMessage.\n    while (::PeekMessage(&message, nullptr, 0, 0, PM_REMOVE)) {\n      processed_events = true;\n      if (message.message == WM_QUIT) {\n        keep_running = false;\n        break;\n      }\n      ::TranslateMessage(&message);\n      ::DispatchMessage(&message);\n      // Allow Flutter to process messages each time a Windows message is\n      // processed, to prevent starvation.\n      next_flutter_event_time =\n          std::min(next_flutter_event_time, ProcessFlutterMessages());\n    }\n    // If the PeekMessage loop didn't run, process Flutter messages.\n    if (!processed_events) {\n      next_flutter_event_time =\n          std::min(next_flutter_event_time, ProcessFlutterMessages());\n    }\n  }\n}\n\nvoid RunLoop::RegisterFlutterInstance(\n    flutter::FlutterEngine* flutter_instance) {\n  flutter_instances_.insert(flutter_instance);\n}\n\nvoid RunLoop::UnregisterFlutterInstance(\n    flutter::FlutterEngine* flutter_instance) {\n  flutter_instances_.erase(flutter_instance);\n}\n\nRunLoop::TimePoint RunLoop::ProcessFlutterMessages() {\n  TimePoint next_event_time = TimePoint::max();\n  for (auto instance : flutter_instances_) {\n    std::chrono::nanoseconds wait_duration = instance->ProcessMessages();\n    if (wait_duration != std::chrono::nanoseconds::max()) {\n      next_event_time =\n          std::min(next_event_time, TimePoint::clock::now() + wait_duration);\n    }\n  }\n  return next_event_time;\n}\n"
  },
  {
    "path": "example_nav2/windows/runner/run_loop.h",
    "content": "#ifndef RUNNER_RUN_LOOP_H_\n#define RUNNER_RUN_LOOP_H_\n\n#include <flutter/flutter_engine.h>\n\n#include <chrono>\n#include <set>\n\n// A runloop that will service events for Flutter instances as well\n// as native messages.\nclass RunLoop {\n public:\n  RunLoop();\n  ~RunLoop();\n\n  // Prevent copying\n  RunLoop(RunLoop const&) = delete;\n  RunLoop& operator=(RunLoop const&) = delete;\n\n  // Runs the run loop until the application quits.\n  void Run();\n\n  // Registers the given Flutter instance for event servicing.\n  void RegisterFlutterInstance(\n      flutter::FlutterEngine* flutter_instance);\n\n  // Unregisters the given Flutter instance from event servicing.\n  void UnregisterFlutterInstance(\n      flutter::FlutterEngine* flutter_instance);\n\n private:\n  using TimePoint = std::chrono::steady_clock::time_point;\n\n  // Processes all currently pending messages for registered Flutter instances.\n  TimePoint ProcessFlutterMessages();\n\n  std::set<flutter::FlutterEngine*> flutter_instances_;\n};\n\n#endif  // RUNNER_RUN_LOOP_H_\n"
  },
  {
    "path": "example_nav2/windows/runner/runner.exe.manifest",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n  <application xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n    <windowsSettings>\n      <dpiAwareness xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">PerMonitorV2</dpiAwareness>\n    </windowsSettings>\n  </application>\n  <compatibility xmlns=\"urn:schemas-microsoft-com:compatibility.v1\">\n    <application>\n      <!-- Windows 10 -->\n      <supportedOS Id=\"{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}\"/>\n      <!-- Windows 8.1 -->\n      <supportedOS Id=\"{1f676c76-80e1-4239-95bb-83d0f6d0da78}\"/>\n      <!-- Windows 8 -->\n      <supportedOS Id=\"{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}\"/>\n      <!-- Windows 7 -->\n      <supportedOS Id=\"{35138b9a-5d96-4fbd-8e2d-a2440225f93a}\"/>\n    </application>\n  </compatibility>\n</assembly>\n"
  },
  {
    "path": "example_nav2/windows/runner/utils.cpp",
    "content": "#include \"utils.h\"\n\n#include <flutter_windows.h>\n#include <io.h>\n#include <stdio.h>\n#include <windows.h>\n\n#include <iostream>\n\nvoid CreateAndAttachConsole() {\n  if (::AllocConsole()) {\n    FILE *unused;\n    if (freopen_s(&unused, \"CONOUT$\", \"w\", stdout)) {\n      _dup2(_fileno(stdout), 1);\n    }\n    if (freopen_s(&unused, \"CONOUT$\", \"w\", stderr)) {\n      _dup2(_fileno(stdout), 2);\n    }\n    std::ios::sync_with_stdio();\n    FlutterDesktopResyncOutputStreams();\n  }\n}\n\nstd::vector<std::string> GetCommandLineArguments() {\n  // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use.\n  int argc;\n  wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);\n  if (argv == nullptr) {\n    return std::vector<std::string>();\n  }\n\n  std::vector<std::string> command_line_arguments;\n\n  // Skip the first argument as it's the binary name.\n  for (int i = 1; i < argc; i++) {\n    command_line_arguments.push_back(Utf8FromUtf16(argv[i]));\n  }\n\n  ::LocalFree(argv);\n\n  return command_line_arguments;\n}\n\nstd::string Utf8FromUtf16(const wchar_t* utf16_string) {\n  if (utf16_string == nullptr) {\n    return std::string();\n  }\n  int target_length = ::WideCharToMultiByte(\n      CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,\n      -1, nullptr, 0, nullptr, nullptr);\n  if (target_length == 0) {\n    return std::string();\n  }\n  std::string utf8_string;\n  utf8_string.resize(target_length);\n  int converted_length = ::WideCharToMultiByte(\n      CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,\n      -1, utf8_string.data(),\n      target_length, nullptr, nullptr);\n  if (converted_length == 0) {\n    return std::string();\n  }\n  return utf8_string;\n}\n"
  },
  {
    "path": "example_nav2/windows/runner/utils.h",
    "content": "#ifndef RUNNER_UTILS_H_\n#define RUNNER_UTILS_H_\n\n#include <string>\n#include <vector>\n\n// Creates a console for the process, and redirects stdout and stderr to\n// it for both the runner and the Flutter library.\nvoid CreateAndAttachConsole();\n\n// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string\n// encoded in UTF-8. Returns an empty std::string on failure.\nstd::string Utf8FromUtf16(const wchar_t* utf16_string);\n\n// Gets the command line arguments passed in as a std::vector<std::string>,\n// encoded in UTF-8. Returns an empty std::vector<std::string> on failure.\nstd::vector<std::string> GetCommandLineArguments();\n\n#endif  // RUNNER_UTILS_H_\n"
  },
  {
    "path": "example_nav2/windows/runner/win32_window.cpp",
    "content": "#include \"win32_window.h\"\n\n#include <flutter_windows.h>\n\n#include \"resource.h\"\n\nnamespace {\n\nconstexpr const wchar_t kWindowClassName[] = L\"FLUTTER_RUNNER_WIN32_WINDOW\";\n\n// The number of Win32Window objects that currently exist.\nstatic int g_active_window_count = 0;\n\nusing EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd);\n\n// Scale helper to convert logical scaler values to physical using passed in\n// scale factor\nint Scale(int source, double scale_factor) {\n  return static_cast<int>(source * scale_factor);\n}\n\n// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module.\n// This API is only needed for PerMonitor V1 awareness mode.\nvoid EnableFullDpiSupportIfAvailable(HWND hwnd) {\n  HMODULE user32_module = LoadLibraryA(\"User32.dll\");\n  if (!user32_module) {\n    return;\n  }\n  auto enable_non_client_dpi_scaling =\n      reinterpret_cast<EnableNonClientDpiScaling*>(\n          GetProcAddress(user32_module, \"EnableNonClientDpiScaling\"));\n  if (enable_non_client_dpi_scaling != nullptr) {\n    enable_non_client_dpi_scaling(hwnd);\n    FreeLibrary(user32_module);\n  }\n}\n\n}  // namespace\n\n// Manages the Win32Window's window class registration.\nclass WindowClassRegistrar {\n public:\n  ~WindowClassRegistrar() = default;\n\n  // Returns the singleton registar instance.\n  static WindowClassRegistrar* GetInstance() {\n    if (!instance_) {\n      instance_ = new WindowClassRegistrar();\n    }\n    return instance_;\n  }\n\n  // Returns the name of the window class, registering the class if it hasn't\n  // previously been registered.\n  const wchar_t* GetWindowClass();\n\n  // Unregisters the window class. Should only be called if there are no\n  // instances of the window.\n  void UnregisterWindowClass();\n\n private:\n  WindowClassRegistrar() = default;\n\n  static WindowClassRegistrar* instance_;\n\n  bool class_registered_ = false;\n};\n\nWindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr;\n\nconst wchar_t* WindowClassRegistrar::GetWindowClass() {\n  if (!class_registered_) {\n    WNDCLASS window_class{};\n    window_class.hCursor = LoadCursor(nullptr, IDC_ARROW);\n    window_class.lpszClassName = kWindowClassName;\n    window_class.style = CS_HREDRAW | CS_VREDRAW;\n    window_class.cbClsExtra = 0;\n    window_class.cbWndExtra = 0;\n    window_class.hInstance = GetModuleHandle(nullptr);\n    window_class.hIcon =\n        LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON));\n    window_class.hbrBackground = 0;\n    window_class.lpszMenuName = nullptr;\n    window_class.lpfnWndProc = Win32Window::WndProc;\n    RegisterClass(&window_class);\n    class_registered_ = true;\n  }\n  return kWindowClassName;\n}\n\nvoid WindowClassRegistrar::UnregisterWindowClass() {\n  UnregisterClass(kWindowClassName, nullptr);\n  class_registered_ = false;\n}\n\nWin32Window::Win32Window() {\n  ++g_active_window_count;\n}\n\nWin32Window::~Win32Window() {\n  --g_active_window_count;\n  Destroy();\n}\n\nbool Win32Window::CreateAndShow(const std::wstring& title,\n                                const Point& origin,\n                                const Size& size) {\n  Destroy();\n\n  const wchar_t* window_class =\n      WindowClassRegistrar::GetInstance()->GetWindowClass();\n\n  const POINT target_point = {static_cast<LONG>(origin.x),\n                              static_cast<LONG>(origin.y)};\n  HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST);\n  UINT dpi = FlutterDesktopGetDpiForMonitor(monitor);\n  double scale_factor = dpi / 96.0;\n\n  HWND window = CreateWindow(\n      window_class, title.c_str(), WS_OVERLAPPEDWINDOW | WS_VISIBLE,\n      Scale(origin.x, scale_factor), Scale(origin.y, scale_factor),\n      Scale(size.width, scale_factor), Scale(size.height, scale_factor),\n      nullptr, nullptr, GetModuleHandle(nullptr), this);\n\n  if (!window) {\n    return false;\n  }\n\n  return OnCreate();\n}\n\n// static\nLRESULT CALLBACK Win32Window::WndProc(HWND const window,\n                                      UINT const message,\n                                      WPARAM const wparam,\n                                      LPARAM const lparam) noexcept {\n  if (message == WM_NCCREATE) {\n    auto window_struct = reinterpret_cast<CREATESTRUCT*>(lparam);\n    SetWindowLongPtr(window, GWLP_USERDATA,\n                     reinterpret_cast<LONG_PTR>(window_struct->lpCreateParams));\n\n    auto that = static_cast<Win32Window*>(window_struct->lpCreateParams);\n    EnableFullDpiSupportIfAvailable(window);\n    that->window_handle_ = window;\n  } else if (Win32Window* that = GetThisFromHandle(window)) {\n    return that->MessageHandler(window, message, wparam, lparam);\n  }\n\n  return DefWindowProc(window, message, wparam, lparam);\n}\n\nLRESULT\nWin32Window::MessageHandler(HWND hwnd,\n                            UINT const message,\n                            WPARAM const wparam,\n                            LPARAM const lparam) noexcept {\n  switch (message) {\n    case WM_DESTROY:\n      window_handle_ = nullptr;\n      Destroy();\n      if (quit_on_close_) {\n        PostQuitMessage(0);\n      }\n      return 0;\n\n    case WM_DPICHANGED: {\n      auto newRectSize = reinterpret_cast<RECT*>(lparam);\n      LONG newWidth = newRectSize->right - newRectSize->left;\n      LONG newHeight = newRectSize->bottom - newRectSize->top;\n\n      SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth,\n                   newHeight, SWP_NOZORDER | SWP_NOACTIVATE);\n\n      return 0;\n    }\n    case WM_SIZE: {\n      RECT rect = GetClientArea();\n      if (child_content_ != nullptr) {\n        // Size and position the child window.\n        MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left,\n                   rect.bottom - rect.top, TRUE);\n      }\n      return 0;\n    }\n\n    case WM_ACTIVATE:\n      if (child_content_ != nullptr) {\n        SetFocus(child_content_);\n      }\n      return 0;\n  }\n\n  return DefWindowProc(window_handle_, message, wparam, lparam);\n}\n\nvoid Win32Window::Destroy() {\n  OnDestroy();\n\n  if (window_handle_) {\n    DestroyWindow(window_handle_);\n    window_handle_ = nullptr;\n  }\n  if (g_active_window_count == 0) {\n    WindowClassRegistrar::GetInstance()->UnregisterWindowClass();\n  }\n}\n\nWin32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept {\n  return reinterpret_cast<Win32Window*>(\n      GetWindowLongPtr(window, GWLP_USERDATA));\n}\n\nvoid Win32Window::SetChildContent(HWND content) {\n  child_content_ = content;\n  SetParent(content, window_handle_);\n  RECT frame = GetClientArea();\n\n  MoveWindow(content, frame.left, frame.top, frame.right - frame.left,\n             frame.bottom - frame.top, true);\n\n  SetFocus(child_content_);\n}\n\nRECT Win32Window::GetClientArea() {\n  RECT frame;\n  GetClientRect(window_handle_, &frame);\n  return frame;\n}\n\nHWND Win32Window::GetHandle() {\n  return window_handle_;\n}\n\nvoid Win32Window::SetQuitOnClose(bool quit_on_close) {\n  quit_on_close_ = quit_on_close;\n}\n\nbool Win32Window::OnCreate() {\n  // No-op; provided for subclasses.\n  return true;\n}\n\nvoid Win32Window::OnDestroy() {\n  // No-op; provided for subclasses.\n}\n"
  },
  {
    "path": "example_nav2/windows/runner/win32_window.h",
    "content": "#ifndef RUNNER_WIN32_WINDOW_H_\n#define RUNNER_WIN32_WINDOW_H_\n\n#include <windows.h>\n\n#include <functional>\n#include <memory>\n#include <string>\n\n// A class abstraction for a high DPI-aware Win32 Window. Intended to be\n// inherited from by classes that wish to specialize with custom\n// rendering and input handling\nclass Win32Window {\n public:\n  struct Point {\n    unsigned int x;\n    unsigned int y;\n    Point(unsigned int x, unsigned int y) : x(x), y(y) {}\n  };\n\n  struct Size {\n    unsigned int width;\n    unsigned int height;\n    Size(unsigned int width, unsigned int height)\n        : width(width), height(height) {}\n  };\n\n  Win32Window();\n  virtual ~Win32Window();\n\n  // Creates and shows a win32 window with |title| and position and size using\n  // |origin| and |size|. New windows are created on the default monitor. Window\n  // sizes are specified to the OS in physical pixels, hence to ensure a\n  // consistent size to will treat the width height passed in to this function\n  // as logical pixels and scale to appropriate for the default monitor. Returns\n  // true if the window was created successfully.\n  bool CreateAndShow(const std::wstring& title,\n                     const Point& origin,\n                     const Size& size);\n\n  // Release OS resources associated with window.\n  void Destroy();\n\n  // Inserts |content| into the window tree.\n  void SetChildContent(HWND content);\n\n  // Returns the backing Window handle to enable clients to set icon and other\n  // window properties. Returns nullptr if the window has been destroyed.\n  HWND GetHandle();\n\n  // If true, closing this window will quit the application.\n  void SetQuitOnClose(bool quit_on_close);\n\n  // Return a RECT representing the bounds of the current client area.\n  RECT GetClientArea();\n\n protected:\n  // Processes and route salient window messages for mouse handling,\n  // size change and DPI. Delegates handling of these to member overloads that\n  // inheriting classes can handle.\n  virtual LRESULT MessageHandler(HWND window,\n                                 UINT const message,\n                                 WPARAM const wparam,\n                                 LPARAM const lparam) noexcept;\n\n  // Called when CreateAndShow is called, allowing subclass window-related\n  // setup. Subclasses should return false if setup fails.\n  virtual bool OnCreate();\n\n  // Called when Destroy is called.\n  virtual void OnDestroy();\n\n private:\n  friend class WindowClassRegistrar;\n\n  // OS callback called by message pump. Handles the WM_NCCREATE message which\n  // is passed when the non-client area is being created and enables automatic\n  // non-client DPI scaling so that the non-client area automatically\n  // responsponds to changes in DPI. All other messages are handled by\n  // MessageHandler.\n  static LRESULT CALLBACK WndProc(HWND const window,\n                                  UINT const message,\n                                  WPARAM const wparam,\n                                  LPARAM const lparam) noexcept;\n\n  // Retrieves a class instance pointer for |window|\n  static Win32Window* GetThisFromHandle(HWND const window) noexcept;\n\n  bool quit_on_close_ = false;\n\n  // window handle for top level window.\n  HWND window_handle_ = nullptr;\n\n  // window handle for hosted content.\n  HWND child_content_ = nullptr;\n};\n\n#endif  // RUNNER_WIN32_WINDOW_H_\n"
  },
  {
    "path": "lib/get.dart",
    "content": "/// GetX is an extra-light and powerful multi-platform framework.\n/// It combines high performance state management, intelligent dependency\n/// injection, and route management in a quick and practical way.\nlibrary;\n\nexport 'get_animations/index.dart';\nexport 'get_common/get_reset.dart';\nexport 'get_connect/connect.dart';\nexport 'get_core/get_core.dart';\nexport 'get_instance/get_instance.dart';\nexport 'get_navigation/get_navigation.dart';\nexport 'get_rx/get_rx.dart';\nexport 'get_state_manager/get_state_manager.dart';\nexport 'get_utils/get_utils.dart';\nexport 'route_manager.dart';\n"
  },
  {
    "path": "lib/get_animations/animations.dart",
    "content": "import 'dart:math';\nimport 'dart:ui';\n\nimport 'package:flutter/widgets.dart';\n\nimport 'get_animated_builder.dart';\n\ntypedef OffsetBuilder = Offset Function(BuildContext, double);\n\nclass FadeInAnimation extends OpacityAnimation {\n  FadeInAnimation({\n    super.key,\n    required super.duration,\n    required super.delay,\n    required super.child,\n    super.onComplete,\n    super.begin = 0,\n    super.end = 1,\n    super.idleValue = 0,\n  });\n}\n\nclass FadeOutAnimation extends OpacityAnimation {\n  FadeOutAnimation({\n    super.key,\n    required super.duration,\n    required super.delay,\n    required super.child,\n    super.onComplete,\n    super.begin = 1,\n    super.end = 0,\n    super.idleValue = 1,\n  });\n}\n\nclass OpacityAnimation extends GetAnimatedBuilder<double> {\n  OpacityAnimation({\n    super.key,\n    required super.duration,\n    required super.delay,\n    required super.child,\n    required super.onComplete,\n    required double begin,\n    required double end,\n    required super.idleValue,\n  }) : super(\n          tween: Tween<double>(begin: begin, end: end),\n          builder: (context, value, child) {\n            return Opacity(\n              opacity: value,\n              child: child!,\n            );\n          },\n        );\n}\n\nclass RotateAnimation extends GetAnimatedBuilder<double> {\n  RotateAnimation({\n    super.key,\n    required super.duration,\n    required super.delay,\n    required super.child,\n    super.onComplete,\n    required double begin,\n    required double end,\n    super.idleValue = 0,\n  }) : super(\n          builder: (context, value, child) => Transform.rotate(\n            angle: value,\n            child: child,\n          ),\n          tween: Tween<double>(begin: begin, end: end),\n        );\n}\n\nclass ScaleAnimation extends GetAnimatedBuilder<double> {\n  ScaleAnimation({\n    super.key,\n    required super.duration,\n    required super.delay,\n    required super.child,\n    super.onComplete,\n    required double begin,\n    required double end,\n    super.idleValue = 0,\n  }) : super(\n          builder: (context, value, child) => Transform.scale(\n            scale: value,\n            child: child,\n          ),\n          tween: Tween<double>(begin: begin, end: end),\n        );\n}\n\n// class SlideAnimation extends GetAnimatedBuilder<Offset> {\n//   SlideAnimation({\n//     super.key,\n//     required super.duration,\n//     required super.delay,\n//     required super.child,\n//     super.onComplete,\n//     required Offset begin,\n//     required Offset end,\n//     super.idleValue = const Offset(0, 0),\n//   }) : super(\n//           builder: (context, value, child) => Transform.translate(\n//             offset: value,\n//             child: child,\n//           ),\n//           tween: Tween(begin: begin, end: end),\n//         );\n// }\n\nclass BounceAnimation extends GetAnimatedBuilder<double> {\n  BounceAnimation({\n    super.key,\n    required super.duration,\n    required super.delay,\n    required super.child,\n    super.onComplete,\n    super.curve = Curves.bounceOut,\n    required double begin,\n    required double end,\n    super.idleValue = 0,\n  }) : super(\n          builder: (context, value, child) => Transform.scale(\n            scale: 1 + value.abs(),\n            child: child,\n          ),\n          tween: Tween<double>(begin: begin, end: end),\n        );\n}\n\nclass SpinAnimation extends GetAnimatedBuilder<double> {\n  SpinAnimation({\n    super.key,\n    required super.duration,\n    required super.delay,\n    required super.child,\n    super.onComplete,\n    super.idleValue = 0,\n  }) : super(\n          builder: (context, value, child) => Transform.rotate(\n            angle: value * pi / 180.0,\n            child: child,\n          ),\n          tween: Tween<double>(begin: 0, end: 360),\n        );\n}\n\nclass SizeAnimation extends GetAnimatedBuilder<double> {\n  SizeAnimation({\n    super.key,\n    required super.duration,\n    required super.delay,\n    required super.child,\n    super.onComplete,\n    super.idleValue = 0,\n    required double begin,\n    required double end,\n  }) : super(\n          builder: (context, value, child) => Transform.scale(\n            scale: value,\n            child: child,\n          ),\n          tween: Tween<double>(begin: begin, end: end),\n        );\n}\n\nclass BlurAnimation extends GetAnimatedBuilder<double> {\n  BlurAnimation({\n    super.key,\n    required super.duration,\n    required super.delay,\n    required super.child,\n    super.onComplete,\n    required double begin,\n    required double end,\n    super.idleValue = 0,\n  }) : super(\n          builder: (context, value, child) => BackdropFilter(\n            filter: ImageFilter.blur(\n              sigmaX: value,\n              sigmaY: value,\n            ),\n            child: child,\n          ),\n          tween: Tween<double>(begin: begin, end: end),\n        );\n}\n\nclass FlipAnimation extends GetAnimatedBuilder<double> {\n  FlipAnimation({\n    super.key,\n    required super.duration,\n    required super.delay,\n    required super.child,\n    super.onComplete,\n    required double begin,\n    required double end,\n    super.idleValue = 0,\n  }) : super(\n          builder: (context, value, child) {\n            final radians = value * pi;\n            return Transform(\n              transform: Matrix4.rotationY(radians),\n              alignment: Alignment.center,\n              child: child,\n            );\n          },\n          tween: Tween<double>(begin: begin, end: end),\n        );\n}\n\nclass WaveAnimation extends GetAnimatedBuilder<double> {\n  WaveAnimation({\n    super.key,\n    required super.duration,\n    required super.delay,\n    required super.child,\n    super.onComplete,\n    required double begin,\n    required double end,\n    super.idleValue = 0,\n  }) : super(\n          builder: (context, value, child) => Transform(\n            transform: Matrix4.translationValues(\n              0.0,\n              20.0 * sin(value * pi * 2),\n              0.0,\n            ),\n            child: child,\n          ),\n          tween: Tween<double>(begin: begin, end: end),\n        );\n}\n\nclass WobbleAnimation extends GetAnimatedBuilder<double> {\n  WobbleAnimation({\n    super.key,\n    required super.duration,\n    required super.delay,\n    required super.child,\n    super.onComplete,\n    required double begin,\n    required double end,\n    super.idleValue = 0,\n  }) : super(\n          builder: (context, value, child) => Transform(\n            transform: Matrix4.identity()\n              ..setEntry(3, 2, 0.001)\n              ..rotateZ(sin(value * pi * 2) * 0.1),\n            alignment: Alignment.center,\n            child: child,\n          ),\n          tween: Tween<double>(begin: begin, end: end),\n        );\n}\n\nclass SlideInLeftAnimation extends SlideAnimation {\n  SlideInLeftAnimation({\n    super.key,\n    required super.duration,\n    required super.delay,\n    required super.child,\n    super.onComplete,\n    required super.begin,\n    required super.end,\n    super.idleValue = 0,\n  }) : super(\n          offsetBuild: (context, value) =>\n              Offset(value * MediaQuery.of(context).size.width, 0),\n        );\n}\n\nclass SlideInRightAnimation extends SlideAnimation {\n  SlideInRightAnimation({\n    super.key,\n    required super.duration,\n    required super.delay,\n    required super.child,\n    super.onComplete,\n    required super.begin,\n    required super.end,\n    super.idleValue = 0,\n  }) : super(\n          offsetBuild: (context, value) =>\n              Offset((1 - value) * MediaQuery.of(context).size.width, 0),\n        );\n}\n\nclass SlideInUpAnimation extends SlideAnimation {\n  SlideInUpAnimation({\n    super.key,\n    required super.duration,\n    required super.delay,\n    required super.child,\n    super.onComplete,\n    required super.begin,\n    required super.end,\n    super.idleValue = 0,\n  }) : super(\n          offsetBuild: (context, value) =>\n              Offset(0, value * MediaQuery.of(context).size.height),\n        );\n}\n\nclass SlideInDownAnimation extends SlideAnimation {\n  SlideInDownAnimation({\n    super.key,\n    required super.duration,\n    required super.delay,\n    required super.child,\n    super.onComplete,\n    required super.begin,\n    required super.end,\n    super.idleValue = 0,\n  }) : super(\n          offsetBuild: (context, value) =>\n              Offset(0, (1 - value) * MediaQuery.of(context).size.height),\n        );\n}\n\nclass SlideAnimation extends GetAnimatedBuilder<double> {\n  SlideAnimation({\n    super.key,\n    required super.duration,\n    required super.delay,\n    required super.child,\n    required double begin,\n    required double end,\n    required OffsetBuilder offsetBuild,\n    super.onComplete,\n    super.idleValue = 0,\n  }) : super(\n          builder: (context, value, child) => Transform.translate(\n            offset: offsetBuild(context, value),\n            child: child,\n          ),\n          tween: Tween<double>(begin: begin, end: end),\n        );\n}\n\n// class ZoomAnimation extends GetAnimatedBuilder<double> {\n//   ZoomAnimation({\n//     super.key,\n//     required super.duration,\n//     required super.delay,\n//     required super.child,\n//     super.onComplete,\n//     required double begin,\n//     required double end,\n//     super.idleValue = 0,\n//   }) : super(\n//           builder: (context, value, child) => Transform.scale(\n//             scale: lerpDouble(1, end, value)!,\n//             child: child,\n//           ),\n//           tween: Tween<double>(begin: begin, end: end),\n//         );\n// }\n\nclass ColorAnimation extends GetAnimatedBuilder<Color?> {\n  ColorAnimation({\n    super.key,\n    required super.duration,\n    required super.delay,\n    required super.child,\n    super.onComplete,\n    required Color begin,\n    required Color end,\n    Color? idleColor,\n  }) : super(\n          builder: (context, value, child) => ColorFiltered(\n            colorFilter: ColorFilter.mode(\n              Color.lerp(begin, end, value!.a.toDouble())!,\n              BlendMode.srcIn,\n            ),\n            child: child,\n          ),\n          idleValue: idleColor ?? begin,\n          tween: ColorTween(begin: begin, end: end),\n        );\n}\n"
  },
  {
    "path": "lib/get_animations/extensions.dart",
    "content": "import 'package:flutter/material.dart';\n\nimport 'animations.dart';\nimport 'get_animated_builder.dart';\n\nconst _defaultDuration = Duration(seconds: 2);\nconst _defaultDelay = Duration.zero;\n\nextension AnimationExtension on Widget {\n  GetAnimatedBuilder? get _currentAnimation =>\n      (this is GetAnimatedBuilder) ? this as GetAnimatedBuilder : null;\n\n  GetAnimatedBuilder fadeIn({\n    Duration duration = _defaultDuration,\n    Duration delay = _defaultDelay,\n    ValueSetter<AnimationController>? onComplete,\n    bool isSequential = false,\n  }) {\n    assert(isSequential || this is! FadeOutAnimation,\n        'Can not use fadeOut + fadeIn when isSequential is false');\n\n    return FadeInAnimation(\n      duration: duration,\n      delay: _getDelay(isSequential, delay),\n      onComplete: onComplete,\n      child: this,\n    );\n  }\n\n  GetAnimatedBuilder fadeOut({\n    Duration duration = _defaultDuration,\n    Duration delay = _defaultDelay,\n    ValueSetter<AnimationController>? onComplete,\n    bool isSequential = false,\n  }) {\n    assert(isSequential || this is! FadeInAnimation,\n        'Can not use fadeOut() + fadeIn when isSequential is false');\n\n    return FadeOutAnimation(\n      duration: duration,\n      delay: _getDelay(isSequential, delay),\n      onComplete: onComplete,\n      child: this,\n    );\n  }\n\n  GetAnimatedBuilder rotate({\n    required double begin,\n    required double end,\n    Duration duration = _defaultDuration,\n    Duration delay = _defaultDelay,\n    ValueSetter<AnimationController>? onComplete,\n    bool isSequential = false,\n  }) {\n    return RotateAnimation(\n      duration: duration,\n      delay: _getDelay(isSequential, delay),\n      begin: begin,\n      end: end,\n      onComplete: onComplete,\n      child: this,\n    );\n  }\n\n  GetAnimatedBuilder scale({\n    required double begin,\n    required double end,\n    Duration duration = _defaultDuration,\n    Duration delay = _defaultDelay,\n    ValueSetter<AnimationController>? onComplete,\n    bool isSequential = false,\n  }) {\n    return ScaleAnimation(\n      duration: duration,\n      delay: _getDelay(isSequential, delay),\n      begin: begin,\n      end: end,\n      onComplete: onComplete,\n      child: this,\n    );\n  }\n\n  GetAnimatedBuilder slide({\n    required OffsetBuilder offset,\n    double begin = 0,\n    double end = 1,\n    Duration duration = _defaultDuration,\n    Duration delay = _defaultDelay,\n    ValueSetter<AnimationController>? onComplete,\n    bool isSequential = false,\n  }) {\n    return SlideAnimation(\n      duration: duration,\n      delay: _getDelay(isSequential, delay),\n      begin: begin,\n      end: end,\n      onComplete: onComplete,\n      offsetBuild: offset,\n      child: this,\n    );\n  }\n\n  GetAnimatedBuilder bounce({\n    required double begin,\n    required double end,\n    Duration duration = _defaultDuration,\n    Duration delay = _defaultDelay,\n    ValueSetter<AnimationController>? onComplete,\n    bool isSequential = false,\n  }) {\n    return BounceAnimation(\n      duration: duration,\n      delay: _getDelay(isSequential, delay),\n      begin: begin,\n      end: end,\n      onComplete: onComplete,\n      child: this,\n    );\n  }\n\n  GetAnimatedBuilder spin({\n    Duration duration = _defaultDuration,\n    Duration delay = _defaultDelay,\n    ValueSetter<AnimationController>? onComplete,\n    bool isSequential = false,\n  }) {\n    return SpinAnimation(\n      duration: duration,\n      delay: _getDelay(isSequential, delay),\n      onComplete: onComplete,\n      child: this,\n    );\n  }\n\n  GetAnimatedBuilder size({\n    required double begin,\n    required double end,\n    Duration duration = _defaultDuration,\n    Duration delay = _defaultDelay,\n    ValueSetter<AnimationController>? onComplete,\n    bool isSequential = false,\n  }) {\n    return SizeAnimation(\n      duration: duration,\n      delay: _getDelay(isSequential, delay),\n      begin: begin,\n      end: end,\n      onComplete: onComplete,\n      child: this,\n    );\n  }\n\n  GetAnimatedBuilder blur({\n    double begin = 0,\n    double end = 15,\n    Duration duration = _defaultDuration,\n    Duration delay = _defaultDelay,\n    ValueSetter<AnimationController>? onComplete,\n    bool isSequential = false,\n  }) {\n    return BlurAnimation(\n      duration: duration,\n      delay: _getDelay(isSequential, delay),\n      begin: begin,\n      end: end,\n      onComplete: onComplete,\n      child: this,\n    );\n  }\n\n  GetAnimatedBuilder flip({\n    double begin = 0,\n    double end = 1,\n    Duration duration = _defaultDuration,\n    Duration delay = _defaultDelay,\n    ValueSetter<AnimationController>? onComplete,\n    bool isSequential = false,\n  }) {\n    return FlipAnimation(\n      duration: duration,\n      delay: _getDelay(isSequential, delay),\n      begin: begin,\n      end: end,\n      onComplete: onComplete,\n      child: this,\n    );\n  }\n\n  GetAnimatedBuilder wave({\n    double begin = 0,\n    double end = 1,\n    Duration duration = _defaultDuration,\n    Duration delay = _defaultDelay,\n    ValueSetter<AnimationController>? onComplete,\n    bool isSequential = false,\n  }) {\n    return WaveAnimation(\n      duration: duration,\n      delay: _getDelay(isSequential, delay),\n      begin: begin,\n      end: end,\n      onComplete: onComplete,\n      child: this,\n    );\n  }\n\n  Duration _getDelay(bool isSequential, Duration delay) {\n    assert(!(isSequential && delay != Duration.zero),\n        \"Error: When isSequential is true, delay must be non-zero. Context: isSequential: $isSequential delay: $delay\");\n\n    return isSequential\n        ? (_currentAnimation?.totalDuration ?? Duration.zero)\n        : delay;\n  }\n}\n"
  },
  {
    "path": "lib/get_animations/get_animated_builder.dart",
    "content": "import 'package:flutter/material.dart';\n\nimport 'animations.dart';\n\nclass GetAnimatedBuilder<T> extends StatefulWidget {\n  final Duration duration;\n  final Duration delay;\n  final Widget child;\n  final ValueSetter<AnimationController>? onComplete;\n  final ValueSetter<AnimationController>? onStart;\n  final Tween<T> tween;\n  final T idleValue;\n  final ValueWidgetBuilder<T> builder;\n  final Curve curve;\n\n  Duration get totalDuration => duration + delay;\n\n  const GetAnimatedBuilder({\n    super.key,\n    this.curve = Curves.linear,\n    this.onComplete,\n    this.onStart,\n    required this.duration,\n    required this.tween,\n    required this.idleValue,\n    required this.builder,\n    required this.child,\n    required this.delay,\n  });\n  @override\n  GetAnimatedBuilderState<T> createState() => GetAnimatedBuilderState<T>();\n}\n\nclass GetAnimatedBuilderState<T> extends State<GetAnimatedBuilder<T>>\n    with SingleTickerProviderStateMixin {\n  late final AnimationController _controller;\n  late final Animation<T> _animation;\n\n  // AnimationController get controller => _controller;\n  // Animation<T> get animation => _animation;\n\n  bool _wasStarted = false;\n  // bool get wasStarted => _wasStarted;\n\n  late T _idleValue;\n\n  bool _willResetOnDispose = false;\n\n  bool get willResetOnDispose => _willResetOnDispose;\n\n  void _listener(AnimationStatus status) {\n    switch (status) {\n      case AnimationStatus.completed:\n        widget.onComplete?.call(_controller);\n        if (_willResetOnDispose) {\n          _controller.reset();\n        }\n        break;\n      // case AnimationStatus.dismissed:\n      case AnimationStatus.forward:\n        widget.onStart?.call(_controller);\n        break;\n      // case AnimationStatus.reverse:\n      default:\n        break;\n    }\n  }\n\n  @override\n  void initState() {\n    super.initState();\n\n    if (widget is OpacityAnimation) {\n      final current =\n          context.findRootAncestorStateOfType<GetAnimatedBuilderState>();\n      final isLast = current == null;\n\n      if (widget is FadeInAnimation) {\n        _idleValue = 1.0 as dynamic;\n      } else {\n        if (isLast) {\n          _willResetOnDispose = false;\n        } else {\n          _willResetOnDispose = true;\n        }\n        _idleValue = widget.idleValue;\n      }\n    } else {\n      _idleValue = widget.idleValue;\n    }\n\n    _controller = AnimationController(\n      vsync: this,\n      duration: widget.duration,\n    );\n\n    _controller.addStatusListener(_listener);\n\n    _animation = widget.tween.animate(\n      CurvedAnimation(\n        parent: _controller,\n        curve: widget.curve,\n      ),\n    );\n\n    Future.delayed(widget.delay, () {\n      if (mounted) {\n        setState(() {\n          _wasStarted = true;\n          _controller.forward();\n        });\n      }\n    });\n  }\n\n  @override\n  void dispose() {\n    _controller.removeStatusListener(_listener);\n    _controller.dispose();\n    super.dispose();\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return AnimatedBuilder(\n      animation: _animation,\n      builder: (context, child) {\n        final value = _wasStarted ? _animation.value : _idleValue;\n        return widget.builder(context, value, child);\n      },\n      child: widget.child,\n    );\n  }\n}\n"
  },
  {
    "path": "lib/get_animations/index.dart",
    "content": "export './animations.dart';\nexport './extensions.dart';\nexport './get_animated_builder.dart';\n"
  },
  {
    "path": "lib/get_common/get_reset.dart",
    "content": "import '../get.dart';\n\nextension GetResetExt on GetInterface {\n  void reset({bool clearRouteBindings = true}) {\n    Get.resetInstance(clearRouteBindings: clearRouteBindings);\n    // Get.clearRouteTree();\n    Get.clearTranslations();\n    // Get.resetRootNavigator();\n  }\n}\n"
  },
  {
    "path": "lib/get_connect/connect.dart",
    "content": "import '../get_instance/src/lifecycle.dart';\nimport 'http/src/certificates/certificates.dart';\nimport 'http/src/exceptions/exceptions.dart';\nimport 'http/src/http.dart';\nimport 'http/src/response/response.dart';\nimport 'sockets/sockets.dart';\n\nexport 'http/src/certificates/certificates.dart';\nexport 'http/src/http.dart';\nexport 'http/src/multipart/form_data.dart';\nexport 'http/src/multipart/multipart_file.dart';\nexport 'http/src/response/response.dart';\nexport 'sockets/sockets.dart';\n\nabstract class GetConnectInterface with GetLifeCycleMixin {\n  List<GetSocket>? sockets;\n  GetHttpClient get httpClient;\n\n  Future<Response<T>> get<T>(\n    String url, {\n    Map<String, String>? headers,\n    String? contentType,\n    Map<String, dynamic>? query,\n    Decoder<T>? decoder,\n  });\n\n  Future<Response<T>> request<T>(\n    String url,\n    String method, {\n    dynamic body,\n    String? contentType,\n    Map<String, String>? headers,\n    Map<String, dynamic>? query,\n    Decoder<T>? decoder,\n  });\n\n  Future<Response<T>> post<T>(\n    String url,\n    dynamic body, {\n    String? contentType,\n    Map<String, String>? headers,\n    Map<String, dynamic>? query,\n    Decoder<T>? decoder,\n  });\n\n  Future<Response<T>> put<T>(\n    String url,\n    dynamic body, {\n    String? contentType,\n    Map<String, String>? headers,\n    Map<String, dynamic>? query,\n    Decoder<T>? decoder,\n  });\n\n  Future<Response<T>> delete<T>(\n    String url, {\n    Map<String, String>? headers,\n    String? contentType,\n    Map<String, dynamic>? query,\n    Decoder<T>? decoder,\n  });\n\n  Future<Response<T>> patch<T>(\n    String url,\n    dynamic body, {\n    String? contentType,\n    Map<String, String>? headers,\n    Map<String, dynamic>? query,\n    Decoder<T>? decoder,\n    Progress? uploadProgress,\n  });\n\n  Future<GraphQLResponse<T>> query<T>(\n    String query, {\n    String? url,\n    Map<String, dynamic>? variables,\n    Map<String, String>? headers,\n  });\n\n  Future<GraphQLResponse<T>> mutation<T>(\n    String mutation, {\n    String? url,\n    Map<String, dynamic>? variables,\n    Map<String, String>? headers,\n  });\n\n  GetSocket socket(\n    String url, {\n    Duration ping = const Duration(seconds: 5),\n  });\n}\n\nclass GetConnect extends GetConnectInterface {\n  GetConnect({\n    this.userAgent = 'getx-client',\n    this.timeout = const Duration(seconds: 5),\n    this.followRedirects = true,\n    this.maxRedirects = 5,\n    this.sendUserAgent = false,\n    this.maxAuthRetries = 1,\n    this.allowAutoSignedCert = false,\n    this.withCredentials = false,\n  });\n\n  bool allowAutoSignedCert;\n  String userAgent;\n  bool sendUserAgent;\n  String? baseUrl;\n  String defaultContentType = 'application/json; charset=utf-8';\n  bool followRedirects;\n  int maxRedirects;\n  int maxAuthRetries;\n  Decoder? defaultDecoder;\n  Duration timeout;\n  List<TrustedCertificate>? trustedCertificates;\n  String Function(Uri url)? findProxy;\n  GetHttpClient? _httpClient;\n  List<GetSocket>? _sockets;\n  bool withCredentials;\n\n  @override\n  List<GetSocket> get sockets => _sockets ??= <GetSocket>[];\n\n  @override\n  GetHttpClient get httpClient => _httpClient ??= GetHttpClient(\n      userAgent: userAgent,\n      sendUserAgent: sendUserAgent,\n      timeout: timeout,\n      followRedirects: followRedirects,\n      maxRedirects: maxRedirects,\n      maxAuthRetries: maxAuthRetries,\n      allowAutoSignedCert: allowAutoSignedCert,\n      baseUrl: baseUrl,\n      trustedCertificates: trustedCertificates,\n      withCredentials: withCredentials,\n      findProxy: findProxy);\n\n  @override\n  Future<Response<T>> get<T>(\n    String url, {\n    Map<String, String>? headers,\n    String? contentType,\n    Map<String, dynamic>? query,\n    Decoder<T>? decoder,\n  }) {\n    _checkIfDisposed();\n    return httpClient.get<T>(\n      url,\n      headers: headers,\n      contentType: contentType,\n      query: query,\n      decoder: decoder,\n    );\n  }\n\n  @override\n  Future<Response<T>> post<T>(\n    String? url,\n    dynamic body, {\n    String? contentType,\n    Map<String, String>? headers,\n    Map<String, dynamic>? query,\n    Decoder<T>? decoder,\n    Progress? uploadProgress,\n  }) {\n    _checkIfDisposed();\n    return httpClient.post<T>(\n      url,\n      body: body,\n      headers: headers,\n      contentType: contentType,\n      query: query,\n      decoder: decoder,\n      uploadProgress: uploadProgress,\n    );\n  }\n\n  @override\n  Future<Response<T>> put<T>(\n    String url,\n    dynamic body, {\n    String? contentType,\n    Map<String, String>? headers,\n    Map<String, dynamic>? query,\n    Decoder<T>? decoder,\n    Progress? uploadProgress,\n  }) {\n    _checkIfDisposed();\n    return httpClient.put<T>(\n      url,\n      body: body,\n      headers: headers,\n      contentType: contentType,\n      query: query,\n      decoder: decoder,\n      uploadProgress: uploadProgress,\n    );\n  }\n\n  @override\n  Future<Response<T>> patch<T>(\n    String url,\n    dynamic body, {\n    String? contentType,\n    Map<String, String>? headers,\n    Map<String, dynamic>? query,\n    Decoder<T>? decoder,\n    Progress? uploadProgress,\n  }) {\n    _checkIfDisposed();\n    return httpClient.patch<T>(\n      url,\n      body: body,\n      headers: headers,\n      contentType: contentType,\n      query: query,\n      decoder: decoder,\n      uploadProgress: uploadProgress,\n    );\n  }\n\n  @override\n  Future<Response<T>> request<T>(\n    String url,\n    String method, {\n    dynamic body,\n    String? contentType,\n    Map<String, String>? headers,\n    Map<String, dynamic>? query,\n    Decoder<T>? decoder,\n    Progress? uploadProgress,\n  }) {\n    _checkIfDisposed();\n    return httpClient.request<T>(\n      url,\n      method,\n      body: body,\n      headers: headers,\n      contentType: contentType,\n      query: query,\n      decoder: decoder,\n      uploadProgress: uploadProgress,\n    );\n  }\n\n  @override\n  Future<Response<T>> delete<T>(\n    String url, {\n    Map<String, String>? headers,\n    String? contentType,\n    Map<String, dynamic>? query,\n    Decoder<T>? decoder,\n  }) {\n    _checkIfDisposed();\n    return httpClient.delete(\n      url,\n      headers: headers,\n      contentType: contentType,\n      query: query,\n      decoder: decoder,\n    );\n  }\n\n  @override\n  GetSocket socket(\n    String url, {\n    Duration ping = const Duration(seconds: 5),\n  }) {\n    _checkIfDisposed(isHttp: false);\n\n    final newSocket = GetSocket(_concatUrl(url)!, ping: ping);\n    sockets.add(newSocket);\n    return newSocket;\n  }\n\n  String? _concatUrl(String? url) {\n    if (url == null) return baseUrl;\n    return baseUrl == null ? url : baseUrl! + url;\n  }\n\n  /// query allow made GraphQL raw queries\n  /// final connect = GetConnect();\n  /// connect.baseUrl = 'https://countries.trevorblades.com/';\n  /// final response = await connect.query(\n  /// r\"\"\"\n  /// {\n  ///  country(code: \"BR\") {\n  ///    name\n  ///    native\n  ///    currency\n  ///    languages {\n  ///      code\n  ///      name\n  ///    }\n  ///  }\n  ///}\n  ///\"\"\",\n  ///);\n  ///print(response.body);\n  @override\n  Future<GraphQLResponse<T>> query<T>(\n    String query, {\n    String? url,\n    Map<String, dynamic>? variables,\n    Map<String, String>? headers,\n  }) async {\n    try {\n      final res = await post(\n        url,\n        {'query': query, 'variables': variables},\n        headers: headers,\n      );\n\n      final listError = res.body['errors'];\n      if ((listError is List) && listError.isNotEmpty) {\n        return GraphQLResponse<T>(\n            graphQLErrors: listError\n                .map((e) => GraphQLError(\n                      code: (e['extensions'] != null\n                              ? e['extensions']['code'] ?? ''\n                              : '')\n                          .toString(),\n                      message: (e['message'] ?? '').toString(),\n                    ))\n                .toList());\n      }\n      return GraphQLResponse<T>.fromResponse(res);\n    } on Exception catch (err) {\n      return GraphQLResponse<T>(graphQLErrors: [\n        GraphQLError(\n          code: null,\n          message: err.toString(),\n        )\n      ]);\n    }\n  }\n\n  @override\n  Future<GraphQLResponse<T>> mutation<T>(\n    String mutation, {\n    String? url,\n    Map<String, dynamic>? variables,\n    Map<String, String>? headers,\n  }) async {\n    try {\n      final res = await post(\n        url,\n        {'query': mutation, 'variables': variables},\n        headers: headers,\n      );\n\n      final listError = res.body['errors'];\n      if ((listError is List) && listError.isNotEmpty) {\n        return GraphQLResponse<T>(\n            graphQLErrors: listError\n                .map((e) => GraphQLError(\n                      code: e['extensions']['code']?.toString(),\n                      message: e['message']?.toString(),\n                    ))\n                .toList());\n      }\n      return GraphQLResponse<T>.fromResponse(res);\n    } on Exception catch (err) {\n      return GraphQLResponse<T>(graphQLErrors: [\n        GraphQLError(\n          code: null,\n          message: err.toString(),\n        )\n      ]);\n    }\n  }\n\n  bool _isDisposed = false;\n\n  bool get isDisposed => _isDisposed;\n\n  void _checkIfDisposed({bool isHttp = true}) {\n    if (_isDisposed) {\n      throw 'Can not emit events to disposed clients';\n    }\n  }\n\n  void dispose() {\n    if (_sockets != null) {\n      for (var socket in sockets) {\n        socket.close();\n      }\n      _sockets?.clear();\n      sockets = null;\n    }\n    if (_httpClient != null) {\n      httpClient.close();\n      _httpClient = null;\n    }\n    _isDisposed = true;\n  }\n}\n"
  },
  {
    "path": "lib/get_connect/http/src/certificates/certificates.dart",
    "content": "class TrustedCertificate {\n  final List<int> bytes;\n\n  const TrustedCertificate(this.bytes);\n}\n"
  },
  {
    "path": "lib/get_connect/http/src/exceptions/exceptions.dart",
    "content": "class GetHttpException implements Exception {\n  final String message;\n\n  final Uri? uri;\n\n  GetHttpException(this.message, [this.uri]);\n\n  @override\n  String toString() => message;\n}\n\nclass GraphQLError {\n  GraphQLError({this.code, this.message});\n  final String? message;\n  final String? code;\n\n  @override\n  String toString() => 'GETCONNECT ERROR:\\n\\tcode:$code\\n\\tmessage:$message';\n}\n\nclass UnauthorizedException implements Exception {\n  @override\n  String toString() {\n    return 'Operation Unauthorized';\n  }\n}\n\nclass UnexpectedFormat implements Exception {\n  final String message;\n  UnexpectedFormat(this.message);\n  @override\n  String toString() {\n    return 'Unexpected format: $message';\n  }\n}\n"
  },
  {
    "path": "lib/get_connect/http/src/http/html/file_decoder_html.dart",
    "content": "// import 'dart:html' as html;\n\nList<int> fileToBytes(dynamic data) {\n  if (data is List<int>) {\n    return data;\n  } else {\n    throw const FormatException(\n        'File is not \"File\" or \"String\" or \"List<int>\"');\n  }\n}\n\n// void writeOnFile(List<int> bytes) {\n//   var blob = html.Blob([\"data\"], 'text/plain', 'native');\n//   var anchorElement = html.AnchorElement(\n//     href: html.Url.createObjectUrlFromBlob(blob).toString(),\n//   )\n//     ..setAttribute(\"download\", \"data.txt\")\n//     ..click();\n// }\n"
  },
  {
    "path": "lib/get_connect/http/src/http/html/http_request_html.dart",
    "content": "import 'dart:async';\nimport 'dart:js_interop';\n\nimport 'package:web/web.dart' show XHRGetters, XMLHttpRequest;\n\nimport '../../certificates/certificates.dart';\nimport '../../exceptions/exceptions.dart';\nimport '../../request/request.dart';\nimport '../../response/response.dart';\nimport '../interface/request_base.dart';\nimport '../utils/body_decoder.dart';\n\nclass HttpRequestImpl implements IClient {\n  HttpRequestImpl({\n    bool allowAutoSignedCert = true,\n    List<TrustedCertificate>? trustedCertificates,\n    this.withCredentials = false,\n    String Function(Uri url)? findProxy,\n  });\n\n  final _xhrs = <XMLHttpRequest>{};\n  final bool withCredentials;\n\n  @override\n  Future<Response<T>> send<T>(Request<T> request) async {\n    if (_isClosed) {\n      throw GetHttpException(\n          'HTTP request failed. Client is already closed.', request.url);\n    }\n\n    var bytes = await request.bodyBytes.toBytes();\n    XMLHttpRequest xhr = XMLHttpRequest();\n\n    xhr\n      ..timeout = (timeout ?? Duration.zero).inMilliseconds\n      ..open(request.method, '${request.url}', true);\n\n    _xhrs.add(xhr);\n\n    xhr\n      ..responseType = 'arraybuffer' // Changed from 'blob' to 'arraybuffer'\n      ..withCredentials = withCredentials;\n\n    request.headers.forEach((key, value) => xhr.setRequestHeader(key, value));\n\n    var completer = Completer<Response<T>>();\n\n    unawaited(xhr.onLoad.first.then((_) async {\n      final bodyBytes =\n          (xhr.response as JSArrayBuffer).toDart.asUint8List().toStream();\n\n      if (request.responseInterceptor != null) {\n        throw GetHttpException(\n            'Response interception not implemented for web yet!', request.url);\n      }\n\n      final stringBody =\n          await bodyBytesToString(bodyBytes, xhr.responseHeaders);\n      final contentType =\n          xhr.responseHeaders['content-type'] ?? 'application/json';\n\n      final body = bodyDecoded<T>(request, stringBody, contentType);\n\n      final response = Response<T>(\n        bodyBytes: bodyBytes,\n        statusCode: xhr.status,\n        request: request,\n        headers: xhr.responseHeaders,\n        statusText: xhr.statusText,\n        body: body,\n        bodyString: stringBody,\n      );\n\n      completer.complete(response);\n    }));\n\n    unawaited(xhr.onError.first.then((_) {\n      completer.completeError(\n        GetHttpException('XMLHttpRequest error.', request.url),\n        StackTrace.current,\n      );\n    }));\n\n    xhr.send(bytes.toJS);\n\n    try {\n      return await completer.future;\n    } finally {\n      _xhrs.remove(xhr);\n    }\n  }\n\n  @override\n  void close() {\n    _isClosed = true;\n    for (var xhr in _xhrs) {\n      xhr.abort();\n    }\n    _xhrs.clear();\n  }\n\n  @override\n  Duration? timeout;\n  bool _isClosed = false;\n}\n\nextension on XMLHttpRequest {\n  Map<String, String> get responseHeaders {\n    var headers = <String, String>{};\n    var headersString = getAllResponseHeaders();\n    var headersList = headersString.split('\\r\\n');\n    for (var header in headersList) {\n      if (header.isEmpty) continue;\n\n      var splitIdx = header.indexOf(': ');\n      if (splitIdx == -1) continue;\n\n      var key = header.substring(0, splitIdx).toLowerCase();\n      var value = header.substring(splitIdx + 2);\n      if (headers.containsKey(key)) {\n        headers[key] = '${headers[key]}, $value';\n      } else {\n        headers[key] = value;\n      }\n    }\n    return headers;\n  }\n}\n"
  },
  {
    "path": "lib/get_connect/http/src/http/interface/request_base.dart",
    "content": "import '../../request/request.dart';\nimport '../../response/response.dart';\n\n/// Abstract interface of [HttpRequestImpl].\nabstract class IClient {\n  /// Sends an HTTP [Request].\n  Future<Response<T>> send<T>(Request<T> request);\n\n  /// Closes the [Request] and cleans up any resources associated with it.\n  void close();\n\n  /// Gets and sets the timeout.\n  ///\n  /// For mobile, this value will be applied for both connection and request\n  /// timeout.\n  ///\n  /// For web, this value will be the request timeout.\n  Duration? timeout;\n}\n"
  },
  {
    "path": "lib/get_connect/http/src/http/io/file_decoder_io.dart",
    "content": "import 'dart:io';\n\nList<int> fileToBytes(dynamic data) {\n  if (data is File) {\n    return data.readAsBytesSync();\n  } else if (data is String) {\n    if (File(data).existsSync()) {\n      return File(data).readAsBytesSync();\n    } else {\n      throw 'File $data not exists';\n    }\n  } else if (data is List<int>) {\n    return data;\n  } else {\n    throw const FormatException(\n        'File is not \"File\" or \"String\" or \"List<int>\"');\n  }\n}\n\nvoid writeOnFile(List<int> bytes) {}\n"
  },
  {
    "path": "lib/get_connect/http/src/http/io/http_request_io.dart",
    "content": "import 'dart:async';\nimport 'dart:io' as io;\n\nimport '../../certificates/certificates.dart';\nimport '../../exceptions/exceptions.dart';\nimport '../../request/request.dart';\nimport '../../response/client_response.dart';\nimport '../../response/response.dart';\nimport '../interface/request_base.dart';\nimport '../utils/body_decoder.dart';\n\nclass IoRedirectInfo implements RedirectInfo {\n  final io.RedirectInfo _redirectInfo;\n  IoRedirectInfo({required io.RedirectInfo redirectInfo})\n      : _redirectInfo = redirectInfo;\n\n  @override\n  int get statusCode => _redirectInfo.statusCode;\n\n  @override\n  String get method => _redirectInfo.method;\n\n  @override\n  Uri get location => _redirectInfo.location;\n}\n\nclass IoHttpHeaders implements HttpHeaders {\n  final io.HttpHeaders _headers;\n  IoHttpHeaders({required io.HttpHeaders headers}) : _headers = headers;\n\n  @override\n  bool get chunkedTransferEncoding => _headers.chunkedTransferEncoding;\n\n  @override\n  int get contentLength => _headers.contentLength;\n\n  @override\n  DateTime? get date => _headers.date;\n\n  @override\n  DateTime? get expires => _headers.expires;\n\n  @override\n  String? get host => _headers.host;\n\n  @override\n  DateTime? get ifModifiedSince => _headers.ifModifiedSince;\n\n  @override\n  bool get persistentConnection => _headers.persistentConnection;\n\n  @override\n  int? get port => _headers.port;\n\n  @override\n  List<String>? operator [](String name) {\n    return _headers[name];\n  }\n\n  @override\n  void add(String name, Object value, {bool preserveHeaderCase = false}) {\n    _headers.add(name, value, preserveHeaderCase: preserveHeaderCase);\n  }\n\n  @override\n  void clear() {\n    _headers.clear();\n  }\n\n  @override\n  void forEach(void Function(String name, List<String> values) action) {\n    _headers.forEach(action);\n  }\n\n  @override\n  void noFolding(String name) {\n    _headers.noFolding(name);\n  }\n\n  @override\n  void remove(String name, Object value) {\n    _headers.remove(name, value);\n  }\n\n  @override\n  void removeAll(String name) {\n    _headers.removeAll(name);\n  }\n\n  @override\n  void set(String name, Object value, {bool preserveHeaderCase = false}) {\n    _headers.set(name, value, preserveHeaderCase: preserveHeaderCase);\n  }\n\n  @override\n  String? value(String name) {\n    return _headers.value(name);\n  }\n\n  @override\n  set chunkedTransferEncoding(bool chunkedTransferEncoding) {\n    _headers.chunkedTransferEncoding = chunkedTransferEncoding;\n  }\n\n  @override\n  set contentLength(int contentLength) {\n    _headers.contentLength = contentLength;\n  }\n\n  @override\n  set date(DateTime? date) {\n    _headers.date = date;\n  }\n\n  @override\n  set expires(DateTime? expires) {\n    _headers.expires = expires;\n  }\n\n  @override\n  set host(String? host) {\n    _headers.host = host;\n  }\n\n  @override\n  set ifModifiedSince(DateTime? ifModifiedSince) {\n    _headers.ifModifiedSince = ifModifiedSince;\n  }\n\n  @override\n  set persistentConnection(bool persistentConnection) {\n    _headers.persistentConnection = persistentConnection;\n  }\n\n  @override\n  set port(int? port) {\n    _headers.port = port;\n  }\n}\n\nclass IOHttpResponse implements HttpClientResponse {\n  IOHttpResponse({required io.HttpClientResponse response})\n      : _response = response;\n  final io.HttpClientResponse _response;\n  @override\n  Future<bool> any(bool Function(List<int> element) test) {\n    return _response.any(test);\n  }\n\n  @override\n  Stream<List<int>> asBroadcastStream(\n      {void Function(StreamSubscription<List<int>> subscription)? onListen,\n      void Function(StreamSubscription<List<int>> subscription)? onCancel}) {\n    return _response.asBroadcastStream(onListen: onListen, onCancel: onCancel);\n  }\n\n  @override\n  Stream<E> asyncExpand<E>(Stream<E>? Function(List<int> event) convert) {\n    return _response.asyncExpand(convert);\n  }\n\n  @override\n  Stream<E> asyncMap<E>(FutureOr<E> Function(List<int> event) convert) {\n    return _response.asyncMap(convert);\n  }\n\n  @override\n  Stream<R> cast<R>() {\n    return _response.cast<R>();\n  }\n\n  @override\n  Future<bool> contains(Object? needle) {\n    return _response.contains(needle);\n  }\n\n  @override\n  int get contentLength => _response.contentLength;\n\n  @override\n  Stream<List<int>> distinct(\n      [bool Function(List<int> previous, List<int> next)? equals]) {\n    return _response.distinct(equals);\n  }\n\n  @override\n  Future<E> drain<E>([E? futureValue]) {\n    return _response.drain(futureValue);\n  }\n\n  @override\n  Future<List<int>> elementAt(int index) {\n    return _response.elementAt(index);\n  }\n\n  @override\n  Future<bool> every(bool Function(List<int> element) test) {\n    return _response.every(test);\n  }\n\n  @override\n  Stream<S> expand<S>(Iterable<S> Function(List<int> element) convert) {\n    return _response.expand(convert);\n  }\n\n  @override\n  Future<List<int>> get first => _response.first;\n\n  @override\n  Future<List<int>> firstWhere(bool Function(List<int> element) test,\n      {List<int> Function()? orElse}) {\n    return _response.firstWhere(test, orElse: orElse);\n  }\n\n  @override\n  Future<S> fold<S>(\n      S initialValue, S Function(S previous, List<int> element) combine) {\n    return _response.fold(initialValue, combine);\n  }\n\n  @override\n  Future<void> forEach(void Function(List<int> element) action) {\n    return _response.forEach(action);\n  }\n\n  @override\n  Stream<List<int>> handleError(Function onError,\n      {bool Function(dynamic error)? test}) {\n    return _response.handleError(onError, test: test);\n  }\n\n  @override\n  HttpHeaders get headers => IoHttpHeaders(headers: _response.headers);\n\n  @override\n  bool get isBroadcast => _response.isBroadcast;\n\n  @override\n  Future<bool> get isEmpty => _response.isEmpty;\n\n  @override\n  bool get isRedirect => _response.isRedirect;\n\n  @override\n  Future<String> join([String separator = \"\"]) {\n    return _response.join(separator);\n  }\n\n  @override\n  Future<List<int>> get last => _response.last;\n\n  @override\n  Future<List<int>> lastWhere(bool Function(List<int> element) test,\n      {List<int> Function()? orElse}) {\n    return _response.lastWhere(test, orElse: orElse);\n  }\n\n  @override\n  Future<int> get length => _response.length;\n\n  @override\n  StreamSubscription<List<int>> listen(void Function(List<int> event)? onData,\n      {Function? onError, void Function()? onDone, bool? cancelOnError}) {\n    return _response.listen(onData,\n        onError: onError, onDone: onDone, cancelOnError: cancelOnError);\n  }\n\n  @override\n  Stream<S> map<S>(S Function(List<int> event) convert) {\n    return _response.map(convert);\n  }\n\n  @override\n  bool get persistentConnection => _response.persistentConnection;\n\n  @override\n  Future pipe(StreamConsumer<List<int>> streamConsumer) {\n    return _response.pipe(streamConsumer);\n  }\n\n  @override\n  String get reasonPhrase => _response.reasonPhrase;\n\n  @override\n  Future<HttpClientResponse> redirect(\n      [String? method, Uri? url, bool? followLoops]) async {\n    final data = await _response.redirect(method, url, followLoops);\n    return IOHttpResponse(response: data);\n  }\n\n  @override\n  List<RedirectInfo> get redirects => _response.redirects\n      .map((item) => IoRedirectInfo(redirectInfo: item))\n      .toList();\n\n  @override\n  Future<List<int>> reduce(\n      List<int> Function(List<int> previous, List<int> element) combine) {\n    return _response.reduce(combine);\n  }\n\n  @override\n  Future<List<int>> get single => _response.single;\n\n  @override\n  Future<List<int>> singleWhere(bool Function(List<int> element) test,\n      {List<int> Function()? orElse}) {\n    return _response.singleWhere(test, orElse: orElse);\n  }\n\n  @override\n  Stream<List<int>> skip(int count) {\n    return _response.skip(count);\n  }\n\n  @override\n  Stream<List<int>> skipWhile(bool Function(List<int> element) test) {\n    return _response.skipWhile(test);\n  }\n\n  @override\n  int get statusCode => _response.statusCode;\n\n  @override\n  Stream<List<int>> take(int count) {\n    return _response.take(count);\n  }\n\n  @override\n  Stream<List<int>> takeWhile(bool Function(List<int> element) test) {\n    return _response.takeWhile(test);\n  }\n\n  @override\n  Stream<List<int>> timeout(Duration timeLimit,\n      {void Function(EventSink<List<int>> sink)? onTimeout}) {\n    return _response.timeout(timeLimit, onTimeout: onTimeout);\n  }\n\n  @override\n  Future<List<List<int>>> toList() {\n    return _response.toList();\n  }\n\n  @override\n  Future<Set<List<int>>> toSet() {\n    return _response.toSet();\n  }\n\n  @override\n  Stream<S> transform<S>(StreamTransformer<List<int>, S> streamTransformer) {\n    return _response.transform(streamTransformer);\n  }\n\n  @override\n  Stream<List<int>> where(bool Function(List<int> event) test) {\n    return _response.where(test);\n  }\n}\n\n/// A `dart:io` implementation of `IClient`.\nclass HttpRequestImpl extends IClient {\n  io.HttpClient? _httpClient;\n  io.SecurityContext? _securityContext;\n\n  HttpRequestImpl({\n    bool allowAutoSignedCert = true,\n    List<TrustedCertificate>? trustedCertificates,\n    bool withCredentials = false,\n    String Function(Uri url)? findProxy,\n  }) {\n    _httpClient = io.HttpClient();\n    if (trustedCertificates != null) {\n      _securityContext = io.SecurityContext();\n      for (final trustedCertificate in trustedCertificates) {\n        _securityContext!\n            .setTrustedCertificatesBytes(List.from(trustedCertificate.bytes));\n      }\n    }\n\n    _httpClient = io.HttpClient(context: _securityContext);\n    _httpClient!.badCertificateCallback = (_, __, ___) => allowAutoSignedCert;\n    _httpClient!.findProxy = findProxy;\n  }\n\n  @override\n  Future<Response<T>> send<T>(Request<T> request) async {\n    var stream = request.bodyBytes.asBroadcastStream();\n    io.HttpClientRequest? ioRequest;\n    try {\n      _httpClient!.connectionTimeout = timeout;\n      ioRequest = (await _httpClient!.openUrl(request.method, request.url))\n        ..followRedirects = request.followRedirects\n        ..persistentConnection = request.persistentConnection\n        ..maxRedirects = request.maxRedirects\n        ..contentLength = request.contentLength ?? -1;\n      request.headers.forEach(ioRequest.headers.set);\n\n      var response = timeout == null\n          ? await stream.pipe(ioRequest) as io.HttpClientResponse\n          : await stream.pipe(ioRequest).timeout(timeout!)\n              as io.HttpClientResponse;\n\n      var headers = <String, String>{};\n      response.headers.forEach((key, values) {\n        headers[key] = values.join(',');\n      });\n\n      final bodyBytes = (response);\n\n      final interceptionResponse = await request.responseInterceptor\n          ?.call(request, T, IOHttpResponse(response: response));\n      if (interceptionResponse != null) return interceptionResponse;\n\n      final stringBody = await bodyBytesToString(bodyBytes, headers);\n\n      final body = bodyDecoded<T>(\n        request,\n        stringBody,\n        response.headers.contentType?.mimeType,\n      );\n\n      return Response(\n        headers: headers,\n        request: request,\n        statusCode: response.statusCode,\n        statusText: response.reasonPhrase,\n        bodyBytes: bodyBytes,\n        body: body,\n        bodyString: stringBody,\n      );\n    } on TimeoutException catch (_) {\n      ioRequest?.abort();\n      rethrow;\n    } on io.HttpException catch (error) {\n      throw GetHttpException(error.message, error.uri);\n    }\n  }\n\n  /// Closes the HttpClient.\n  @override\n  void close() {\n    if (_httpClient != null) {\n      _httpClient!.close(force: true);\n      _httpClient = null;\n    }\n  }\n}\n\n// extension FileExt on io.FileSystemEntity {\n//   String get fileName {\n//     return this?.path?.split(io.Platform.pathSeparator)?.last;\n//   }\n// }\n"
  },
  {
    "path": "lib/get_connect/http/src/http/mock/http_request_mock.dart",
    "content": "import '../../request/request.dart';\nimport '../../response/response.dart';\nimport '../interface/request_base.dart';\nimport '../utils/body_decoder.dart';\n\ntypedef MockClientHandler = Future<Response> Function(Request request);\n\nclass MockClient extends IClient {\n  /// The handler for than transforms request on response\n  final MockClientHandler _handler;\n\n  /// Creates a [MockClient] with a handler that receives [Request]s and sends\n  /// [Response]s.\n  MockClient(this._handler);\n\n  @override\n  Future<Response<T>> send<T>(Request<T> request) async {\n    var requestBody = await request.bodyBytes.toBytes();\n    var bodyBytes = requestBody.toStream();\n\n    var response = await _handler(request);\n\n    final stringBody = await bodyBytesToString(bodyBytes, response.headers!);\n\n    var mimeType = response.headers!.containsKey('content-type')\n        ? response.headers!['content-type']\n        : '';\n\n    final body = bodyDecoded<T>(\n      request,\n      stringBody,\n      mimeType,\n    );\n    return Response(\n      headers: response.headers,\n      request: request,\n      statusCode: response.statusCode,\n      statusText: response.statusText,\n      bodyBytes: bodyBytes,\n      body: body,\n      bodyString: stringBody,\n    );\n  }\n\n  @override\n  void close() {}\n}\n"
  },
  {
    "path": "lib/get_connect/http/src/http/request/http_request.dart",
    "content": "import '../../certificates/certificates.dart';\nimport '../stub/http_request_stub.dart'\n    if (dart.library.js_interop) '../html/http_request_html.dart'\n    if (dart.library.io) '../io/http_request_io.dart';\n\nHttpRequestImpl createHttp({\n  bool allowAutoSignedCert = true,\n  List<TrustedCertificate>? trustedCertificates,\n  bool withCredentials = false,\n  String Function(Uri url)? findProxy,\n}) {\n  return HttpRequestImpl(\n    allowAutoSignedCert: allowAutoSignedCert,\n    trustedCertificates: trustedCertificates,\n    withCredentials: withCredentials,\n    findProxy: findProxy,\n  );\n}\n"
  },
  {
    "path": "lib/get_connect/http/src/http/stub/file_decoder_stub.dart",
    "content": "void writeOnFile(List<int> bytes) {}\n\nList<int> fileToBytes(dynamic data) {\n  throw UnimplementedError();\n}\n"
  },
  {
    "path": "lib/get_connect/http/src/http/stub/http_request_stub.dart",
    "content": "import '../../certificates/certificates.dart';\nimport '../../request/request.dart';\nimport '../../response/response.dart';\nimport '../interface/request_base.dart';\n\nclass HttpRequestImpl extends IClient {\n  HttpRequestImpl({\n    bool allowAutoSignedCert = true,\n    List<TrustedCertificate>? trustedCertificates,\n    bool withCredentials = false,\n    String Function(Uri url)? findProxy,\n  });\n  @override\n  void close() {}\n\n  @override\n  Future<Response<T>> send<T>(Request<T> request) {\n    throw UnimplementedError();\n  }\n}\n"
  },
  {
    "path": "lib/get_connect/http/src/http/utils/body_decoder.dart",
    "content": "import 'dart:convert';\n\nimport '../../../../../get_core/get_core.dart';\nimport '../../request/request.dart';\n\nT? bodyDecoded<T>(Request<T> request, String stringBody, String? mimeType) {\n  T? body;\n  dynamic bodyToDecode;\n\n  if (mimeType != null && mimeType.contains('application/json')) {\n    try {\n      bodyToDecode = jsonDecode(stringBody);\n    } on FormatException catch (_) {\n      Get.log('Cannot decode server response to json');\n      bodyToDecode = stringBody;\n    }\n  } else {\n    bodyToDecode = stringBody;\n  }\n\n  try {\n    if (stringBody == '') {\n      body = null;\n    } else if (request.decoder == null) {\n      body = bodyToDecode as T?;\n    } else {\n      body = request.decoder!(bodyToDecode);\n    }\n  } on Exception catch (_) {\n    body = stringBody as T;\n  }\n\n  return body;\n}\n"
  },
  {
    "path": "lib/get_connect/http/src/http.dart",
    "content": "import 'dart:async';\nimport 'dart:convert';\n\nimport '../src/certificates/certificates.dart';\nimport '../src/exceptions/exceptions.dart';\nimport '../src/multipart/form_data.dart';\nimport '../src/request/request.dart';\nimport '../src/response/response.dart';\nimport '../src/status/http_status.dart';\nimport 'http/interface/request_base.dart';\nimport 'http/request/http_request.dart';\nimport 'interceptors/get_modifiers.dart';\nimport 'response/client_response.dart';\n\ntypedef Decoder<T> = T Function(dynamic data);\n\ntypedef Progress = Function(double percent);\n\ntypedef ResponseInterceptor<T> = Future<Response<T>?> Function(\n    Request<T> request, Type targetType, HttpClientResponse response);\n\nclass GetHttpClient {\n  String userAgent;\n  String? baseUrl;\n\n  String defaultContentType = 'application/json; charset=utf-8';\n\n  bool followRedirects;\n  int maxRedirects;\n  int maxAuthRetries;\n\n  bool sendUserAgent;\n  bool sendContentLength;\n\n  Decoder? defaultDecoder;\n  ResponseInterceptor? defaultResponseInterceptor;\n\n  Duration timeout;\n\n  bool errorSafety = true;\n\n  final IClient _httpClient;\n\n  final GetModifier _modifier;\n\n  String Function(Uri url)? findProxy;\n\n  GetHttpClient({\n    this.userAgent = 'getx-client',\n    this.timeout = const Duration(seconds: 8),\n    this.followRedirects = true,\n    this.maxRedirects = 5,\n    this.sendUserAgent = false,\n    this.sendContentLength = true,\n    this.maxAuthRetries = 1,\n    bool allowAutoSignedCert = false,\n    this.baseUrl,\n    List<TrustedCertificate>? trustedCertificates,\n    bool withCredentials = false,\n    String Function(Uri url)? findProxy,\n    IClient? customClient,\n  })  : _httpClient = customClient ??\n            createHttp(\n              allowAutoSignedCert: allowAutoSignedCert,\n              trustedCertificates: trustedCertificates,\n              withCredentials: withCredentials,\n              findProxy: findProxy,\n            ),\n        _modifier = GetModifier();\n\n  void addAuthenticator<T>(RequestModifier<T> auth) {\n    _modifier.authenticator = auth as RequestModifier;\n  }\n\n  void addRequestModifier<T>(RequestModifier<T> interceptor) {\n    _modifier.addRequestModifier<T>(interceptor);\n  }\n\n  void removeRequestModifier<T>(RequestModifier<T> interceptor) {\n    _modifier.removeRequestModifier(interceptor);\n  }\n\n  void addResponseModifier<T>(ResponseModifier<T> interceptor) {\n    _modifier.addResponseModifier(interceptor);\n  }\n\n  void removeResponseModifier<T>(ResponseModifier<T> interceptor) {\n    _modifier.removeResponseModifier<T>(interceptor);\n  }\n\n  Uri createUri(String? url, Map<String, dynamic>? query) {\n    if (baseUrl != null) {\n      url = baseUrl! + url!;\n    }\n    final uri = Uri.parse(url!);\n    if (query != null) {\n      return uri.replace(queryParameters: query);\n    }\n    return uri;\n  }\n\n  Future<Request<T>> _requestWithBody<T>(\n    String? url,\n    String? contentType,\n    dynamic body,\n    String method,\n    Map<String, dynamic>? query,\n    Decoder<T>? decoder,\n    ResponseInterceptor<T>? responseInterceptor,\n    Progress? uploadProgress,\n  ) async {\n    List<int>? bodyBytes;\n    Stream<List<int>>? bodyStream;\n    final headers = <String, String>{};\n\n    if (sendUserAgent) {\n      headers['user-agent'] = userAgent;\n    }\n\n    if (body is FormData) {\n      bodyBytes = await body.toBytes();\n      headers['content-length'] = bodyBytes.length.toString();\n      headers['content-type'] =\n          'multipart/form-data; boundary=${body.boundary}';\n    } else if (contentType != null &&\n        contentType.toLowerCase() == 'application/x-www-form-urlencoded' &&\n        body is Map) {\n      var parts = [];\n      (body as Map<String, dynamic>).forEach((key, value) {\n        parts.add('${Uri.encodeQueryComponent(key)}='\n            '${Uri.encodeQueryComponent(value.toString())}');\n      });\n      var formData = parts.join('&');\n      bodyBytes = utf8.encode(formData);\n      _setContentLength(headers, bodyBytes.length);\n      headers['content-type'] = contentType;\n    } else if (body is Map || body is List) {\n      var jsonString = json.encode(body);\n      bodyBytes = utf8.encode(jsonString);\n      _setContentLength(headers, bodyBytes.length);\n      headers['content-type'] = contentType ?? defaultContentType;\n    } else if (body is String) {\n      bodyBytes = utf8.encode(body);\n      _setContentLength(headers, bodyBytes.length);\n\n      headers['content-type'] = contentType ?? defaultContentType;\n    } else if (body == null) {\n      _setContentLength(headers, 0);\n      headers['content-type'] = contentType ?? defaultContentType;\n    } else {\n      if (!errorSafety) {\n        throw UnexpectedFormat('body cannot be ${body.runtimeType}');\n      }\n    }\n\n    if (bodyBytes != null) {\n      bodyStream = _trackProgress(bodyBytes, uploadProgress);\n    }\n\n    final uri = createUri(url, query);\n    return Request<T>(\n        method: method,\n        url: uri,\n        headers: headers,\n        bodyBytes: bodyStream,\n        contentLength: bodyBytes?.length ?? 0,\n        followRedirects: followRedirects,\n        maxRedirects: maxRedirects,\n        decoder: decoder,\n        responseInterceptor: responseInterceptor);\n  }\n\n  void _setContentLength(Map<String, String> headers, int contentLength) {\n    if (sendContentLength) {\n      headers['content-length'] = '$contentLength';\n    }\n  }\n\n  Stream<List<int>> _trackProgress(\n    List<int> bodyBytes,\n    Progress? uploadProgress,\n  ) {\n    var total = 0;\n    var length = bodyBytes.length;\n\n    var byteStream =\n        Stream.fromIterable(bodyBytes.map((i) => [i])).transform<List<int>>(\n      StreamTransformer.fromHandlers(handleData: (data, sink) {\n        total += data.length;\n        if (uploadProgress != null) {\n          var percent = total / length * 100;\n          uploadProgress(percent);\n        }\n        sink.add(data);\n      }),\n    );\n    return byteStream;\n  }\n\n  void _setSimpleHeaders(\n    Map<String, String> headers,\n    String? contentType,\n  ) {\n    headers['content-type'] = contentType ?? defaultContentType;\n    if (sendUserAgent) {\n      headers['user-agent'] = userAgent;\n    }\n  }\n\n  Future<Response<T>> _performRequest<T>(\n    HandlerExecute<T> handler, {\n    bool authenticate = false,\n    int requestNumber = 1,\n    Map<String, String>? headers,\n  }) async {\n    var request = await handler();\n\n    headers?.forEach((key, value) {\n      request.headers[key] = value;\n    });\n\n    if (authenticate) await _modifier.authenticator!(request);\n    final newRequest = await _modifier.modifyRequest<T>(request);\n\n    _httpClient.timeout = timeout;\n    try {\n      var response = await _httpClient.send<T>(newRequest);\n\n      final newResponse =\n          await _modifier.modifyResponse<T>(newRequest, response);\n\n      if (HttpStatus.unauthorized == newResponse.statusCode &&\n          _modifier.authenticator != null &&\n          requestNumber <= maxAuthRetries) {\n        return _performRequest<T>(\n          handler,\n          authenticate: true,\n          requestNumber: requestNumber + 1,\n          headers: newRequest.headers,\n        );\n      } else if (HttpStatus.unauthorized == newResponse.statusCode) {\n        if (!errorSafety) {\n          throw UnauthorizedException();\n        } else {\n          return Response<T>(\n            request: newRequest,\n            headers: newResponse.headers,\n            statusCode: newResponse.statusCode,\n            body: newResponse.body,\n            bodyBytes: newResponse.bodyBytes,\n            bodyString: newResponse.bodyString,\n            statusText: newResponse.statusText,\n          );\n        }\n      }\n\n      return newResponse;\n    } on Exception catch (err) {\n      if (!errorSafety) {\n        throw GetHttpException(err.toString());\n      } else {\n        return Response<T>(\n          request: newRequest,\n          headers: null,\n          statusCode: null,\n          body: null,\n          statusText: \"$err\",\n        );\n      }\n    }\n  }\n\n  Future<Request<T>> _get<T>(\n    String url,\n    String? contentType,\n    Map<String, dynamic>? query,\n    Decoder<T>? decoder,\n    ResponseInterceptor<T>? responseInterceptor,\n  ) {\n    final headers = <String, String>{};\n    _setSimpleHeaders(headers, contentType);\n    final uri = createUri(url, query);\n\n    return Future.value(Request<T>(\n      method: 'get',\n      url: uri,\n      headers: headers,\n      decoder: decoder ?? (defaultDecoder as Decoder<T>?),\n      responseInterceptor: _responseInterceptor(responseInterceptor),\n      contentLength: 0,\n      followRedirects: followRedirects,\n      maxRedirects: maxRedirects,\n    ));\n  }\n\n  ResponseInterceptor<T>? _responseInterceptor<T>(\n      ResponseInterceptor<T>? actual) {\n    if (actual != null) return actual;\n    final defaultInterceptor = defaultResponseInterceptor;\n    return defaultInterceptor != null\n        ? (request, targetType, response) async =>\n            await defaultInterceptor(request, targetType, response)\n                as Response<T>?\n        : null;\n  }\n\n  Future<Request<T>> _request<T>(\n    String? url,\n    String method, {\n    String? contentType,\n    required dynamic body,\n    required Map<String, dynamic>? query,\n    Decoder<T>? decoder,\n    ResponseInterceptor<T>? responseInterceptor,\n    required Progress? uploadProgress,\n  }) {\n    return _requestWithBody<T>(\n      url,\n      contentType,\n      body,\n      method,\n      query,\n      decoder ?? (defaultDecoder as Decoder<T>?),\n      _responseInterceptor(responseInterceptor),\n      uploadProgress,\n    );\n  }\n\n  Request<T> _delete<T>(\n    String url,\n    String? contentType,\n    Map<String, dynamic>? query,\n    Decoder<T>? decoder,\n    ResponseInterceptor<T>? responseInterceptor,\n  ) {\n    final headers = <String, String>{};\n    _setSimpleHeaders(headers, contentType);\n    final uri = createUri(url, query);\n\n    return Request<T>(\n      method: 'delete',\n      url: uri,\n      headers: headers,\n      decoder: decoder ?? (defaultDecoder as Decoder<T>?),\n      responseInterceptor: _responseInterceptor(responseInterceptor),\n    );\n  }\n\n  Future<Response<T>> send<T>(Request<T> request) async {\n    try {\n      var response = await _performRequest<T>(() => Future.value(request));\n      return response;\n    } on Exception catch (e) {\n      if (!errorSafety) {\n        throw GetHttpException(e.toString());\n      }\n      return Future.value(Response<T>(\n        statusText: 'Can not connect to server. Reason: $e',\n      ));\n    }\n  }\n\n  Future<Response<T>> patch<T>(\n    String url, {\n    dynamic body,\n    String? contentType,\n    Map<String, String>? headers,\n    Map<String, dynamic>? query,\n    Decoder<T>? decoder,\n    ResponseInterceptor<T>? responseInterceptor,\n    Progress? uploadProgress,\n    // List<MultipartFile> files,\n  }) async {\n    try {\n      var response = await _performRequest<T>(\n        () => _request<T>(\n          url,\n          'patch',\n          contentType: contentType,\n          body: body,\n          query: query,\n          decoder: decoder,\n          responseInterceptor: responseInterceptor,\n          uploadProgress: uploadProgress,\n        ),\n        headers: headers,\n      );\n      return response;\n    } on Exception catch (e) {\n      if (!errorSafety) {\n        throw GetHttpException(e.toString());\n      }\n      return Future.value(Response<T>(\n        statusText: 'Can not connect to server. Reason: $e',\n      ));\n    }\n  }\n\n  Future<Response<T>> post<T>(\n    String? url, {\n    dynamic body,\n    String? contentType,\n    Map<String, String>? headers,\n    Map<String, dynamic>? query,\n    Decoder<T>? decoder,\n    ResponseInterceptor<T>? responseInterceptor,\n    Progress? uploadProgress,\n    // List<MultipartFile> files,\n  }) async {\n    try {\n      var response = await _performRequest<T>(\n        () => _request<T>(\n          url,\n          'post',\n          contentType: contentType,\n          body: body,\n          query: query,\n          decoder: decoder,\n          responseInterceptor: responseInterceptor,\n          uploadProgress: uploadProgress,\n        ),\n        headers: headers,\n      );\n      return response;\n    } on Exception catch (e) {\n      if (!errorSafety) {\n        throw GetHttpException(e.toString());\n      }\n      return Future.value(Response<T>(\n        statusText: 'Can not connect to server. Reason: $e',\n      ));\n    }\n  }\n\n  Future<Response<T>> request<T>(\n    String url,\n    String method, {\n    dynamic body,\n    String? contentType,\n    Map<String, String>? headers,\n    Map<String, dynamic>? query,\n    Decoder<T>? decoder,\n    ResponseInterceptor<T>? responseInterceptor,\n    Progress? uploadProgress,\n  }) async {\n    try {\n      var response = await _performRequest<T>(\n        () => _request<T>(\n          url,\n          method,\n          contentType: contentType,\n          query: query,\n          body: body,\n          decoder: decoder,\n          responseInterceptor: responseInterceptor,\n          uploadProgress: uploadProgress,\n        ),\n        headers: headers,\n      );\n      return response;\n    } on Exception catch (e) {\n      if (!errorSafety) {\n        throw GetHttpException(e.toString());\n      }\n      return Future.value(Response<T>(\n        statusText: 'Can not connect to server. Reason: $e',\n      ));\n    }\n  }\n\n  Future<Response<T>> put<T>(\n    String url, {\n    dynamic body,\n    String? contentType,\n    Map<String, String>? headers,\n    Map<String, dynamic>? query,\n    Decoder<T>? decoder,\n    ResponseInterceptor<T>? responseInterceptor,\n    Progress? uploadProgress,\n  }) async {\n    try {\n      var response = await _performRequest<T>(\n        () => _request<T>(\n          url,\n          'put',\n          contentType: contentType,\n          query: query,\n          body: body,\n          decoder: decoder,\n          responseInterceptor: responseInterceptor,\n          uploadProgress: uploadProgress,\n        ),\n        headers: headers,\n      );\n      return response;\n    } on Exception catch (e) {\n      if (!errorSafety) {\n        throw GetHttpException(e.toString());\n      }\n      return Future.value(Response<T>(\n        statusText: 'Can not connect to server. Reason: $e',\n      ));\n    }\n  }\n\n  Future<Response<T>> get<T>(\n    String url, {\n    Map<String, String>? headers,\n    String? contentType,\n    Map<String, dynamic>? query,\n    Decoder<T>? decoder,\n    ResponseInterceptor<T>? responseInterceptor,\n  }) async {\n    try {\n      var response = await _performRequest<T>(\n        () => _get<T>(url, contentType, query, decoder, responseInterceptor),\n        headers: headers,\n      );\n      return response;\n    } on Exception catch (e) {\n      if (!errorSafety) {\n        throw GetHttpException(e.toString());\n      }\n      return Future.value(Response<T>(\n        statusText: 'Can not connect to server. Reason: $e',\n      ));\n    }\n  }\n\n  Future<Response<T>> delete<T>(String url,\n      {Map<String, String>? headers,\n      String? contentType,\n      Map<String, dynamic>? query,\n      Decoder<T>? decoder,\n      ResponseInterceptor<T>? responseInterceptor}) async {\n    try {\n      var response = await _performRequest<T>(\n        () async =>\n            _delete<T>(url, contentType, query, decoder, responseInterceptor),\n        headers: headers,\n      );\n      return response;\n    } on Exception catch (e) {\n      if (!errorSafety) {\n        throw GetHttpException(e.toString());\n      }\n      return Future.value(Response<T>(\n        statusText: 'Can not connect to server. Reason: $e',\n      ));\n    }\n  }\n\n  void close() {\n    _httpClient.close();\n  }\n}\n"
  },
  {
    "path": "lib/get_connect/http/src/interceptors/get_modifiers.dart",
    "content": "import 'dart:async';\n\nimport '../request/request.dart';\nimport '../response/response.dart';\n\ntypedef RequestModifier<T> = FutureOr<Request<T>> Function(Request<T?> request);\n\ntypedef ResponseModifier<T> = FutureOr Function(\n    Request<T?> request, Response<T?> response);\n\ntypedef HandlerExecute<T> = Future<Request<T>> Function();\n\nclass GetModifier<S> {\n  final _requestModifiers = <RequestModifier>[];\n  final _responseModifiers = <ResponseModifier>[];\n  RequestModifier? authenticator;\n\n  void addRequestModifier<T>(RequestModifier<T> interceptor) {\n    _requestModifiers.add(interceptor as RequestModifier);\n  }\n\n  void removeRequestModifier<T>(RequestModifier<T> interceptor) {\n    _requestModifiers.remove(interceptor);\n  }\n\n  void addResponseModifier<T>(ResponseModifier<T> interceptor) {\n    _responseModifiers.add(interceptor as ResponseModifier);\n  }\n\n  void removeResponseModifier<T>(ResponseModifier<T> interceptor) {\n    _requestModifiers.remove(interceptor);\n  }\n\n  Future<Request<T>> modifyRequest<T>(Request<T> request) async {\n    var newRequest = request;\n    if (_requestModifiers.isNotEmpty) {\n      for (var interceptor in _requestModifiers) {\n        newRequest = await interceptor(newRequest) as Request<T>;\n      }\n    }\n\n    return newRequest;\n  }\n\n  Future<Response<T>> modifyResponse<T>(\n      Request<T> request, Response<T> response) async {\n    var newResponse = response;\n    if (_responseModifiers.isNotEmpty) {\n      for (var interceptor in _responseModifiers) {\n        newResponse = await interceptor(request, newResponse) as Response<T>;\n      }\n    }\n\n    return newResponse;\n  }\n}\n"
  },
  {
    "path": "lib/get_connect/http/src/multipart/form_data.dart",
    "content": "import 'dart:async';\nimport 'dart:convert';\nimport 'dart:math';\n\nimport '../request/request.dart';\nimport '../utils/utils.dart';\nimport 'multipart_file.dart';\n\nclass FormData {\n  FormData(Map<String, dynamic> map) : boundary = _getBoundary() {\n    map.forEach((key, value) {\n      if (value == null) return;\n      if (value is MultipartFile) {\n        files.add(MapEntry(key, value));\n      } else if (value is List<MultipartFile>) {\n        files.addAll(value.map((e) => MapEntry(key, e)));\n      } else if (value is List) {\n        fields.addAll(value.map((e) => MapEntry(key, e.toString())));\n      } else {\n        fields.add(MapEntry(key, value.toString()));\n      }\n    });\n  }\n\n  static const int _maxBoundaryLength = 70;\n\n  static String _getBoundary() {\n    final newRandom = Random();\n    var list = List<int>.generate(_maxBoundaryLength - GET_BOUNDARY.length,\n        (_) => boundaryCharacters[newRandom.nextInt(boundaryCharacters.length)],\n        growable: false);\n    return '$GET_BOUNDARY${String.fromCharCodes(list)}';\n  }\n\n  final String boundary;\n\n  /// The form fields to send for this request.\n  final fields = <MapEntry<String, String>>[];\n\n  /// The files to send for this request\n  final files = <MapEntry<String, MultipartFile>>[];\n\n  /// Returns the header string for a field. The return value is guaranteed to\n  /// contain only ASCII characters.\n  String _fieldHeader(String name, String value) {\n    var header =\n        'content-disposition: form-data; name=\"${browserEncode(name)}\"';\n    if (!isPlainAscii(value)) {\n      header = '$header\\r\\n'\n          'content-type: text/plain; charset=utf-8\\r\\n'\n          'content-transfer-encoding: binary';\n    }\n    return '$header\\r\\n\\r\\n';\n  }\n\n  /// Returns the header string for a file. The return value is guaranteed to\n  /// contain only ASCII characters.\n  String _fileHeader(MapEntry<String, MultipartFile> file) {\n    var header =\n        'content-disposition: form-data; name=\"${browserEncode(file.key)}\"';\n    header = '$header; filename=\"${browserEncode(file.value.filename)}\"';\n    header = '$header\\r\\n'\n        'content-type: ${file.value.contentType}';\n    return '$header\\r\\n\\r\\n';\n  }\n\n  /// The length of the request body from this [FormData]\n  int get length {\n    var length = 0;\n\n    for (final item in fields) {\n      length += '--'.length +\n          _maxBoundaryLength +\n          '\\r\\n'.length +\n          utf8.encode(_fieldHeader(item.key, item.value)).length +\n          utf8.encode(item.value).length +\n          '\\r\\n'.length;\n    }\n\n    for (var file in files) {\n      length += '--'.length +\n          _maxBoundaryLength +\n          '\\r\\n'.length +\n          utf8.encode(_fileHeader(file)).length +\n          file.value.length! +\n          '\\r\\n'.length;\n    }\n\n    return length + '--'.length + _maxBoundaryLength + '--\\r\\n'.length;\n  }\n\n  Future<List<int>> toBytes() {\n    return BodyBytesStream(_encode()).toBytes();\n  }\n\n  Stream<List<int>> _encode() async* {\n    const line = [13, 10];\n    final separator = utf8.encode('--$boundary\\r\\n');\n    final close = utf8.encode('--$boundary--\\r\\n');\n\n    for (var field in fields) {\n      yield separator;\n      yield utf8.encode(_fieldHeader(field.key, field.value));\n      yield utf8.encode(field.value);\n      yield line;\n    }\n\n    for (final file in files) {\n      yield separator;\n      yield utf8.encode(_fileHeader(file));\n      yield* file.value.stream!;\n      yield line;\n    }\n    yield close;\n  }\n}\n"
  },
  {
    "path": "lib/get_connect/http/src/multipart/multipart_file.dart",
    "content": "import '../http/stub/file_decoder_stub.dart'\n    if (dart.library.js_interop) '../http/html/file_decoder_html.dart'\n    if (dart.library.io) '../http/io/file_decoder_io.dart';\nimport '../request/request.dart';\n\nclass MultipartFile {\n  MultipartFile(\n    dynamic data, {\n    required this.filename,\n    this.contentType = 'application/octet-stream',\n  }) : _bytes = fileToBytes(data) {\n    _length = _bytes.length;\n    _stream = _bytes.toStream();\n  }\n\n  final List<int> _bytes;\n\n  final String contentType;\n\n  /// This stream will emit the file content of File.\n  Stream<List<int>>? _stream;\n\n  int? _length;\n\n  Stream<List<int>>? get stream => _stream;\n\n  int? get length => _length;\n\n  final String filename;\n}\n"
  },
  {
    "path": "lib/get_connect/http/src/request/request.dart",
    "content": "import 'dart:async';\nimport 'dart:convert';\nimport 'dart:typed_data';\n\nimport '../http.dart';\nimport '../multipart/form_data.dart';\n\nclass Request<T> {\n  /// Headers attach to this [Request]\n  final Map<String, String> headers;\n\n  /// The [Uri] from request\n  final Uri url;\n\n  final Decoder<T>? decoder;\n\n  final ResponseInterceptor<T>? responseInterceptor;\n\n  /// The Http Method from this [Request]\n  /// ex: `GET`,`POST`,`PUT`,`DELETE`\n  final String method;\n\n  final int? contentLength;\n\n  /// The BodyBytesStream of body from this [Request]\n  final Stream<List<int>> bodyBytes;\n\n  /// When true, the client will follow redirects to resolves this [Request]\n  final bool followRedirects;\n\n  /// The maximum number of redirects if [followRedirects] is true.\n  final int maxRedirects;\n\n  final bool persistentConnection;\n\n  final FormData? files;\n\n  const Request._({\n    required this.method,\n    required this.bodyBytes,\n    required this.url,\n    required this.headers,\n    required this.contentLength,\n    required this.followRedirects,\n    required this.maxRedirects,\n    required this.files,\n    required this.persistentConnection,\n    required this.decoder,\n    this.responseInterceptor,\n  });\n\n  factory Request({\n    required Uri url,\n    required String method,\n    required Map<String, String> headers,\n    Stream<List<int>>? bodyBytes,\n    bool followRedirects = true,\n    int maxRedirects = 4,\n    int? contentLength,\n    FormData? files,\n    bool persistentConnection = true,\n    Decoder<T>? decoder,\n    ResponseInterceptor<T>? responseInterceptor,\n  }) {\n    if (followRedirects) {\n      assert(maxRedirects > 0);\n    }\n    return Request._(\n        url: url,\n        method: method,\n        bodyBytes: bodyBytes ??= <int>[].toStream(),\n        headers: Map.from(headers),\n        followRedirects: followRedirects,\n        maxRedirects: maxRedirects,\n        contentLength: contentLength,\n        files: files,\n        persistentConnection: persistentConnection,\n        decoder: decoder,\n        responseInterceptor: responseInterceptor);\n  }\n\n  Request<T> copyWith({\n    Uri? url,\n    String? method,\n    Map<String, String>? headers,\n    Stream<List<int>>? bodyBytes,\n    bool? followRedirects,\n    int? maxRedirects,\n    int? contentLength,\n    FormData? files,\n    bool? persistentConnection,\n    Decoder<T>? decoder,\n    bool appendHeader = true,\n    ResponseInterceptor<T>? responseInterceptor,\n  }) {\n    // If appendHeader is set to true, we will merge origin headers with that\n    if (appendHeader && headers != null) {\n      headers.addAll(this.headers);\n    }\n\n    return Request<T>._(\n        url: url ?? this.url,\n        method: method ?? this.method,\n        bodyBytes: bodyBytes ?? this.bodyBytes,\n        headers: headers == null ? this.headers : Map.from(headers),\n        followRedirects: followRedirects ?? this.followRedirects,\n        maxRedirects: maxRedirects ?? this.maxRedirects,\n        contentLength: contentLength ?? this.contentLength,\n        files: files ?? this.files,\n        persistentConnection: persistentConnection ?? this.persistentConnection,\n        decoder: decoder ?? this.decoder,\n        responseInterceptor: responseInterceptor ?? this.responseInterceptor);\n  }\n}\n\nextension StreamExt on List<int> {\n  Stream<List<int>> toStream() => Stream.value(this).asBroadcastStream();\n}\n\nextension BodyBytesStream on Stream<List<int>> {\n  Future<Uint8List> toBytes() {\n    var completer = Completer<Uint8List>();\n    var sink = ByteConversionSink.withCallback(\n      (bytes) => completer.complete(\n        Uint8List.fromList(bytes),\n      ),\n    );\n    listen((val) => sink.add(val),\n        onError: completer.completeError,\n        onDone: sink.close,\n        cancelOnError: true);\n    return completer.future;\n  }\n\n  Future<String> bytesToString([Encoding encoding = utf8]) =>\n      encoding.decodeStream(this);\n}\n"
  },
  {
    "path": "lib/get_connect/http/src/response/client_response.dart",
    "content": "/// Redirect information.\nabstract interface class RedirectInfo {\n  /// Returns the status code used for the redirect.\n  int get statusCode;\n\n  /// Returns the method used for the redirect.\n  String get method;\n\n  /// Returns the location for the redirect.\n  Uri get location;\n}\n\nabstract interface class HttpClientResponse implements Stream<List<int>> {\n  /// Returns the status code.\n  ///\n  /// The status code must be set before the body is written\n  /// to. Setting the status code after writing to the body will throw\n  /// a `StateError`.\n  int get statusCode;\n\n  /// Returns the reason phrase associated with the status code.\n  ///\n  /// The reason phrase must be set before the body is written\n  /// to. Setting the reason phrase after writing to the body will throw\n  /// a `StateError`.\n  String get reasonPhrase;\n\n  /// Returns the content length of the response body. Returns -1 if the size of\n  /// the response body is not known in advance.\n  ///\n  /// If the content length needs to be set, it must be set before the\n  /// body is written to. Setting the content length after writing to the body\n  /// will throw a `StateError`.\n  int get contentLength;\n\n  // /// The compression state of the response.\n  // ///\n  // /// This specifies whether the response bytes were compressed when they were\n  // /// received across the wire and whether callers will receive compressed\n  // /// or uncompressed bytes when they listed to this response's byte stream.\n  // @Since(\"2.4\")\n  // HttpClientResponseCompressionState get compressionState;\n\n  /// Gets the persistent connection state returned by the server.\n  ///\n  /// If the persistent connection state needs to be set, it must be\n  /// set before the body is written to. Setting the persistent connection state\n  /// after writing to the body will throw a `StateError`.\n  bool get persistentConnection;\n\n  /// Returns whether the status code is one of the normal redirect\n  /// codes [HttpStatus.movedPermanently], [HttpStatus.found],\n  /// [HttpStatus.movedTemporarily], [HttpStatus.seeOther] and\n  /// [HttpStatus.temporaryRedirect].\n  bool get isRedirect;\n\n  /// Returns the series of redirects this connection has been through. The\n  /// list will be empty if no redirects were followed. [redirects] will be\n  /// updated both in the case of an automatic and a manual redirect.\n  List<RedirectInfo> get redirects;\n\n  /// Redirects this connection to a new URL. The default value for\n  /// [method] is the method for the current request. The default value\n  /// for [url] is the value of the [HttpHeaders.locationHeader] header of\n  /// the current response. All body data must have been read from the\n  /// current response before calling [redirect].\n  ///\n  /// All headers added to the request will be added to the redirection\n  /// request. However, any body sent with the request will not be\n  /// part of the redirection request.\n  ///\n  /// If [followLoops] is set to `true`, redirect will follow the redirect,\n  /// even if the URL was already visited. The default value is `false`.\n  ///\n  /// The method will ignore [HttpClientRequest.maxRedirects]\n  /// and will always perform the redirect.\n  Future<HttpClientResponse> redirect(\n      [String? method, Uri? url, bool? followLoops]);\n\n  /// Returns the client response headers.\n  ///\n  /// The client response headers are immutable.\n  HttpHeaders get headers;\n\n  // /// Detach the underlying socket from the HTTP client. When the\n  // /// socket is detached the HTTP client will no longer perform any\n  // /// operations on it.\n  // ///\n  // /// This is normally used when a HTTP upgrade is negotiated and the\n  // /// communication should continue with a different protocol.\n  // Future<Socket> detachSocket();\n\n  // /// Cookies set by the server (from the 'set-cookie' header).\n  // List<Cookie> get cookies;\n\n  // /// Returns the certificate of the HTTPS server providing the response.\n  // /// Returns null if the connection is not a secure TLS or SSL connection.\n  // X509Certificate? get certificate;\n\n  // /// Gets information about the client connection. Returns `null` if the socket\n  // /// is not available.\n  // HttpConnectionInfo? get connectionInfo;\n}\n\n/// Headers for HTTP requests and responses.\n///\n/// In some situations, headers are immutable:\n///\n/// * [HttpRequest] and [HttpClientResponse] always have immutable headers.\n///\n/// * [HttpResponse] and [HttpClientRequest] have immutable headers\n///   from the moment the body is written to.\n///\n/// In these situations, the mutating methods throw exceptions.\n///\n/// For all operations on HTTP headers the header name is\n/// case-insensitive.\n///\n/// To set the value of a header use the `set()` method:\n///\n///     request.headers.set(HttpHeaders.cacheControlHeader,\n///                         'max-age=3600, must-revalidate');\n///\n/// To retrieve the value of a header use the `value()` method:\n///\n///     print(request.headers.value(HttpHeaders.userAgentHeader));\n///\n/// An `HttpHeaders` object holds a list of values for each name\n/// as the standard allows. In most cases a name holds only a single value,\n/// The most common mode of operation is to use `set()` for setting a value,\n/// and `value()` for retrieving a value.\nabstract interface class HttpHeaders {\n  static const acceptHeader = \"accept\";\n  static const acceptCharsetHeader = \"accept-charset\";\n  static const acceptEncodingHeader = \"accept-encoding\";\n  static const acceptLanguageHeader = \"accept-language\";\n  static const acceptRangesHeader = \"accept-ranges\";\n  static const accessControlAllowCredentialsHeader =\n      'access-control-allow-credentials';\n  static const accessControlAllowHeadersHeader = 'access-control-allow-headers';\n  static const accessControlAllowMethodsHeader = 'access-control-allow-methods';\n  static const accessControlAllowOriginHeader = 'access-control-allow-origin';\n  static const accessControlExposeHeadersHeader =\n      'access-control-expose-headers';\n  static const accessControlMaxAgeHeader = 'access-control-max-age';\n  static const accessControlRequestHeadersHeader =\n      'access-control-request-headers';\n  static const accessControlRequestMethodHeader =\n      'access-control-request-method';\n  static const ageHeader = \"age\";\n  static const allowHeader = \"allow\";\n  static const authorizationHeader = \"authorization\";\n  static const cacheControlHeader = \"cache-control\";\n  static const connectionHeader = \"connection\";\n  static const contentEncodingHeader = \"content-encoding\";\n  static const contentLanguageHeader = \"content-language\";\n  static const contentLengthHeader = \"content-length\";\n  static const contentLocationHeader = \"content-location\";\n  static const contentMD5Header = \"content-md5\";\n  static const contentRangeHeader = \"content-range\";\n  static const contentTypeHeader = \"content-type\";\n  static const dateHeader = \"date\";\n  static const etagHeader = \"etag\";\n  static const expectHeader = \"expect\";\n  static const expiresHeader = \"expires\";\n  static const fromHeader = \"from\";\n  static const hostHeader = \"host\";\n  static const ifMatchHeader = \"if-match\";\n  static const ifModifiedSinceHeader = \"if-modified-since\";\n  static const ifNoneMatchHeader = \"if-none-match\";\n  static const ifRangeHeader = \"if-range\";\n  static const ifUnmodifiedSinceHeader = \"if-unmodified-since\";\n  static const lastModifiedHeader = \"last-modified\";\n  static const locationHeader = \"location\";\n  static const maxForwardsHeader = \"max-forwards\";\n  static const pragmaHeader = \"pragma\";\n  static const proxyAuthenticateHeader = \"proxy-authenticate\";\n  static const proxyAuthorizationHeader = \"proxy-authorization\";\n  static const rangeHeader = \"range\";\n  static const refererHeader = \"referer\";\n  static const retryAfterHeader = \"retry-after\";\n  static const serverHeader = \"server\";\n  static const teHeader = \"te\";\n  static const trailerHeader = \"trailer\";\n  static const transferEncodingHeader = \"transfer-encoding\";\n  static const upgradeHeader = \"upgrade\";\n  static const userAgentHeader = \"user-agent\";\n  static const varyHeader = \"vary\";\n  static const viaHeader = \"via\";\n  static const warningHeader = \"warning\";\n  static const wwwAuthenticateHeader = \"www-authenticate\";\n  static const contentDisposition = \"content-disposition\";\n\n  // Cookie headers from RFC 6265.\n  static const cookieHeader = \"cookie\";\n  static const setCookieHeader = \"set-cookie\";\n\n  static const generalHeaders = [\n    cacheControlHeader,\n    connectionHeader,\n    dateHeader,\n    pragmaHeader,\n    trailerHeader,\n    transferEncodingHeader,\n    upgradeHeader,\n    viaHeader,\n    warningHeader\n  ];\n\n  static const entityHeaders = [\n    allowHeader,\n    contentEncodingHeader,\n    contentLanguageHeader,\n    contentLengthHeader,\n    contentLocationHeader,\n    contentMD5Header,\n    contentRangeHeader,\n    contentTypeHeader,\n    expiresHeader,\n    lastModifiedHeader\n  ];\n\n  static const responseHeaders = [\n    acceptRangesHeader,\n    ageHeader,\n    etagHeader,\n    locationHeader,\n    proxyAuthenticateHeader,\n    retryAfterHeader,\n    serverHeader,\n    varyHeader,\n    wwwAuthenticateHeader,\n    contentDisposition\n  ];\n\n  static const requestHeaders = [\n    acceptHeader,\n    acceptCharsetHeader,\n    acceptEncodingHeader,\n    acceptLanguageHeader,\n    authorizationHeader,\n    expectHeader,\n    fromHeader,\n    hostHeader,\n    ifMatchHeader,\n    ifModifiedSinceHeader,\n    ifNoneMatchHeader,\n    ifRangeHeader,\n    ifUnmodifiedSinceHeader,\n    maxForwardsHeader,\n    proxyAuthorizationHeader,\n    rangeHeader,\n    refererHeader,\n    teHeader,\n    userAgentHeader\n  ];\n\n  /// The date specified by the [dateHeader] header, if any.\n  DateTime? date;\n\n  /// The date and time specified by the [expiresHeader] header, if any.\n  DateTime? expires;\n\n  /// The date and time specified by the [ifModifiedSinceHeader] header, if any.\n  DateTime? ifModifiedSince;\n\n  /// The value of the [hostHeader] header, if any.\n  String? host;\n\n  /// The value of the port part of the [hostHeader] header, if any.\n  int? port;\n\n  /// The [ContentType] of the [contentTypeHeader] header, if any.\n  // ContentType? contentType;\n\n  /// The value of the [contentLengthHeader] header, if any.\n  ///\n  /// The value is negative if there is no content length set.\n  int contentLength = -1;\n\n  /// Whether the connection is persistent (keep-alive).\n  late bool persistentConnection;\n\n  /// Whether the connection uses chunked transfer encoding.\n  ///\n  /// Reflects and modifies the value of the [transferEncodingHeader] header.\n  late bool chunkedTransferEncoding;\n\n  /// The values for the header named [name].\n  ///\n  /// Returns null if there is no header with the provided name,\n  /// otherwise returns a new list containing the current values.\n  /// Not that modifying the list does not change the header.\n  List<String>? operator [](String name);\n\n  /// Convenience method for the value for a single valued header.\n  ///\n  /// The value must not have more than one value.\n  ///\n  /// Returns `null` if there is no header with the provided name.\n  String? value(String name);\n\n  /// Adds a header value.\n  ///\n  /// The header named [name] will have a string value derived from [value]\n  /// added to its list of values.\n  ///\n  /// Some headers are single valued, and for these, adding a value will\n  /// replace a previous value. If the [value] is a [DateTime], an\n  /// HTTP date format will be applied. If the value is an [Iterable],\n  /// each element will be added separately. For all other\n  /// types the default [Object.toString] method will be used.\n  ///\n  /// Header names are converted to lower-case unless\n  /// [preserveHeaderCase] is set to true. If two header names are\n  /// the same when converted to lower-case, they are considered to be\n  /// the same header, with one set of values.\n  ///\n  /// The current case of the a header name is that of the name used by\n  /// the last [set] or [add] call for that header.\n  void add(String name, Object value, {bool preserveHeaderCase = false});\n\n  /// Sets the header [name] to [value].\n  ///\n  /// Removes all existing values for the header named [name] and\n  /// then [add]s [value] to it.\n  void set(String name, Object value, {bool preserveHeaderCase = false});\n\n  /// Removes a specific value for a header name.\n  ///\n  /// Some headers have system supplied values which cannot be removed.\n  /// For all other headers and values, the [value] is converted to a string\n  /// in the same way as for [add], then that string value is removed from the\n  /// current values of [name].\n  /// If there are no remaining values for [name], the header is no longer\n  /// considered present.\n  void remove(String name, Object value);\n\n  /// Removes all values for the specified header name.\n  ///\n  /// Some headers have system supplied values which cannot be removed.\n  /// All other values for [name] are removed.\n  /// If there are no remaining values for [name], the header is no longer\n  /// considered present.\n  void removeAll(String name);\n\n  /// Performs the [action] on each header.\n  ///\n  /// The [action] function is called with each header's name and a list\n  /// of the header's values. The casing of the name string is determined by\n  /// the last [add] or [set] operation for that particular header,\n  /// which defaults to lower-casing the header name unless explicitly\n  /// set to preserve the case.\n  void forEach(void Function(String name, List<String> values) action);\n\n  /// Disables folding for the header named [name] when sending the HTTP header.\n  ///\n  /// By default, multiple header values are folded into a\n  /// single header line by separating the values with commas.\n  ///\n  /// The 'set-cookie' header has folding disabled by default.\n  void noFolding(String name);\n\n  /// Removes all headers.\n  ///\n  /// Some headers have system supplied values which cannot be removed.\n  /// All other header values are removed, and header names with not\n  /// remaining values are no longer considered present.\n  void clear();\n}\n"
  },
  {
    "path": "lib/get_connect/http/src/response/response.dart",
    "content": "import 'dart:collection';\nimport 'dart:convert';\n\nimport '../exceptions/exceptions.dart';\nimport '../request/request.dart';\nimport '../status/http_status.dart';\n\nclass GraphQLResponse<T> extends Response<T> {\n  final List<GraphQLError>? graphQLErrors;\n\n  GraphQLResponse({super.body, this.graphQLErrors});\n\n  GraphQLResponse.fromResponse(Response res)\n      : graphQLErrors = null,\n        super(\n            request: res.request,\n            statusCode: res.statusCode,\n            bodyBytes: res.bodyBytes,\n            bodyString: res.bodyString,\n            statusText: res.statusText,\n            headers: res.headers,\n            body: res.body['data'] as T?);\n}\n\nclass Response<T> {\n  const Response({\n    this.request,\n    this.statusCode,\n    this.bodyBytes,\n    this.bodyString,\n    this.statusText = '',\n    this.headers = const {},\n    this.body,\n  });\n\n  Response<T> copyWith({\n    Request? request,\n    int? statusCode,\n    Stream<List<int>>? bodyBytes,\n    String? bodyString,\n    String? statusText,\n    Map<String, String>? headers,\n    T? body,\n  }) {\n    return Response<T>(\n      request: request ?? this.request,\n      statusCode: statusCode ?? this.statusCode,\n      bodyBytes: bodyBytes ?? this.bodyBytes,\n      bodyString: bodyString ?? this.bodyString,\n      statusText: statusText ?? this.statusText,\n      headers: headers ?? this.headers,\n      body: body ?? this.body,\n    );\n  }\n\n  /// The Http [Request] linked with this [Response].\n  final Request? request;\n\n  /// The response headers.\n  final Map<String, String>? headers;\n\n  /// The status code returned by the server.\n  final int? statusCode;\n\n  /// Human-readable context for [statusCode].\n  final String? statusText;\n\n  /// [HttpStatus] from [Response]. `status.connectionError` is true\n  /// when statusCode is null. `status.isUnauthorized` is true when\n  /// statusCode is equal `401`. `status.isNotFound` is true when\n  /// statusCode is equal `404`. `status.isServerError` is true when\n  /// statusCode is between `500` and `599`.\n  HttpStatus get status => HttpStatus(statusCode);\n\n  /// `hasError` is true when statusCode is not between 200 and 299.\n  bool get hasError => status.hasError;\n\n  /// `isOk` is true when statusCode is between 200 and 299.\n  bool get isOk => !hasError;\n\n  /// `unauthorized` is true when statusCode is equal `401`.\n  bool get unauthorized => status.isUnauthorized;\n\n  /// The response body as a Stream of Bytes.\n  final Stream<List<int>>? bodyBytes;\n\n  /// The response body as a Stream of Bytes.\n  final String? bodyString;\n\n  /// The decoded body of this [Response]. You can access the\n  /// body parameters as Map\n  /// Ex: `body['title'];`\n  final T? body;\n}\n\nFuture<String> bodyBytesToString(\n    Stream<List<int>> bodyBytes, Map<String, String> headers) {\n  return bodyBytes.bytesToString(_encodingForHeaders(headers));\n}\n\n/// Returns the encoding to use for a response with the given headers.\n///\n/// Defaults to [utf8] if the headers don't specify a charset or if that\n/// charset is unknown.\nEncoding _encodingForHeaders(Map<String, String> headers) =>\n    _encodingForCharset(_contentTypeForHeaders(headers).parameters!['charset']);\n\n/// Returns the [Encoding] that corresponds to [charset].\n///\n/// Returns [fallback] if [charset] is null or if no [Encoding] was found that\n/// corresponds to [charset].\nEncoding _encodingForCharset(String? charset, [Encoding fallback = utf8]) {\n  if (charset == null) return fallback;\n  return Encoding.getByName(charset) ?? fallback;\n}\n\n/// Returns the MediaType object for the given headers's content-type.\n///\n/// Defaults to `application/octet-stream`.\nHeaderValue _contentTypeForHeaders(Map<String, String> headers) {\n  var contentType = headers['content-type'];\n  if (contentType != null) return HeaderValue.parse(contentType);\n  return HeaderValue('application/octet-stream');\n}\n\nclass HeaderValue {\n  String _value;\n  Map<String, String?>? _parameters;\n  Map<String, String?>? _unmodifiableParameters;\n\n  HeaderValue([this._value = '', Map<String, String>? parameters]) {\n    if (parameters != null) {\n      _parameters = HashMap<String, String>.from(parameters);\n    }\n  }\n\n  static HeaderValue parse(String value,\n      {String parameterSeparator = ';',\n      String? valueSeparator,\n      bool preserveBackslash = false}) {\n    var result = HeaderValue();\n    result._parse(value, parameterSeparator, valueSeparator, preserveBackslash);\n    return result;\n  }\n\n  String get value => _value;\n\n  void _ensureParameters() {\n    _parameters ??= HashMap<String, String>();\n  }\n\n  Map<String, String?>? get parameters {\n    _ensureParameters();\n    _unmodifiableParameters ??= UnmodifiableMapView(_parameters!);\n    return _unmodifiableParameters;\n  }\n\n  @override\n  String toString() {\n    var stringBuffer = StringBuffer();\n    stringBuffer.write(_value);\n    if (parameters != null && parameters!.isNotEmpty) {\n      _parameters!.forEach((name, value) {\n        stringBuffer\n          ..write('; ')\n          ..write(name)\n          ..write('=')\n          ..write(value);\n      });\n    }\n    return stringBuffer.toString();\n  }\n\n  void _parse(String value, String parameterSeparator, String? valueSeparator,\n      bool preserveBackslash) {\n    var index = 0;\n\n    bool done() => index == value.length;\n\n    void bump() {\n      while (!done()) {\n        if (value[index] != ' ' && value[index] != '\\t') return;\n        index++;\n      }\n    }\n\n    String parseValue() {\n      var start = index;\n      while (!done()) {\n        if (value[index] == ' ' ||\n            value[index] == '\\t' ||\n            value[index] == valueSeparator ||\n            value[index] == parameterSeparator) {\n          break;\n        }\n        index++;\n      }\n      return value.substring(start, index);\n    }\n\n    void expect(String expected) {\n      if (done() || value[index] != expected) {\n        throw StateError('Failed to parse header value');\n      }\n      index++;\n    }\n\n    void maybeExpect(String expected) {\n      if (value[index] == expected) index++;\n    }\n\n    void parseParameters() {\n      var parameters = HashMap<String, String?>();\n      _parameters = UnmodifiableMapView(parameters);\n\n      String parseParameterName() {\n        var start = index;\n        while (!done()) {\n          if (value[index] == ' ' ||\n              value[index] == '\\t' ||\n              value[index] == '=' ||\n              value[index] == parameterSeparator ||\n              value[index] == valueSeparator) {\n            break;\n          }\n          index++;\n        }\n        return value.substring(start, index).toLowerCase();\n      }\n\n      String? parseParameterValue() {\n        if (!done() && value[index] == '\"') {\n          var stringBuffer = StringBuffer();\n          index++;\n          while (!done()) {\n            if (value[index] == '\\\\') {\n              if (index + 1 == value.length) {\n                throw StateError('Failed to parse header value');\n              }\n              if (preserveBackslash && value[index + 1] != '\"') {\n                stringBuffer.write(value[index]);\n              }\n              index++;\n            } else if (value[index] == '\"') {\n              index++;\n              break;\n            }\n            stringBuffer.write(value[index]);\n            index++;\n          }\n          return stringBuffer.toString();\n        } else {\n          var val = parseValue();\n          return val == '' ? null : val;\n        }\n      }\n\n      while (!done()) {\n        bump();\n        if (done()) return;\n        var name = parseParameterName();\n        bump();\n        if (done()) {\n          parameters[name] = null;\n          return;\n        }\n        maybeExpect('=');\n        bump();\n        if (done()) {\n          parameters[name] = null;\n          return;\n        }\n        var valueParameter = parseParameterValue();\n        if (name == 'charset' && valueParameter != null) {\n          valueParameter = valueParameter.toLowerCase();\n        }\n        parameters[name] = valueParameter;\n        bump();\n        if (done()) return;\n        if (value[index] == valueSeparator) return;\n        expect(parameterSeparator);\n      }\n    }\n\n    bump();\n    _value = parseValue();\n    bump();\n    if (done()) return;\n    maybeExpect(parameterSeparator);\n    parseParameters();\n  }\n}\n"
  },
  {
    "path": "lib/get_connect/http/src/status/http_status.dart",
    "content": "class HttpStatus {\n  HttpStatus(this.code);\n\n  final int? code;\n\n  static const int continue_ = 100;\n  static const int switchingProtocols = 101;\n  static const int processing = 102;\n  static const int earlyHints = 103;\n  static const int ok = 200;\n  static const int created = 201;\n  static const int accepted = 202;\n  static const int nonAuthoritativeInformation = 203;\n  static const int noContent = 204;\n  static const int resetContent = 205;\n  static const int partialContent = 206;\n  static const int multiStatus = 207;\n  static const int alreadyReported = 208;\n  static const int imUsed = 226;\n  static const int multipleChoices = 300;\n  static const int movedPermanently = 301;\n  static const int found = 302;\n  static const int movedTemporarily = 302; // Common alias for found.\n  static const int seeOther = 303;\n  static const int notModified = 304;\n  static const int useProxy = 305;\n  static const int switchProxy = 306;\n  static const int temporaryRedirect = 307;\n  static const int permanentRedirect = 308;\n  static const int badRequest = 400;\n  static const int unauthorized = 401;\n  static const int paymentRequired = 402;\n  static const int forbidden = 403;\n  static const int notFound = 404;\n  static const int methodNotAllowed = 405;\n  static const int notAcceptable = 406;\n  static const int proxyAuthenticationRequired = 407;\n  static const int requestTimeout = 408;\n  static const int conflict = 409;\n  static const int gone = 410;\n  static const int lengthRequired = 411;\n  static const int preconditionFailed = 412;\n  static const int requestEntityTooLarge = 413;\n  static const int requestUriTooLong = 414;\n  static const int unsupportedMediaType = 415;\n  static const int requestedRangeNotSatisfiable = 416;\n  static const int expectationFailed = 417;\n  static const int imATeapot = 418;\n  static const int misdirectedRequest = 421;\n  static const int unprocessableEntity = 422;\n  static const int locked = 423;\n  static const int failedDependency = 424;\n  static const int tooEarly = 425;\n  static const int upgradeRequired = 426;\n  static const int preconditionRequired = 428;\n  static const int tooManyRequests = 429;\n  static const int requestHeaderFieldsTooLarge = 431;\n  static const int connectionClosedWithoutResponse = 444;\n  static const int unavailableForLegalReasons = 451;\n  static const int clientClosedRequest = 499;\n  static const int internalServerError = 500;\n  static const int notImplemented = 501;\n  static const int badGateway = 502;\n  static const int serviceUnavailable = 503;\n  static const int gatewayTimeout = 504;\n  static const int httpVersionNotSupported = 505;\n  static const int variantAlsoNegotiates = 506;\n  static const int insufficientStorage = 507;\n  static const int loopDetected = 508;\n  static const int notExtended = 510;\n  static const int networkAuthenticationRequired = 511;\n  static const int networkConnectTimeoutError = 599;\n\n  bool get connectionError => code == null;\n\n  bool get isUnauthorized => code == unauthorized;\n\n  bool get isForbidden => code == forbidden;\n\n  bool get isNotFound => code == notFound;\n\n  bool get isServerError =>\n      between(internalServerError, networkConnectTimeoutError);\n\n  bool between(int begin, int end) {\n    return !connectionError && code! >= begin && code! <= end;\n  }\n\n  bool get isOk => between(200, 299);\n\n  bool get hasError => !isOk;\n}\n"
  },
  {
    "path": "lib/get_connect/http/src/utils/utils.dart",
    "content": "// ignore_for_file: constant_identifier_names\n\nimport 'dart:convert';\n\nbool isTokenChar(int byte) {\n  return byte > 31 && byte < 128 && !SEPARATOR_MAP[byte];\n}\n\nbool isValueChar(int byte) {\n  return (byte > 31 && byte < 128) ||\n      (byte == CharCode.SP) ||\n      (byte == CharCode.HT);\n}\n\nclass CharCode {\n  static const int HT = 9;\n  static const int LF = 10;\n  static const int CR = 13;\n  static const int SP = 32;\n  static const int COMMA = 44;\n  static const int SLASH = 47;\n  static const int ZERO = 48;\n  static const int ONE = 49;\n  static const int COLON = 58;\n  static const int SEMI_COLON = 59;\n}\n\nconst bool F = false;\n\nconst bool T = true;\nconst SEPARATOR_MAP = [\n  F, F, F, F, F, F, F, F, F, T, F, F, F, F, F, F, F, F, F, F, F, F, F, F, //\n  F, F, F, F, F, F, F, F, T, F, T, F, F, F, F, F, T, T, F, F, T, F, F, T, //\n  F, F, F, F, F, F, F, F, F, F, T, T, T, T, T, T, T, F, F, F, F, F, F, F, //\n  F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, T, T, T, F, F, //\n  F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, //\n  F, F, F, T, F, T, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, //\n  F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, //\n  F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, //\n  F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, //\n  F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, //\n  F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F\n];\n\nString validateField(String field) {\n  for (var i = 0; i < field.length; i++) {\n    if (!isTokenChar(field.codeUnitAt(i))) {\n      throw FormatException(\n          'Invalid HTTP header field name: ${json.encode(field)}', field, i);\n    }\n  }\n  return field.toLowerCase();\n}\n\n// Stream<List<int>> toBodyBytesStream(Stream<List<int>> stream) {\n//   return (stream);\n// }\n\nfinal _asciiOnly = RegExp(r'^[\\x00-\\x7F]+$');\n\nfinal newlineRegExp = RegExp(r'\\r\\n|\\r|\\n');\n\n/// Returns whether [string] is composed entirely of ASCII-compatible\n/// characters.\nbool isPlainAscii(String string) => _asciiOnly.hasMatch(string);\n\nconst String GET_BOUNDARY = 'getx-http-boundary-';\n\n/// Encode [value] like browsers\nString browserEncode(String value) {\n  return value.replaceAll(newlineRegExp, '%0D%0A').replaceAll('\"', '%22');\n}\n\nconst List<int> boundaryCharacters = <int>[\n  43,\n  95,\n  45,\n  46,\n  48,\n  49,\n  50,\n  51,\n  52,\n  53,\n  54,\n  55,\n  56,\n  57,\n  65,\n  66,\n  67,\n  68,\n  69,\n  70,\n  71,\n  72,\n  73,\n  74,\n  75,\n  76,\n  77,\n  78,\n  79,\n  80,\n  81,\n  82,\n  83,\n  84,\n  85,\n  86,\n  87,\n  88,\n  89,\n  90,\n  97,\n  98,\n  99,\n  100,\n  101,\n  102,\n  103,\n  104,\n  105,\n  106,\n  107,\n  108,\n  109,\n  110,\n  111,\n  112,\n  113,\n  114,\n  115,\n  116,\n  117,\n  118,\n  119,\n  120,\n  121,\n  122\n];\n"
  },
  {
    "path": "lib/get_connect/sockets/sockets.dart",
    "content": "import 'src/sockets_stub.dart'\n    if (dart.library.js_interop) 'src/sockets_html.dart'\n    if (dart.library.io) 'src/sockets_io.dart';\n\nclass GetSocket extends BaseWebSocket {\n  GetSocket(super.url, {super.ping, super.allowSelfSigned});\n}\n"
  },
  {
    "path": "lib/get_connect/sockets/src/socket_notifier.dart",
    "content": "import 'dart:convert';\n\n/// Signature for [SocketNotifier.addCloses].\ntypedef CloseSocket = void Function(Close);\n\n/// Signature for [SocketNotifier.addMessages].\ntypedef MessageSocket = void Function(dynamic val);\n\n/// Signature for [SocketNotifier.open].\ntypedef OpenSocket = void Function();\n\n/// Wrapper class to message and reason from SocketNotifier\nclass Close {\n  final String? message;\n  final int? reason;\n\n  Close(this.message, this.reason);\n\n  @override\n  String toString() {\n    return 'Closed by server [$reason => $message]!';\n  }\n}\n\n/// This class manages the transmission of messages over websockets using\n/// GetConnect\nclass SocketNotifier {\n  List<void Function(dynamic)>? _onMessages = <MessageSocket>[];\n  Map<String, void Function(dynamic)>? _onEvents = <String, MessageSocket>{};\n  List<void Function(Close)>? _onCloses = <CloseSocket>[];\n  List<void Function(Close)>? _onErrors = <CloseSocket>[];\n\n  late OpenSocket open;\n\n  /// subscribe to close events\n  void addCloses(CloseSocket socket) {\n    _onCloses!.add(socket);\n  }\n\n  /// subscribe to error events\n  void addErrors(CloseSocket socket) {\n    _onErrors!.add((socket));\n  }\n\n  /// subscribe to named events\n  void addEvents(String event, MessageSocket socket) {\n    _onEvents![event] = socket;\n  }\n\n  /// subscribe to message events\n  void addMessages(MessageSocket socket) {\n    _onMessages!.add((socket));\n  }\n\n  /// Dispose messages, events, closes and errors subscriptions\n  void dispose() {\n    _onMessages = null;\n    _onEvents = null;\n    _onCloses = null;\n    _onErrors = null;\n  }\n\n  /// Notify all subscriptions on [addCloses]\n  void notifyClose(Close err) {\n    for (var item in _onCloses!) {\n      item(err);\n    }\n  }\n\n  /// Notify all subscriptions on [addMessages]\n  void notifyData(dynamic data) {\n    for (var item in _onMessages!) {\n      item(data);\n    }\n    if (data is String) {\n      _tryOn(data);\n    }\n  }\n\n  /// Notify all subscriptions on [addErrors]\n  void notifyError(Close err) {\n    // rooms.removeWhere((key, value) => value.contains(_ws));\n    for (var item in _onErrors!) {\n      item(err);\n    }\n  }\n\n  void _tryOn(String message) {\n    try {\n      var msg = jsonDecode(message);\n      final event = msg['type'];\n      final data = msg['data'];\n      if (_onEvents!.containsKey(event)) {\n        _onEvents![event]!(data);\n      }\n      // ignore: avoid_catches_without_on_clauses\n    } catch (_) {\n      return;\n    }\n  }\n}\n"
  },
  {
    "path": "lib/get_connect/sockets/src/sockets_html.dart",
    "content": "import 'dart:async';\nimport 'dart:convert';\nimport 'dart:js_interop';\n\nimport 'package:web/web.dart' as html;\n\nimport '../../../get_core/get_core.dart';\nimport 'socket_notifier.dart';\n\nclass BaseWebSocket {\n  String url;\n  html.WebSocket? socket;\n  SocketNotifier? socketNotifier = SocketNotifier();\n  Duration ping;\n  bool isDisposed = false;\n  bool allowSelfSigned;\n\n  ConnectionStatus? connectionStatus;\n  Timer? _t;\n  BaseWebSocket(\n    this.url, {\n    this.ping = const Duration(seconds: 5),\n    this.allowSelfSigned = true,\n  }) {\n    url = url.startsWith('https')\n        ? url.replaceAll('https:', 'wss:')\n        : url.replaceAll('http:', 'ws:');\n  }\n\n  void close([int? status, String? reason]) {\n    // This weird code is fault of web package, they are not using null safety yet\n    // See https://github.com/dart-lang/web/blob/main/web/lib/src/dom/websockets.dart#L60\n    if (status != null && reason != null) {\n      socket?.close(status, reason);\n    } else if (status != null) {\n      socket?.close(status);\n    } else {\n      socket?.close();\n    }\n  }\n\n  // ignore: use_setters_to_change_properties\n  void connect() {\n    try {\n      connectionStatus = ConnectionStatus.connecting;\n      socket = html.WebSocket(url);\n      socket!.onOpen.listen((e) {\n        socketNotifier?.open();\n        _t = Timer?.periodic(ping, (t) {\n          socket!.send(''.toJSBox);\n        });\n        connectionStatus = ConnectionStatus.connected;\n      });\n\n      socket!.onMessage.listen((event) {\n        socketNotifier!.notifyData(event.data);\n      });\n\n      socket!.onClose.listen((e) {\n        _t?.cancel();\n\n        connectionStatus = ConnectionStatus.closed;\n        socketNotifier!.notifyClose(Close(e.reason, e.code));\n      });\n      socket!.onError.listen((event) {\n        _t?.cancel();\n        socketNotifier!.notifyError(Close(event.toString(), 0));\n        connectionStatus = ConnectionStatus.closed;\n      });\n    } on Exception catch (e) {\n      _t?.cancel();\n      socketNotifier!.notifyError(Close(e.toString(), 500));\n      connectionStatus = ConnectionStatus.closed;\n      //  close(500, e.toString());\n    }\n  }\n\n  void dispose() {\n    socketNotifier!.dispose();\n    socketNotifier = null;\n    isDisposed = true;\n  }\n\n  void emit(String event, dynamic data) {\n    send(jsonEncode({'type': event, 'data': data}));\n  }\n\n  void on(String event, MessageSocket message) {\n    socketNotifier!.addEvents(event, message);\n  }\n\n  void onClose(CloseSocket fn) {\n    socketNotifier!.addCloses(fn);\n  }\n\n  void onError(CloseSocket fn) {\n    socketNotifier!.addErrors(fn);\n  }\n\n  void onMessage(MessageSocket fn) {\n    socketNotifier!.addMessages(fn);\n  }\n\n  // ignore: use_setters_to_change_properties\n  void onOpen(OpenSocket fn) {\n    socketNotifier!.open = fn;\n  }\n\n  void send(Object data) {\n    if (connectionStatus == ConnectionStatus.closed) {\n      connect();\n    }\n    if (socket != null && socket!.readyState == html.WebSocket.OPEN) {\n      socket!.send(data.toJSBox);\n    } else {\n      Get.log('WebSocket not connected, message $data not sent');\n    }\n  }\n}\n\nenum ConnectionStatus {\n  connecting,\n  connected,\n  closed,\n}\n"
  },
  {
    "path": "lib/get_connect/sockets/src/sockets_io.dart",
    "content": "import 'dart:async';\nimport 'dart:convert';\nimport 'dart:io';\nimport 'dart:math';\n\nimport '../../../get_core/get_core.dart';\nimport 'socket_notifier.dart';\n\nclass BaseWebSocket {\n  String url;\n  WebSocket? socket;\n  SocketNotifier? socketNotifier = SocketNotifier();\n  bool isDisposed = false;\n  Duration ping;\n  bool allowSelfSigned;\n  ConnectionStatus? connectionStatus;\n\n  BaseWebSocket(\n    this.url, {\n    this.ping = const Duration(seconds: 5),\n    this.allowSelfSigned = true,\n  });\n\n  void close([int? status, String? reason]) {\n    socket?.close(status, reason);\n  }\n\n  // ignore: use_setters_to_change_properties\n  Future connect() async {\n    if (isDisposed) {\n      socketNotifier = SocketNotifier();\n    }\n    try {\n      connectionStatus = ConnectionStatus.connecting;\n      socket = allowSelfSigned\n          ? await _connectForSelfSignedCert(url)\n          : await WebSocket.connect(url);\n\n      socket!.pingInterval = ping;\n      socketNotifier?.open();\n      connectionStatus = ConnectionStatus.connected;\n\n      socket!.listen((data) {\n        socketNotifier!.notifyData(data);\n      }, onError: (err) {\n        socketNotifier!.notifyError(Close(err.toString(), 1005));\n      }, onDone: () {\n        connectionStatus = ConnectionStatus.closed;\n        socketNotifier!\n            .notifyClose(Close('Connection Closed', socket!.closeCode));\n      }, cancelOnError: true);\n      return;\n    } on SocketException catch (e) {\n      connectionStatus = ConnectionStatus.closed;\n      socketNotifier!\n          .notifyError(Close(e.osError!.message, e.osError!.errorCode));\n      return;\n    }\n  }\n\n  void dispose() {\n    socketNotifier!.dispose();\n    socketNotifier = null;\n    isDisposed = true;\n  }\n\n  void emit(String event, dynamic data) {\n    send(jsonEncode({'type': event, 'data': data}));\n  }\n\n  void on(String event, MessageSocket message) {\n    socketNotifier!.addEvents(event, message);\n  }\n\n  void onClose(CloseSocket fn) {\n    socketNotifier!.addCloses(fn);\n  }\n\n  void onError(CloseSocket fn) {\n    socketNotifier!.addErrors(fn);\n  }\n\n  void onMessage(MessageSocket fn) {\n    socketNotifier!.addMessages(fn);\n  }\n\n  // ignore: use_setters_to_change_properties\n  void onOpen(OpenSocket fn) {\n    socketNotifier!.open = fn;\n  }\n\n  void send(dynamic data) async {\n    if (connectionStatus == ConnectionStatus.closed) {\n      await connect();\n    }\n\n    if (socket != null) {\n      socket!.add(data);\n    }\n  }\n\n  Future<WebSocket> _connectForSelfSignedCert(String url) async {\n    try {\n      var r = Random();\n      var key = base64.encode(List<int>.generate(8, (_) => r.nextInt(255)));\n      var client = HttpClient(context: SecurityContext());\n      client.badCertificateCallback = (cert, host, port) {\n        Get.log(\n            'BaseWebSocket: Allow self-signed certificate => $host:$port. ');\n        return true;\n      };\n\n      var request = await client.getUrl(Uri.parse(url))\n        ..headers.add('Connection', 'Upgrade')\n        ..headers.add('Upgrade', 'websocket')\n        ..headers.add('Cache-Control', 'no-cache')\n        ..headers.add('Sec-WebSocket-Version', '13')\n        ..headers.add('Sec-WebSocket-Key', key.toLowerCase());\n\n      var response = await request.close();\n      // ignore: close_sinks\n      var socket = await response.detachSocket();\n      var webSocket = WebSocket.fromUpgradedSocket(\n        socket,\n        serverSide: false,\n      );\n\n      return webSocket;\n    } on Exception catch (_) {\n      rethrow;\n    }\n  }\n}\n\nenum ConnectionStatus {\n  connecting,\n  connected,\n  closed,\n}\n"
  },
  {
    "path": "lib/get_connect/sockets/src/sockets_stub.dart",
    "content": "import './socket_notifier.dart';\n\nclass BaseWebSocket {\n  String url;\n  Duration ping;\n  bool allowSelfSigned;\n  BaseWebSocket(\n    this.url, {\n    this.ping = const Duration(seconds: 5),\n    this.allowSelfSigned = true,\n  }) {\n    throw 'To use sockets you need dart:io or dart:html';\n  }\n\n  Future connect() async {\n    throw 'To use sockets you need dart:io or dart:html';\n  }\n\n  void onOpen(OpenSocket fn) {\n    throw 'To use sockets you need dart:io or dart:html';\n  }\n\n  void onClose(CloseSocket fn) {\n    throw 'To use sockets you need dart:io or dart:html';\n  }\n\n  void onError(CloseSocket fn) {\n    throw 'To use sockets you need dart:io or dart:html';\n  }\n\n  void onMessage(MessageSocket fn) {\n    throw 'To use sockets you need dart:io or dart:html';\n  }\n\n  void on(String event, MessageSocket message) {\n    throw 'To use sockets you need dart:io or dart:html';\n  }\n\n  void close([int? status, String? reason]) {\n    throw 'To use sockets you need dart:io or dart:html';\n  }\n\n  void send(dynamic data) async {\n    throw 'To use sockets you need dart:io or dart:html';\n  }\n\n  void dispose() {\n    throw 'To use sockets you need dart:io or dart:html';\n  }\n\n  void emit(String event, dynamic data) {\n    throw 'To use sockets you need dart:io or dart:html';\n  }\n}\n"
  },
  {
    "path": "lib/get_connect.dart",
    "content": "export 'get_connect/connect.dart';\n"
  },
  {
    "path": "lib/get_core/get_core.dart",
    "content": "library;\n\nexport 'src/flutter_engine.dart';\nexport 'src/get_interface.dart';\nexport 'src/get_main.dart';\nexport 'src/log.dart';\nexport 'src/smart_management.dart';\nexport 'src/typedefs.dart';\n"
  },
  {
    "path": "lib/get_core/src/flutter_engine.dart",
    "content": "import 'package:flutter/widgets.dart';\n\nclass Engine {\n  static WidgetsBinding get instance {\n    return WidgetsFlutterBinding.ensureInitialized();\n  }\n}\n"
  },
  {
    "path": "lib/get_core/src/get_interface.dart",
    "content": "import 'package:flutter/foundation.dart';\n\nimport 'log.dart';\nimport 'smart_management.dart';\n\n/// GetInterface allows any auxiliary package to be merged into the \"Get\"\n/// class through extensions\nabstract class GetInterface {\n  SmartManagement smartManagement = SmartManagement.full;\n  bool isLogEnable = kDebugMode;\n  LogWriterCallback log = defaultLogWriterCallback;\n}\n"
  },
  {
    "path": "lib/get_core/src/get_main.dart",
    "content": "import 'get_interface.dart';\n\n///Use to instead of Navigator.push, off instead of Navigator.pushReplacement,\n///offAll instead of Navigator.pushAndRemoveUntil. For named routes just\n///add \"named\" after them. Example: toNamed, offNamed, and AllNamed.\n///To return to the previous screen, use back().\n///No need to pass any context to Get, just put the name of the route inside\n///the parentheses and the magic will occur.\nclass _GetImpl extends GetInterface {}\n\n// ignore: non_constant_identifier_names\nfinal Get = _GetImpl();\n"
  },
  {
    "path": "lib/get_core/src/log.dart",
    "content": "import 'dart:developer' as developer;\nimport 'get_main.dart';\n\n///VoidCallback from logs\ntypedef LogWriterCallback = void Function(String text, {bool isError});\n\n/// default logger from GetX\nvoid defaultLogWriterCallback(String value, {bool isError = false}) {\n  if (isError || Get.isLogEnable) developer.log(value, name: 'GETX');\n}\n"
  },
  {
    "path": "lib/get_core/src/smart_management.dart",
    "content": "/// GetX by default disposes unused controllers from memory,\n/// Through different behaviors.\n/// SmartManagement.full\n/// [SmartManagement.full] is the default one. Dispose classes that are\n/// not being used and were not set to be permanent. In the majority\n/// of the cases you will want to keep this config untouched.\n/// If you new to GetX then don't change this.\n/// [SmartManagement.onlyBuilder] only controllers started in init:\n/// or loaded into a Binding with Get.lazyPut() will be disposed. If you use\n/// Get.put() or Get.putAsync() or any other approach, SmartManagement\n/// will not have permissions to exclude this dependency. With the default\n/// behavior, even widgets instantiated with \"Get.put\" will be removed,\n/// unlike SmartManagement.onlyBuilders.\n/// [SmartManagement.keepFactory]Just like SmartManagement.full,\n/// it will remove it's dependencies when it's not being used anymore.\n/// However, it will keep their factory, which means it will recreate\n/// the dependency if you need that instance again.\nenum SmartManagement {\n  full,\n  onlyBuilder,\n  keepFactory,\n}\n"
  },
  {
    "path": "lib/get_core/src/typedefs.dart",
    "content": "typedef ValueUpdater<T> = T Function();\n"
  },
  {
    "path": "lib/get_instance/get_instance.dart",
    "content": "export 'src/bindings_interface.dart';\nexport 'src/extension_instance.dart';\nexport 'src/lifecycle.dart';\n"
  },
  {
    "path": "lib/get_instance/src/bindings_interface.dart",
    "content": "// ignore: one_member_abstracts\n\n// ignore: one_member_abstracts\nabstract class BindingsInterface<T> {\n  T dependencies();\n}\n\n/// [Bindings] should be extended or implemented.\n/// When using `GetMaterialApp`, all `GetPage`s and navigation\n/// methods (like Get.to()) have a `binding` property that takes an\n/// instance of Bindings to manage the\n/// dependencies() (via Get.put()) for the Route you are opening.\n// ignore: one_member_abstracts\n@Deprecated('Use Binding instead')\nabstract class Bindings extends BindingsInterface<void> {\n  @override\n  void dependencies();\n}\n\n// /// Simplifies Bindings generation from a single callback.\n// /// To avoid the creation of a custom Binding instance per route.\n// ///\n// /// Example:\n// /// ```\n// /// GetPage(\n// ///   name: '/',\n// ///   page: () => Home(),\n// ///   // This might cause you an error.\n// ///   // binding: BindingsBuilder(() => Get.put(HomeController())),\n// ///   binding: BindingsBuilder(() { Get.put(HomeController(); })),\n// ///   // Using .lazyPut() works fine.\n// ///   // binding: BindingsBuilder(() => Get.lazyPut(() => HomeController())),\n// /// ),\n// /// ```\n// class BindingsBuilder<T> extends Bindings {\n//   /// Register your dependencies in the [builder] callback.\n//   final BindingBuilderCallback builder;\n\n//   /// Shortcut to register 1 Controller with Get.put(),\n//   /// Prevents the issue of the fat arrow function with the constructor.\n//   /// BindingsBuilder(() => Get.put(HomeController())),\n//   ///\n//   /// Sample:\n//   /// ```\n//   /// GetPage(\n//   ///   name: '/',\n//   ///   page: () => Home(),\n//   ///   binding: BindingsBuilder.put(() => HomeController()),\n//   /// ),\n//   /// ```\n//   factory BindingsBuilder.put(InstanceBuilderCallback<T> builder,\n//       {String? tag, bool permanent = false}) {\n//     return BindingsBuilder(\n//         () => Get.put<T>(builder(), tag: tag, permanent: permanent));\n//   }\n\n//   /// WARNING: don't use `()=> Get.put(Controller())`,\n//   /// if only passing 1 callback use `BindingsBuilder.put(Controller())`\n//   /// or `BindingsBuilder(()=> Get.lazyPut(Controller()))`\n//   BindingsBuilder(this.builder);\n\n//   @override\n//   void dependencies() {\n//     builder();\n//   }\n// }\n\ntypedef BindingBuilderCallback = void Function();\n"
  },
  {
    "path": "lib/get_instance/src/extension_instance.dart",
    "content": "import 'dart:async';\n\nimport 'package:flutter/material.dart';\n\nimport '../../get_core/get_core.dart';\nimport '../../get_navigation/src/router_report.dart';\nimport 'lifecycle.dart';\n\nclass InstanceInfo {\n  final bool? isPermanent;\n  final bool? isSingleton;\n  bool get isCreate => !isSingleton!;\n  final bool isRegistered;\n  final bool isPrepared;\n  final bool? isInit;\n  const InstanceInfo({\n    required this.isPermanent,\n    required this.isSingleton,\n    required this.isRegistered,\n    required this.isPrepared,\n    required this.isInit,\n  });\n\n  @override\n  String toString() {\n    return 'InstanceInfo(isPermanent: $isPermanent, isSingleton: $isSingleton, isRegistered: $isRegistered, isPrepared: $isPrepared, isInit: $isInit)';\n  }\n}\n\nextension ResetInstance on GetInterface {\n  /// Clears all registered instances (and/or tags).\n  /// Even the persistent ones.\n  /// This should be used at the end or tearDown of unit tests.\n  ///\n  /// `clearFactory` clears the callbacks registered by [lazyPut]\n  /// `clearRouteBindings` clears Instances associated with routes.\n  ///\n  bool resetInstance({bool clearRouteBindings = true}) {\n    //  if (clearFactory) _factory.clear();\n    // deleteAll(force: true);\n    if (clearRouteBindings) RouterReportManager.instance.clearRouteKeys();\n    Inst._singl.clear();\n\n    return true;\n  }\n}\n\nextension Inst on GetInterface {\n  T call<T>() => find<T>();\n\n  /// Holds references to every registered Instance when using\n  /// `Get.put()`\n  static final Map<String, _InstanceBuilderFactory> _singl = {};\n\n  /// Holds a reference to every registered callback when using\n  /// `Get.lazyPut()`\n  // static final Map<String, _Lazy> _factory = {};\n\n  // void injector<S>(\n  //   InjectorBuilderCallback<S> fn, {\n  //   String? tag,\n  //   bool fenix = false,\n  //   //  bool permanent = false,\n  // }) {\n  //   lazyPut(\n  //     () => fn(this),\n  //     tag: tag,\n  //     fenix: fenix,\n  //     // permanent: permanent,\n  //   );\n  // }\n\n  S put<S>(\n    S dependency, {\n    String? tag,\n    bool permanent = false,\n  }) {\n    _insert(\n        isSingleton: true,\n        name: tag,\n        permanent: permanent,\n        builder: (() => dependency));\n    return find<S>(tag: tag);\n  }\n\n  /// Creates a new Instance<S> lazily from the `<S>builder()` callback.\n  ///\n  /// The first time you call `Get.find()`, the `builder()` callback will create\n  /// the Instance and persisted as a Singleton (like you would\n  /// use `Get.put()`).\n  ///\n  /// Using `Get.smartManagement` as [SmartManagement.keepFactory] has\n  /// the same outcome as using `fenix:true` :\n  /// The internal register of `builder()` will remain in memory to recreate\n  /// the Instance if the Instance has been removed with `Get.delete()`.\n  /// Therefore, future calls to `Get.find()` will return the same Instance.\n  ///\n  /// If you need to make use of GetxController's life-cycle\n  /// (`onInit(), onStart(), onClose()`) [fenix] is a great choice to mix with\n  /// `GetBuilder()` and `GetX()` widgets, and/or `GetMaterialApp` Navigation.\n  ///\n  /// You could use `Get.lazyPut(fenix:true)` in your app's `main()` instead\n  /// of `Bindings()` for each `GetPage`.\n  /// And the memory management will be similar.\n  ///\n  /// Subsequent calls to `Get.lazyPut()` with the same parameters\n  /// (<[S]> and optionally [tag] will **not** override the original).\n  void lazyPut<S>(\n    InstanceBuilderCallback<S> builder, {\n    String? tag,\n    bool? fenix,\n    bool permanent = false,\n  }) {\n    _insert(\n      isSingleton: true,\n      name: tag,\n      permanent: permanent,\n      builder: builder,\n      fenix: fenix ?? Get.smartManagement == SmartManagement.keepFactory,\n    );\n  }\n\n  /// Creates a new Class Instance [S] from the builder callback[S].\n  /// Every time [find]<[S]>() is used, it calls the builder method to generate\n  /// a new Instance [S].\n  /// It also registers each `instance.onClose()` with the current\n  /// Route `Get.reference` to keep the lifecycle active.\n  /// Is important to know that the instances created are only stored per Route.\n  /// So, if you call `Get.delete<T>()` the \"instance factory\" used in this\n  /// method (`Get.spawn<T>()`) will be removed, but NOT the instances\n  /// already created by it.\n  ///\n  /// Example:\n  ///\n  /// ```Get.spawn(() => Repl());\n  /// Repl a = find();\n  /// Repl b = find();\n  /// print(a==b); (false)```\n  void spawn<S>(\n    InstanceBuilderCallback<S> builder, {\n    String? tag,\n    bool permanent = true,\n  }) {\n    _insert(\n      isSingleton: false,\n      name: tag,\n      builder: builder,\n      permanent: permanent,\n    );\n  }\n\n  /// Injects the Instance [S] builder into the `_singleton` HashMap.\n  void _insert<S>({\n    bool? isSingleton,\n    String? name,\n    bool permanent = false,\n    required InstanceBuilderCallback<S> builder,\n    bool fenix = false,\n  }) {\n    final key = _getKey(S, name);\n\n    _InstanceBuilderFactory<S>? dep;\n    if (_singl.containsKey(key)) {\n      final newDep = _singl[key];\n      if (newDep == null || !newDep.isDirty) {\n        return;\n      } else {\n        dep = newDep as _InstanceBuilderFactory<S>;\n      }\n    }\n    _singl[key] = _InstanceBuilderFactory<S>(\n      isSingleton: isSingleton,\n      builderFunc: builder,\n      permanent: permanent,\n      isInit: false,\n      fenix: fenix,\n      tag: name,\n      lateRemove: dep,\n    );\n  }\n\n  /// Initializes the dependencies for a Class Instance [S] (or tag),\n  /// If its a Controller, it starts the lifecycle process.\n  /// Optionally associating the current Route to the lifetime of the instance,\n  /// if `Get.smartManagement` is marked as [SmartManagement.full] or\n  /// [SmartManagement.keepFactory]\n  /// Only flags `isInit` if it's using `Get.create()`\n  /// (not for Singletons access).\n  /// Returns the instance if not initialized, required for Get.create() to\n  /// work properly.\n  S? _initDependencies<S>({String? name}) {\n    final key = _getKey(S, name);\n    final isInit = _singl[key]!.isInit;\n    S? i;\n    if (!isInit) {\n      final isSingleton = _singl[key]?.isSingleton ?? false;\n      if (isSingleton) {\n        _singl[key]!.isInit = true;\n      }\n      i = _startController<S>(tag: name);\n\n      if (isSingleton) {\n        if (Get.smartManagement != SmartManagement.onlyBuilder) {\n          RouterReportManager.instance\n              .reportDependencyLinkedToRoute(_getKey(S, name));\n        }\n      }\n    }\n    return i;\n  }\n\n  InstanceInfo getInstanceInfo<S>({String? tag}) {\n    final build = _getDependency<S>(tag: tag);\n\n    return InstanceInfo(\n      isPermanent: build?.permanent,\n      isSingleton: build?.isSingleton,\n      isRegistered: isRegistered<S>(tag: tag),\n      isPrepared: !(build?.isInit ?? true),\n      isInit: build?.isInit,\n    );\n  }\n\n  _InstanceBuilderFactory? _getDependency<S>({String? tag, String? key}) {\n    final newKey = key ?? _getKey(S, tag);\n\n    if (!_singl.containsKey(newKey)) {\n      Get.log('Instance \"$newKey\" is not registered.', isError: true);\n      return null;\n    } else {\n      return _singl[newKey];\n    }\n  }\n\n  void markAsDirty<S>({String? tag, String? key}) {\n    final newKey = key ?? _getKey(S, tag);\n    if (_singl.containsKey(newKey)) {\n      final dep = _singl[newKey];\n      if (dep != null && !dep.permanent) {\n        dep.isDirty = true;\n      }\n    }\n  }\n\n  /// Initializes the controller\n  S _startController<S>({String? tag}) {\n    final key = _getKey(S, tag);\n    final i = _singl[key]!.getDependency() as S;\n    if (i is GetLifeCycleMixin) {\n      i.onStart();\n      if (tag == null) {\n        Get.log('Instance \"$S\" has been initialized');\n      } else {\n        Get.log('Instance \"$S\" with tag \"$tag\" has been initialized');\n      }\n      if (!_singl[key]!.isSingleton!) {\n        RouterReportManager.instance.appendRouteByCreate(i);\n      }\n    }\n    return i;\n  }\n\n  S putOrFind<S>(InstanceBuilderCallback<S> dep, {String? tag}) {\n    final key = _getKey(S, tag);\n\n    if (_singl.containsKey(key)) {\n      return _singl[key]!.getDependency() as S;\n    } else {\n      return put(dep(), tag: tag);\n    }\n  }\n\n  /// Finds the registered type <[S]> (or [tag])\n  /// In case of using Get.[create] to register a type <[S]> or [tag],\n  /// it will create an instance each time you call [find].\n  /// If the registered type <[S]> (or [tag]) is a Controller,\n  /// it will initialize it's lifecycle.\n  S find<S>({String? tag}) {\n    final key = _getKey(S, tag);\n    if (isRegistered<S>(tag: tag)) {\n      final dep = _singl[key];\n      if (dep == null) {\n        if (tag == null) {\n          throw 'Class \"$S\" is not registered';\n        } else {\n          throw 'Class \"$S\" with tag \"$tag\" is not registered';\n        }\n      }\n\n      /// although dirty solution, the lifecycle starts inside\n      /// `initDependencies`, so we have to return the instance from there\n      /// to make it compatible with `Get.create()`.\n      final i = _initDependencies<S>(name: tag);\n      return i ?? dep.getDependency() as S;\n    } else {\n      // ignore: lines_longer_than_80_chars\n      throw '\"$S\" not found. You need to call \"Get.put($S())\" or \"Get.lazyPut(()=>$S())\"';\n    }\n  }\n\n  /// The findOrNull method will return the instance if it is registered;\n  /// otherwise, it will return null.\n  S? findOrNull<S>({String? tag}) {\n    if (isRegistered<S>(tag: tag)) {\n      return find<S>(tag: tag);\n    }\n    return null;\n  }\n\n  /// Replace a parent instance of a class in dependency management\n  /// with a [child] instance\n  /// - [tag] optional, if you use a [tag] to register the Instance.\n  void replace<P>(P child, {String? tag}) {\n    final info = getInstanceInfo<P>(tag: tag);\n    final permanent = (info.isPermanent ?? false);\n    delete<P>(tag: tag, force: permanent);\n    put(child, tag: tag, permanent: permanent);\n  }\n\n  /// Replaces a parent instance with a new Instance<P> lazily from the\n  /// `<P>builder()` callback.\n  /// - [tag] optional, if you use a [tag] to register the Instance.\n  /// - [fenix] optional\n  ///\n  ///  Note: if fenix is not provided it will be set to true if\n  /// the parent instance was permanent\n  void lazyReplace<P>(InstanceBuilderCallback<P> builder,\n      {String? tag, bool? fenix}) {\n    final info = getInstanceInfo<P>(tag: tag);\n    final permanent = (info.isPermanent ?? false);\n    delete<P>(tag: tag, force: permanent);\n    lazyPut(builder, tag: tag, fenix: fenix ?? permanent);\n  }\n\n  /// Generates the key based on [type] (and optionally a [name])\n  /// to register an Instance Builder in the hashmap.\n  String _getKey(Type type, String? name) {\n    return name == null ? type.toString() : type.toString() + name;\n  }\n\n  /// Delete registered Class Instance [S] (or [tag]) and, closes any open\n  /// controllers `DisposableInterface`, cleans up the memory\n  ///\n  /// /// Deletes the Instance<[S]>, cleaning the memory.\n  //  ///\n  //  /// - [tag] Optional \"tag\" used to register the Instance\n  //  /// - [key] For internal usage, is the processed key used to register\n  //  ///   the Instance. **don't use** it unless you know what you are doing.\n\n  /// Deletes the Instance<[S]>, cleaning the memory and closes any open\n  /// controllers (`DisposableInterface`).\n  ///\n  /// - [tag] Optional \"tag\" used to register the Instance\n  /// - [key] For internal usage, is the processed key used to register\n  ///   the Instance. **don't use** it unless you know what you are doing.\n  /// - [force] Will delete an Instance even if marked as `permanent`.\n  bool delete<S>({String? tag, String? key, bool force = false}) {\n    final newKey = key ?? _getKey(S, tag);\n\n    if (!_singl.containsKey(newKey)) {\n      Get.log('Instance \"$newKey\" already removed.', isError: true);\n      return false;\n    }\n\n    final dep = _singl[newKey];\n\n    if (dep == null) return false;\n\n    final _InstanceBuilderFactory builder;\n    if (dep.isDirty) {\n      builder = dep.lateRemove ?? dep;\n    } else {\n      builder = dep;\n    }\n\n    if (builder.permanent && !force) {\n      Get.log(\n        // ignore: lines_longer_than_80_chars\n        '\"$newKey\" has been marked as permanent, SmartManagement is not authorized to delete it.',\n        isError: true,\n      );\n      return false;\n    }\n    final i = builder.dependency;\n\n    if (i is GetxServiceMixin && !force) {\n      return false;\n    }\n\n    if (i is GetLifeCycleMixin) {\n      i.onDelete();\n      Get.log('\"$newKey\" onDelete() called');\n    }\n\n    if (builder.fenix) {\n      builder.dependency = null;\n      builder.isInit = false;\n      return true;\n    } else {\n      if (dep.lateRemove != null) {\n        dep.lateRemove = null;\n        Get.log('\"$newKey\" deleted from memory');\n        return false;\n      } else {\n        _singl.remove(newKey);\n        if (_singl.containsKey(newKey)) {\n          Get.log('Error removing object \"$newKey\"', isError: true);\n        } else {\n          Get.log('\"$newKey\" deleted from memory');\n        }\n        return true;\n      }\n    }\n  }\n\n  /// Delete all registered Class Instances and, closes any open\n  /// controllers `DisposableInterface`, cleans up the memory\n  ///\n  /// - [force] Will delete the Instances even if marked as `permanent`.\n  void deleteAll({bool force = false}) {\n    final keys = _singl.keys.toList();\n    for (final key in keys) {\n      delete(key: key, force: force);\n    }\n  }\n\n  void reloadAll({bool force = false}) {\n    _singl.forEach((key, value) {\n      if (value.permanent && !force) {\n        Get.log('Instance \"$key\" is permanent. Skipping reload');\n      } else {\n        value.dependency = null;\n        value.isInit = false;\n        Get.log('Instance \"$key\" was reloaded.');\n      }\n    });\n  }\n\n  void reload<S>({\n    String? tag,\n    String? key,\n    bool force = false,\n  }) {\n    final newKey = key ?? _getKey(S, tag);\n\n    final builder = _getDependency<S>(tag: tag, key: newKey);\n    if (builder == null) return;\n\n    if (builder.permanent && !force) {\n      Get.log(\n        '''Instance \"$newKey\" is permanent. Use [force = true] to force the restart.''',\n        isError: true,\n      );\n      return;\n    }\n\n    final i = builder.dependency;\n\n    if (i is GetxServiceMixin && !force) {\n      return;\n    }\n\n    if (i is GetLifeCycleMixin) {\n      i.onDelete();\n      Get.log('\"$newKey\" onDelete() called');\n    }\n\n    builder.dependency = null;\n    builder.isInit = false;\n    Get.log('Instance \"$newKey\" was restarted.');\n  }\n\n  /// Check if a Class Instance<[S]> (or [tag]) is registered in memory.\n  /// - [tag] is optional, if you used a [tag] to register the Instance.\n  bool isRegistered<S>({String? tag}) => _singl.containsKey(_getKey(S, tag));\n\n  /// Checks if a lazy factory callback `Get.lazyPut()` that returns an\n  /// Instance<[S]> is registered in memory.\n  /// - [tag] is optional, if you used a [tag] to register the lazy Instance.\n  bool isPrepared<S>({String? tag}) {\n    final newKey = _getKey(S, tag);\n\n    final builder = _getDependency<S>(tag: tag, key: newKey);\n    if (builder == null) {\n      return false;\n    }\n\n    if (!builder.isInit) {\n      return true;\n    }\n    return false;\n  }\n}\n\ntypedef InstanceBuilderCallback<S> = S Function();\n\ntypedef InstanceCreateBuilderCallback<S> = S Function(BuildContext _);\n\n// typedef InstanceBuilderCallback<S> = S Function();\n\n// typedef InjectorBuilderCallback<S> = S Function(Inst);\n\ntypedef AsyncInstanceBuilderCallback<S> = Future<S> Function();\n\n/// Internal class to register instances with `Get.put<S>()`.\nclass _InstanceBuilderFactory<S> {\n  /// Marks the Builder as a single instance.\n  /// For reusing [dependency] instead of [builderFunc]\n  bool? isSingleton;\n\n  /// When fenix mode is available, when a new instance is need\n  /// Instance manager will recreate a new instance of S\n  bool fenix;\n\n  /// Stores the actual object instance when [isSingleton]=true.\n  S? dependency;\n\n  /// Generates (and regenerates) the instance when [isSingleton]=false.\n  /// Usually used by factory methods\n  InstanceBuilderCallback<S> builderFunc;\n\n  /// Flag to persist the instance in memory,\n  /// without considering `Get.smartManagement`\n  bool permanent = false;\n\n  bool isInit = false;\n\n  _InstanceBuilderFactory<S>? lateRemove;\n\n  bool isDirty = false;\n\n  String? tag;\n\n  _InstanceBuilderFactory({\n    required this.isSingleton,\n    required this.builderFunc,\n    required this.permanent,\n    required this.isInit,\n    required this.fenix,\n    required this.tag,\n    required this.lateRemove,\n  });\n\n  void _showInitLog() {\n    if (tag == null) {\n      Get.log('Instance \"$S\" has been created');\n    } else {\n      Get.log('Instance \"$S\" has been created with tag \"$tag\"');\n    }\n  }\n\n  /// Gets the actual instance by it's [builderFunc] or the persisted instance.\n  S getDependency() {\n    if (isSingleton!) {\n      if (dependency == null) {\n        _showInitLog();\n        dependency = builderFunc();\n      }\n      return dependency!;\n    } else {\n      return builderFunc();\n    }\n  }\n}\n"
  },
  {
    "path": "lib/get_instance/src/lifecycle.dart",
    "content": "import 'package:flutter/foundation.dart';\n\nimport '../../get.dart';\n\n/// The [GetLifeCycle]\n///\n/// ```dart\n/// class SomeController with GetLifeCycle {\n///   SomeController() {\n///     configureLifeCycle();\n///   }\n/// }\n/// ```\nmixin GetLifeCycleMixin {\n  /// Called immediately after the widget is allocated in memory.\n  /// You might use this to initialize something for the controller.\n  @protected\n  @mustCallSuper\n  void onInit() {\n    Engine.instance.addPostFrameCallback((_) => onReady());\n  }\n\n  /// Called 1 frame after onInit(). It is the perfect place to enter\n  /// navigation events, like snackbar, dialogs, or a new route, or\n  /// async request.\n  void onReady() {}\n\n  /// Called before [onDelete] method. [onClose] might be used to\n  /// dispose resources used by the controller. Like closing events,\n  /// or streams before the controller is destroyed.\n  /// Or dispose objects that can potentially create some memory leaks,\n  /// like TextEditingControllers, AnimationControllers.\n  /// Might be useful as well to persist some data on disk.\n  void onClose() {}\n\n  bool _initialized = false;\n\n  /// Checks whether the controller has already been initialized.\n  bool get initialized => _initialized;\n\n  /// Called at the exact moment the widget is allocated in memory.\n  /// It uses an internal \"callable\" type, to avoid any @overrides in subclasses.\n  /// This method should be internal and is required to define the\n  /// lifetime cycle of the subclass.\n  // @protected\n  @mustCallSuper\n  @nonVirtual\n  void onStart() {\n    // _checkIfAlreadyConfigured();\n    if (_initialized) return;\n    onInit();\n    _initialized = true;\n  }\n\n  bool _isClosed = false;\n\n  /// Checks whether the controller has already been closed.\n  bool get isClosed => _isClosed;\n\n  // Called when the controller is removed from memory.\n  @mustCallSuper\n  @nonVirtual\n  void onDelete() {\n    if (_isClosed) return;\n    _isClosed = true;\n    onClose();\n  }\n\n//   void _checkIfAlreadyConfigured() {\n//     if (_initialized) {\n//       throw \"\"\"You can only call configureLifeCycle once.\n// The proper place to insert it is in your class's constructor\n// that inherits GetLifeCycle.\"\"\";\n//     }\n//   }\n}\n\n/// Allow track difference between GetxServices and GetxControllers\nmixin GetxServiceMixin {}\n\n/// Unlike GetxController, which serves to control events on each of its pages,\n/// GetxService is not automatically disposed (nor can be removed with\n/// Get.delete()).\n/// It is ideal for situations where, once started, that service will\n/// remain in memory, such as Auth control for example. Only way to remove\n/// it is Get.reset().\nabstract class GetxService with GetLifeCycleMixin, GetxServiceMixin {}\n"
  },
  {
    "path": "lib/get_navigation/get_navigation.dart",
    "content": "library;\n\nexport 'src/bottomsheet/bottomsheet.dart';\nexport 'src/extension_navigation.dart';\nexport 'src/root/get_cupertino_app.dart';\nexport 'src/root/get_material_app.dart';\nexport 'src/root/internacionalization.dart';\nexport 'src/routes/custom_transition.dart';\nexport 'src/routes/default_route.dart';\nexport 'src/routes/get_route.dart';\nexport 'src/routes/index.dart';\nexport 'src/routes/observers/route_observer.dart';\nexport 'src/routes/route_middleware.dart';\nexport 'src/routes/transitions_type.dart';\nexport 'src/snackbar/snackbar.dart';\nexport 'src/snackbar/snackbar_controller.dart';\n"
  },
  {
    "path": "lib/get_navigation/src/bottomsheet/bottomsheet.dart",
    "content": "import 'package:flutter/material.dart';\n\nimport '../../../get.dart';\nimport '../router_report.dart';\n\nclass GetModalBottomSheetRoute<T> extends PopupRoute<T> {\n  GetModalBottomSheetRoute({\n    this.builder,\n    this.theme,\n    this.barrierLabel,\n    this.backgroundColor,\n    this.isPersistent,\n    this.elevation,\n    this.shape,\n    this.removeTop = true,\n    this.clipBehavior,\n    this.modalBarrierColor,\n    this.isDismissible = true,\n    this.enableDrag = true,\n    required this.isScrollControlled,\n    super.settings,\n    this.enterBottomSheetDuration = const Duration(milliseconds: 250),\n    this.exitBottomSheetDuration = const Duration(milliseconds: 200),\n    this.curve,\n  }) {\n    RouterReportManager.instance.reportCurrentRoute(this);\n  }\n  final bool? isPersistent;\n  final WidgetBuilder? builder;\n  final ThemeData? theme;\n  final bool isScrollControlled;\n  final Color? backgroundColor;\n  final double? elevation;\n  final ShapeBorder? shape;\n  final Clip? clipBehavior;\n  final Color? modalBarrierColor;\n  final bool isDismissible;\n  final bool enableDrag;\n  // final String name;\n  final Duration enterBottomSheetDuration;\n  final Duration exitBottomSheetDuration;\n  final Curve? curve;\n  // remove safearea from top\n  final bool removeTop;\n\n  @override\n  Duration get transitionDuration => const Duration(milliseconds: 700);\n\n  @override\n  bool get barrierDismissible => isDismissible;\n\n  @override\n  final String? barrierLabel;\n\n  @override\n  Color get barrierColor => modalBarrierColor ?? Colors.black54;\n\n  AnimationController? _animationController;\n\n  @override\n  void dispose() {\n    RouterReportManager.instance.reportRouteDispose(this);\n    super.dispose();\n  }\n\n  @override\n  Animation<double> createAnimation() {\n    if (curve != null) {\n      return CurvedAnimation(curve: curve!, parent: _animationController!.view);\n    }\n    return _animationController!.view;\n  }\n\n  @override\n  AnimationController createAnimationController() {\n    assert(_animationController == null);\n    _animationController =\n        BottomSheet.createAnimationController(navigator!.overlay!);\n    _animationController!.duration = enterBottomSheetDuration;\n    _animationController!.reverseDuration = exitBottomSheetDuration;\n    return _animationController!;\n  }\n\n  @override\n  Widget buildPage(BuildContext context, Animation<double> animation,\n      Animation<double> secondaryAnimation) {\n    final sheetTheme =\n        theme?.bottomSheetTheme ?? Theme.of(context).bottomSheetTheme;\n    // By definition, the bottom sheet is aligned to the bottom of the page\n    // and isn't exposed to the top padding of the MediaQuery.\n    Widget bottomSheet = MediaQuery.removePadding(\n      context: context,\n      removeTop: removeTop,\n      child: Padding(\n        padding:\n            EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),\n        child: _GetModalBottomSheet<T>(\n          route: this,\n          backgroundColor: backgroundColor ??\n              sheetTheme.modalBackgroundColor ??\n              sheetTheme.backgroundColor,\n          elevation:\n              elevation ?? sheetTheme.modalElevation ?? sheetTheme.elevation,\n          shape: shape,\n          clipBehavior: clipBehavior,\n          isScrollControlled: isScrollControlled,\n          enableDrag: enableDrag,\n        ),\n      ),\n    );\n    if (theme != null) bottomSheet = Theme(data: theme!, child: bottomSheet);\n    return bottomSheet;\n  }\n}\n\nclass _GetModalBottomSheet<T> extends StatefulWidget {\n  const _GetModalBottomSheet({\n    super.key,\n    this.route,\n    this.backgroundColor,\n    this.elevation,\n    this.shape,\n    this.clipBehavior,\n    this.isScrollControlled = false,\n    this.enableDrag = true,\n    this.isPersistent = false,\n  });\n  final bool isPersistent;\n  final GetModalBottomSheetRoute<T>? route;\n  final bool isScrollControlled;\n  final Color? backgroundColor;\n  final double? elevation;\n  final ShapeBorder? shape;\n  final Clip? clipBehavior;\n  final bool enableDrag;\n\n  @override\n  _GetModalBottomSheetState<T> createState() => _GetModalBottomSheetState<T>();\n}\n\nclass _GetModalBottomSheetState<T> extends State<_GetModalBottomSheet<T>> {\n  String _getRouteLabel(MaterialLocalizations localizations) {\n    if ((Theme.of(context).platform == TargetPlatform.android) ||\n        (Theme.of(context).platform == TargetPlatform.fuchsia)) {\n      return localizations.dialogLabel;\n    } else {\n      return '';\n    }\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    assert(debugCheckHasMediaQuery(context));\n    assert(debugCheckHasMaterialLocalizations(context));\n    final mediaQuery = MediaQuery.of(context);\n    final localizations = MaterialLocalizations.of(context);\n    final routeLabel = _getRouteLabel(localizations);\n\n    return AnimatedBuilder(\n      animation: widget.route!.animation!,\n      builder: (context, child) {\n        // Disable the initial animation when accessible navigation is on so\n        // that the semantics are added to the tree at the correct time.\n        final animationValue = mediaQuery.accessibleNavigation\n            ? 1.0\n            : widget.route!.animation!.value;\n        return Semantics(\n          scopesRoute: true,\n          namesRoute: true,\n          label: routeLabel,\n          explicitChildNodes: true,\n          child: ClipRect(\n            child: CustomSingleChildLayout(\n                delegate: _GetModalBottomSheetLayout(\n                    animationValue, widget.isScrollControlled),\n                child: widget.isPersistent == false\n                    ? BottomSheet(\n                        animationController: widget.route!._animationController,\n                        onClosing: () {\n                          if (widget.route!.isCurrent) {\n                            Navigator.pop(context);\n                          }\n                        },\n                        builder: widget.route!.builder!,\n                        backgroundColor: widget.backgroundColor,\n                        elevation: widget.elevation,\n                        shape: widget.shape,\n                        clipBehavior: widget.clipBehavior,\n                        enableDrag: widget.enableDrag,\n                      )\n                    : Scaffold(\n                        bottomSheet: BottomSheet(\n                          animationController:\n                              widget.route!._animationController,\n                          onClosing: () {\n                            // if (widget.route.isCurrent) {\n                            //   Navigator.pop(context);\n                            // }\n                          },\n                          builder: widget.route!.builder!,\n                          backgroundColor: widget.backgroundColor,\n                          elevation: widget.elevation,\n                          shape: widget.shape,\n                          clipBehavior: widget.clipBehavior,\n                          enableDrag: widget.enableDrag,\n                        ),\n                      )),\n          ),\n        );\n      },\n    );\n  }\n}\n\nclass _GetPerModalBottomSheet<T> extends StatefulWidget {\n  const _GetPerModalBottomSheet({\n    super.key,\n    this.route,\n    this.isPersistent,\n    this.backgroundColor,\n    this.elevation,\n    this.shape,\n    this.clipBehavior,\n    this.isScrollControlled = false,\n    this.enableDrag = true,\n  });\n  final bool? isPersistent;\n  final GetModalBottomSheetRoute<T>? route;\n  final bool isScrollControlled;\n  final Color? backgroundColor;\n  final double? elevation;\n  final ShapeBorder? shape;\n  final Clip? clipBehavior;\n  final bool enableDrag;\n\n  @override\n  // ignore: lines_longer_than_80_chars\n  _GetPerModalBottomSheetState<T> createState() =>\n      _GetPerModalBottomSheetState<T>();\n}\n\n// ignore: lines_longer_than_80_chars\nclass _GetPerModalBottomSheetState<T>\n    extends State<_GetPerModalBottomSheet<T>> {\n  String _getRouteLabel(MaterialLocalizations localizations) {\n    if ((Theme.of(context).platform == TargetPlatform.android) ||\n        (Theme.of(context).platform == TargetPlatform.fuchsia)) {\n      return localizations.dialogLabel;\n    } else {\n      return '';\n    }\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    assert(debugCheckHasMediaQuery(context));\n    assert(debugCheckHasMaterialLocalizations(context));\n    final mediaQuery = MediaQuery.of(context);\n    final localizations = MaterialLocalizations.of(context);\n    final routeLabel = _getRouteLabel(localizations);\n\n    return AnimatedBuilder(\n      animation: widget.route!.animation!,\n      builder: (context, child) {\n        // Disable the initial animation when accessible navigation is on so\n        // that the semantics are added to the tree at the correct time.\n        final animationValue = mediaQuery.accessibleNavigation\n            ? 1.0\n            : widget.route!.animation!.value;\n        return Semantics(\n          scopesRoute: true,\n          namesRoute: true,\n          label: routeLabel,\n          explicitChildNodes: true,\n          child: ClipRect(\n            child: CustomSingleChildLayout(\n                delegate: _GetModalBottomSheetLayout(\n                    animationValue, widget.isScrollControlled),\n                child: widget.isPersistent == false\n                    ? BottomSheet(\n                        animationController: widget.route!._animationController,\n                        onClosing: () {\n                          if (widget.route!.isCurrent) {\n                            Navigator.pop(context);\n                          }\n                        },\n                        builder: widget.route!.builder!,\n                        backgroundColor: widget.backgroundColor,\n                        elevation: widget.elevation,\n                        shape: widget.shape,\n                        clipBehavior: widget.clipBehavior,\n                        enableDrag: widget.enableDrag,\n                      )\n                    : Scaffold(\n                        bottomSheet: BottomSheet(\n                          animationController:\n                              widget.route!._animationController,\n                          onClosing: () {\n                            // if (widget.route.isCurrent) {\n                            //   Navigator.pop(context);\n                            // }\n                          },\n                          builder: widget.route!.builder!,\n                          backgroundColor: widget.backgroundColor,\n                          elevation: widget.elevation,\n                          shape: widget.shape,\n                          clipBehavior: widget.clipBehavior,\n                          enableDrag: widget.enableDrag,\n                        ),\n                      )),\n          ),\n        );\n      },\n    );\n  }\n}\n\nclass _GetModalBottomSheetLayout extends SingleChildLayoutDelegate {\n  _GetModalBottomSheetLayout(this.progress, this.isScrollControlled);\n\n  final double progress;\n  final bool isScrollControlled;\n\n  @override\n  BoxConstraints getConstraintsForChild(BoxConstraints constraints) {\n    return BoxConstraints(\n      minWidth: constraints.maxWidth,\n      maxWidth: constraints.maxWidth,\n      minHeight: 0.0,\n      maxHeight: isScrollControlled\n          ? constraints.maxHeight\n          : constraints.maxHeight * 9.0 / 16.0,\n    );\n  }\n\n  @override\n  Offset getPositionForChild(Size size, Size childSize) {\n    return Offset(0.0, size.height - childSize.height * progress);\n  }\n\n  @override\n  bool shouldRelayout(_GetModalBottomSheetLayout oldDelegate) {\n    return progress != oldDelegate.progress;\n  }\n}\n"
  },
  {
    "path": "lib/get_navigation/src/dialog/dialog_route.dart",
    "content": "import 'package:flutter/widgets.dart';\n\nimport '../router_report.dart';\n\nclass GetDialogRoute<T> extends PopupRoute<T> {\n  GetDialogRoute({\n    required RoutePageBuilder pageBuilder,\n    bool barrierDismissible = true,\n    String? barrierLabel,\n    Color barrierColor = const Color(0x80000000),\n    Duration transitionDuration = const Duration(milliseconds: 200),\n    RouteTransitionsBuilder? transitionBuilder,\n    super.settings,\n  })  : widget = pageBuilder,\n        _barrierDismissible = barrierDismissible,\n        _barrierLabel = barrierLabel,\n        _barrierColor = barrierColor,\n        _transitionDuration = transitionDuration,\n        _transitionBuilder = transitionBuilder {\n    RouterReportManager.instance.reportCurrentRoute(this);\n  }\n\n  final RoutePageBuilder widget;\n\n  @override\n  bool get barrierDismissible => _barrierDismissible;\n  final bool _barrierDismissible;\n\n  @override\n  void dispose() {\n    RouterReportManager.instance.reportRouteDispose(this);\n    super.dispose();\n  }\n\n  @override\n  String? get barrierLabel => _barrierLabel;\n  final String? _barrierLabel;\n\n  @override\n  Color get barrierColor => _barrierColor;\n  final Color _barrierColor;\n\n  @override\n  Duration get transitionDuration => _transitionDuration;\n  final Duration _transitionDuration;\n\n  final RouteTransitionsBuilder? _transitionBuilder;\n\n  @override\n  Widget buildPage(BuildContext context, Animation<double> animation,\n      Animation<double> secondaryAnimation) {\n    return Semantics(\n      scopesRoute: true,\n      explicitChildNodes: true,\n      child: widget(context, animation, secondaryAnimation),\n    );\n  }\n\n  @override\n  Widget buildTransitions(BuildContext context, Animation<double> animation,\n      Animation<double> secondaryAnimation, Widget child) {\n    if (_transitionBuilder == null) {\n      return FadeTransition(\n          opacity: CurvedAnimation(\n            parent: animation,\n            curve: Curves.linear,\n          ),\n          child: child);\n    } // Some default transition\n    return _transitionBuilder(context, animation, secondaryAnimation, child);\n  }\n}\n"
  },
  {
    "path": "lib/get_navigation/src/extension_navigation.dart",
    "content": "import 'dart:ui' as ui;\n\nimport 'package:flutter/material.dart';\nimport 'package:get/get_navigation/src/routes/test_kit.dart';\n\nimport '../../get.dart';\nimport 'dialog/dialog_route.dart';\nimport 'root/get_root.dart';\n\n/// It replaces the Flutter Navigator, but needs no context.\n/// You can to use navigator.push(YourRoute()) rather\n/// Navigator.push(context, YourRoute());\nNavigatorState? get navigator => GetNavigationExt(Get).key.currentState;\n\nextension ExtensionBottomSheet on GetInterface {\n  Future<T?> bottomSheet<T>(\n    Widget bottomsheet, {\n    Color? backgroundColor,\n    double? elevation,\n    bool persistent = true,\n    ShapeBorder? shape,\n    Clip? clipBehavior,\n    Color? barrierColor,\n    bool? ignoreSafeArea,\n    bool isScrollControlled = false,\n    bool useRootNavigator = false,\n    bool isDismissible = true,\n    bool enableDrag = true,\n    RouteSettings? settings,\n    Duration? enterBottomSheetDuration,\n    Duration? exitBottomSheetDuration,\n    Curve? curve,\n  }) {\n    return Navigator.of(overlayContext!, rootNavigator: useRootNavigator)\n        .push(GetModalBottomSheetRoute<T>(\n      builder: (_) => bottomsheet,\n      isPersistent: persistent,\n      // theme: Theme.of(key.currentContext, shadowThemeOnly: true),\n      theme: Theme.of(key.currentContext!),\n      isScrollControlled: isScrollControlled,\n\n      barrierLabel: MaterialLocalizations.of(key.currentContext!)\n          .modalBarrierDismissLabel,\n\n      backgroundColor: backgroundColor ?? Colors.transparent,\n      elevation: elevation,\n      shape: shape,\n      removeTop: ignoreSafeArea ?? true,\n      clipBehavior: clipBehavior,\n      isDismissible: isDismissible,\n      modalBarrierColor: barrierColor,\n      settings: settings,\n      enableDrag: enableDrag,\n      enterBottomSheetDuration:\n          enterBottomSheetDuration ?? const Duration(milliseconds: 250),\n      exitBottomSheetDuration:\n          exitBottomSheetDuration ?? const Duration(milliseconds: 200),\n      curve: curve,\n    ));\n  }\n}\n\nextension ExtensionDialog on GetInterface {\n  /// Show a dialog.\n  /// You can pass a [transitionDuration] and/or [transitionCurve],\n  /// overriding the defaults when the dialog shows up and closes.\n  /// When the dialog closes, uses those animations in reverse.\n  Future<T?> dialog<T>(\n    Widget widget, {\n    bool barrierDismissible = true,\n    Color? barrierColor,\n    bool useSafeArea = true,\n    GlobalKey<NavigatorState>? navigatorKey,\n    Object? arguments,\n    Duration? transitionDuration,\n    Curve? transitionCurve,\n    String? name,\n    RouteSettings? routeSettings,\n    String? id,\n  }) {\n    assert(debugCheckHasMaterialLocalizations(context!));\n\n    //  final theme = Theme.of(context, shadowThemeOnly: true);\n    final theme = Theme.of(context!);\n    return generalDialog<T>(\n      pageBuilder: (buildContext, animation, secondaryAnimation) {\n        final pageChild = widget;\n        Widget dialog = Builder(builder: (context) {\n          return Theme(data: theme, child: pageChild);\n        });\n        if (useSafeArea) {\n          dialog = SafeArea(child: dialog);\n        }\n        return dialog;\n      },\n      barrierDismissible: barrierDismissible,\n      barrierLabel: MaterialLocalizations.of(context!).modalBarrierDismissLabel,\n      barrierColor: barrierColor ?? Colors.black54,\n      transitionDuration: transitionDuration ?? defaultDialogTransitionDuration,\n      transitionBuilder: (context, animation, secondaryAnimation, child) {\n        return FadeTransition(\n          opacity: CurvedAnimation(\n            parent: animation,\n            curve: transitionCurve ?? defaultDialogTransitionCurve,\n          ),\n          child: child,\n        );\n      },\n      navigatorKey: navigatorKey,\n      routeSettings:\n          routeSettings ?? RouteSettings(arguments: arguments, name: name),\n      id: id,\n    );\n  }\n\n  /// Api from showGeneralDialog with no context\n  Future<T?> generalDialog<T>(\n      {required RoutePageBuilder pageBuilder,\n      bool barrierDismissible = false,\n      String? barrierLabel,\n      Color barrierColor = const Color(0x80000000),\n      Duration transitionDuration = const Duration(milliseconds: 200),\n      RouteTransitionsBuilder? transitionBuilder,\n      GlobalKey<NavigatorState>? navigatorKey,\n      RouteSettings? routeSettings,\n      String? id}) {\n    assert(!barrierDismissible || barrierLabel != null);\n    final key = navigatorKey ?? Get.nestedKey(id)?.navigatorKey;\n    final nav = key?.currentState ??\n        Navigator.of(overlayContext!,\n            rootNavigator:\n                true); //overlay context will always return the root navigator\n    return nav.push<T>(\n      GetDialogRoute<T>(\n        pageBuilder: pageBuilder,\n        barrierDismissible: barrierDismissible,\n        barrierLabel: barrierLabel,\n        barrierColor: barrierColor,\n        transitionDuration: transitionDuration,\n        transitionBuilder: transitionBuilder,\n        settings: routeSettings,\n      ),\n    );\n  }\n\n  /// Custom UI Dialog.\n  Future<T?> defaultDialog<T>({\n    String title = \"Alert\",\n    EdgeInsetsGeometry? titlePadding,\n    TextStyle? titleStyle,\n    Widget? content,\n    String? id,\n    EdgeInsetsGeometry? contentPadding,\n    VoidCallback? onConfirm,\n    VoidCallback? onCancel,\n    VoidCallback? onCustom,\n    Color? cancelTextColor,\n    Color? confirmTextColor,\n    String? textConfirm,\n    String? textCancel,\n    String? textCustom,\n    Widget? confirm,\n    Widget? cancel,\n    Widget? custom,\n    Color? backgroundColor,\n    bool barrierDismissible = true,\n    Color? buttonColor,\n    String middleText = \"\\n\",\n    TextStyle? middleTextStyle,\n    double radius = 20.0,\n    //   ThemeData themeData,\n    List<Widget>? actions,\n\n    // onWillPop Scope\n    PopInvokedWithResultCallback<T>? onWillPop,\n\n    // the navigator used to push the dialog\n    GlobalKey<NavigatorState>? navigatorKey,\n  }) {\n    var leanCancel = onCancel != null || textCancel != null;\n    var leanConfirm = onConfirm != null || textConfirm != null;\n    actions ??= [];\n\n    if (cancel != null) {\n      actions.add(cancel);\n    } else {\n      if (leanCancel) {\n        actions.add(TextButton(\n          style: TextButton.styleFrom(\n            tapTargetSize: MaterialTapTargetSize.shrinkWrap,\n            padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 8),\n            shape: RoundedRectangleBorder(\n                side: BorderSide(\n                    color: buttonColor ?? theme.colorScheme.secondary,\n                    width: 2,\n                    style: BorderStyle.solid),\n                borderRadius: BorderRadius.circular(radius)),\n          ),\n          onPressed: () {\n            if (onCancel == null) {\n              //TODO: Close current dialog after api change\n              closeAllDialogs();\n            } else {\n              onCancel.call();\n            }\n          },\n          child: Text(\n            textCancel ?? \"Cancel\",\n            style: TextStyle(\n                color: cancelTextColor ?? theme.colorScheme.secondary),\n          ),\n        ));\n      }\n    }\n    if (confirm != null) {\n      actions.add(confirm);\n    } else {\n      if (leanConfirm) {\n        actions.add(TextButton(\n            style: TextButton.styleFrom(\n              tapTargetSize: MaterialTapTargetSize.shrinkWrap,\n              backgroundColor: buttonColor ?? theme.colorScheme.secondary,\n              shape: RoundedRectangleBorder(\n                  borderRadius: BorderRadius.circular(radius)),\n            ),\n            child: Text(\n              textConfirm ?? \"Ok\",\n              style: TextStyle(\n                  color: confirmTextColor ?? theme.colorScheme.surface),\n            ),\n            onPressed: () {\n              onConfirm?.call();\n            }));\n      }\n    }\n\n    Widget baseAlertDialog = Builder(builder: (context) {\n      return AlertDialog(\n        titlePadding: titlePadding ?? const EdgeInsets.all(8),\n        contentPadding: contentPadding ?? const EdgeInsets.all(8),\n\n        backgroundColor:\n            backgroundColor ?? DialogTheme.of(context).backgroundColor,\n        shape: RoundedRectangleBorder(\n            borderRadius: BorderRadius.all(Radius.circular(radius))),\n        title: Text(title, textAlign: TextAlign.center, style: titleStyle),\n        content: Column(\n          crossAxisAlignment: CrossAxisAlignment.center,\n          mainAxisSize: MainAxisSize.min,\n          children: [\n            content ??\n                Text(middleText,\n                    textAlign: TextAlign.center, style: middleTextStyle),\n            const SizedBox(height: 16),\n            ButtonTheme(\n              minWidth: 78.0,\n              height: 34.0,\n              child: Wrap(\n                alignment: WrapAlignment.center,\n                spacing: 8,\n                runSpacing: 8,\n                children: actions!,\n              ),\n            )\n          ],\n        ),\n        // actions: actions, // ?? <Widget>[cancelButton, confirmButton],\n        buttonPadding: EdgeInsets.zero,\n      );\n    });\n\n    return dialog<T>(\n      onWillPop != null\n          ? PopScope<T>(\n              onPopInvokedWithResult: (didPop, result) =>\n                  onWillPop(didPop, result),\n              // onPopInvoked: onWillPop,\n              child: baseAlertDialog,\n            )\n          : baseAlertDialog,\n      barrierDismissible: barrierDismissible,\n      navigatorKey: navigatorKey,\n      id: id,\n    );\n  }\n}\n\nextension ExtensionSnackbar on GetInterface {\n  SnackbarController rawSnackbar({\n    String? title,\n    String? message,\n    Widget? titleText,\n    Widget? messageText,\n    Widget? icon,\n    bool instantInit = true,\n    bool shouldIconPulse = true,\n    double? maxWidth,\n    EdgeInsets margin = const EdgeInsets.all(0.0),\n    EdgeInsets padding = const EdgeInsets.all(16),\n    double borderRadius = 0.0,\n    Color? borderColor,\n    double borderWidth = 1.0,\n    Color backgroundColor = const Color(0xFF303030),\n    Color? leftBarIndicatorColor,\n    List<BoxShadow>? boxShadows,\n    Gradient? backgroundGradient,\n    Widget? mainButton,\n    OnTap? onTap,\n    Duration? duration = const Duration(seconds: 3),\n    bool isDismissible = true,\n    DismissDirection? dismissDirection,\n    bool showProgressIndicator = false,\n    AnimationController? progressIndicatorController,\n    Color? progressIndicatorBackgroundColor,\n    Animation<Color>? progressIndicatorValueColor,\n    SnackPosition snackPosition = SnackPosition.bottom,\n    SnackStyle snackStyle = SnackStyle.floating,\n    Curve forwardAnimationCurve = Curves.easeOutCirc,\n    Curve reverseAnimationCurve = Curves.easeOutCirc,\n    Duration animationDuration = const Duration(seconds: 1),\n    SnackbarStatusCallback? snackbarStatus,\n    double barBlur = 0.0,\n    double overlayBlur = 0.0,\n    Color? overlayColor,\n    Form? userInputForm,\n  }) {\n    final getSnackBar = GetSnackBar(\n      snackbarStatus: snackbarStatus,\n      title: title,\n      message: message,\n      titleText: titleText,\n      messageText: messageText,\n      snackPosition: snackPosition,\n      borderRadius: borderRadius,\n      margin: margin,\n      duration: duration,\n      barBlur: barBlur,\n      backgroundColor: backgroundColor,\n      icon: icon,\n      shouldIconPulse: shouldIconPulse,\n      maxWidth: maxWidth,\n      padding: padding,\n      borderColor: borderColor,\n      borderWidth: borderWidth,\n      leftBarIndicatorColor: leftBarIndicatorColor,\n      boxShadows: boxShadows,\n      backgroundGradient: backgroundGradient,\n      mainButton: mainButton,\n      onTap: onTap,\n      isDismissible: isDismissible,\n      dismissDirection: dismissDirection,\n      showProgressIndicator: showProgressIndicator,\n      progressIndicatorController: progressIndicatorController,\n      progressIndicatorBackgroundColor: progressIndicatorBackgroundColor,\n      progressIndicatorValueColor: progressIndicatorValueColor,\n      snackStyle: snackStyle,\n      forwardAnimationCurve: forwardAnimationCurve,\n      reverseAnimationCurve: reverseAnimationCurve,\n      animationDuration: animationDuration,\n      overlayBlur: overlayBlur,\n      overlayColor: overlayColor,\n      userInputForm: userInputForm,\n    );\n\n    final controller = SnackbarController(getSnackBar);\n\n    if (instantInit) {\n      controller.show();\n    } else {\n      Engine.instance.addPostFrameCallback((_) {\n        controller.show();\n      });\n    }\n    return controller;\n  }\n\n  SnackbarController showSnackbar(GetSnackBar snackbar) {\n    final controller = SnackbarController(snackbar);\n    controller.show();\n    return controller;\n  }\n\n  SnackbarController snackbar(\n    String title,\n    String message, {\n    Color? colorText,\n    Duration? duration = const Duration(seconds: 3),\n\n    /// with instantInit = false you can put snackbar on initState\n    bool instantInit = true,\n    SnackPosition? snackPosition,\n    Widget? titleText,\n    Widget? messageText,\n    Widget? icon,\n    bool? shouldIconPulse,\n    double? maxWidth,\n    EdgeInsets? margin,\n    EdgeInsets? padding,\n    double? borderRadius,\n    Color? borderColor,\n    double? borderWidth,\n    Color? backgroundColor,\n    Color? leftBarIndicatorColor,\n    List<BoxShadow>? boxShadows,\n    Gradient? backgroundGradient,\n    TextButton? mainButton,\n    OnTap? onTap,\n    OnHover? onHover,\n    bool? isDismissible,\n    bool? showProgressIndicator,\n    DismissDirection? dismissDirection,\n    AnimationController? progressIndicatorController,\n    Color? progressIndicatorBackgroundColor,\n    Animation<Color>? progressIndicatorValueColor,\n    SnackStyle? snackStyle,\n    Curve? forwardAnimationCurve,\n    Curve? reverseAnimationCurve,\n    Duration? animationDuration,\n    double? barBlur,\n    double? overlayBlur,\n    SnackbarStatusCallback? snackbarStatus,\n    Color? overlayColor,\n    Form? userInputForm,\n  }) {\n    final getSnackBar = GetSnackBar(\n        snackbarStatus: snackbarStatus,\n        titleText: titleText ??\n            Text(\n              title,\n              style: TextStyle(\n                color: colorText ?? iconColor ?? Colors.black,\n                fontWeight: FontWeight.w800,\n                fontSize: 16,\n              ),\n            ),\n        messageText: messageText ??\n            Text(\n              message,\n              style: TextStyle(\n                color: colorText ?? iconColor ?? Colors.black,\n                fontWeight: FontWeight.w300,\n                fontSize: 14,\n              ),\n            ),\n        snackPosition: snackPosition ?? SnackPosition.top,\n        borderRadius: borderRadius ?? 15,\n        margin: margin ?? const EdgeInsets.symmetric(horizontal: 10),\n        duration: duration,\n        barBlur: barBlur ?? 7.0,\n        backgroundColor: backgroundColor ?? Colors.grey.withValues(alpha: 0.2),\n        icon: icon,\n        shouldIconPulse: shouldIconPulse ?? true,\n        maxWidth: maxWidth,\n        padding: padding ?? const EdgeInsets.all(16),\n        borderColor: borderColor,\n        borderWidth: borderWidth,\n        leftBarIndicatorColor: leftBarIndicatorColor,\n        boxShadows: boxShadows,\n        backgroundGradient: backgroundGradient,\n        mainButton: mainButton,\n        onTap: onTap,\n        onHover: onHover,\n        isDismissible: isDismissible ?? true,\n        dismissDirection: dismissDirection,\n        showProgressIndicator: showProgressIndicator ?? false,\n        progressIndicatorController: progressIndicatorController,\n        progressIndicatorBackgroundColor: progressIndicatorBackgroundColor,\n        progressIndicatorValueColor: progressIndicatorValueColor,\n        snackStyle: snackStyle ?? SnackStyle.floating,\n        forwardAnimationCurve: forwardAnimationCurve ?? Curves.easeOutCirc,\n        reverseAnimationCurve: reverseAnimationCurve ?? Curves.easeOutCirc,\n        animationDuration: animationDuration ?? const Duration(seconds: 1),\n        overlayBlur: overlayBlur ?? 0.0,\n        overlayColor: overlayColor ?? Colors.transparent,\n        userInputForm: userInputForm);\n\n    final controller = SnackbarController(getSnackBar);\n\n    if (instantInit) {\n      controller.show();\n    } else {\n      //routing.isSnackbar = true;\n      Engine.instance.addPostFrameCallback((_) {\n        controller.show();\n      });\n    }\n    return controller;\n  }\n}\n\nextension GetNavigationExt on GetInterface {\n  /// **Navigation.push()** shortcut.<br><br>\n  ///\n  /// Pushes a new `page` to the stack\n  ///\n  /// It has the advantage of not needing context,\n  /// so you can call from your business logic\n  ///\n  /// You can set a custom [transition], and a transition [duration].\n  ///\n  /// You can send any type of value to the other route in the [arguments].\n  ///\n  /// Just like native routing in Flutter, you can push a route\n  /// as a [fullscreenDialog],\n  ///\n  /// [id] is for when you are using nested navigation,\n  /// as explained in documentation\n  ///\n  /// If you want the same behavior of ios that pops a route when the user drag,\n  /// you can set [popGesture] to true\n  ///\n  /// If you're using the [BindingsInterface] api, you must define it here\n  ///\n  /// By default, GetX will prevent you from push a route that you already in,\n  /// if you want to push anyway, set [preventDuplicates] to false\n  Future<T?>? to<T extends Object?>(Widget Function() page,\n      {bool? opaque,\n      Transition? transition,\n      Curve? curve,\n      Duration? duration,\n      String? id,\n      String? routeName,\n      bool fullscreenDialog = false,\n      dynamic arguments,\n      List<BindingsInterface> bindings = const [],\n      bool preventDuplicates = true,\n      bool? popGesture,\n      bool showCupertinoParallax = true,\n      double Function(BuildContext context)? gestureWidth,\n      bool rebuildStack = true,\n      PreventDuplicateHandlingMode preventDuplicateHandlingMode =\n          PreventDuplicateHandlingMode.reorderRoutes}) {\n    return searchDelegate(id).to(\n      page,\n      opaque: opaque,\n      transition: transition,\n      curve: curve,\n      duration: duration,\n      id: id,\n      routeName: routeName,\n      fullscreenDialog: fullscreenDialog,\n      arguments: arguments,\n      bindings: bindings,\n      preventDuplicates: preventDuplicates,\n      popGesture: popGesture,\n      showCupertinoParallax: showCupertinoParallax,\n      gestureWidth: gestureWidth,\n      rebuildStack: rebuildStack,\n      preventDuplicateHandlingMode: preventDuplicateHandlingMode,\n    );\n  }\n\n//   GetPageBuilder _resolvePage(dynamic page, String method) {\n//     if (page is GetPageBuilder) {\n//       return page;\n//     } else if (page is Widget) {\n//       Get.log(\n//           '''WARNING, consider using: \"Get.$method(() => Page())\"\n//instead of \"Get.$method(Page())\".\n// Using a widget function instead of a widget fully guarantees that the widget\n//and its controllers will be removed from memory when they are no longer used.\n//       ''');\n//       return () => page;\n//     } else if (page is String) {\n//       throw '''Unexpected String,\n// use toNamed() instead''';\n//     } else {\n//       throw '''Unexpected format,\n// you can only use widgets and widget functions here''';\n//     }\n//   }\n\n  /// **Navigation.pushNamed()** shortcut.<br><br>\n  ///\n  /// Pushes a new named `page` to the stack.\n  ///\n  /// It has the advantage of not needing context, so you can call\n  /// from your business logic.\n  ///\n  /// You can send any type of value to the other route in the [arguments].\n  ///\n  /// [id] is for when you are using nested navigation,\n  /// as explained in documentation\n  ///\n  /// By default, GetX will prevent you from push a route that you already in,\n  /// if you want to push anyway, set [preventDuplicates] to false\n  ///\n  /// Note: Always put a slash on the route ('/page1'), to avoid unexpected errors\n  Future<T?>? toNamed<T>(\n    String page, {\n    dynamic arguments,\n    dynamic id,\n    bool preventDuplicates = true,\n    Map<String, String>? parameters,\n  }) {\n    // if (preventDuplicates && page == currentRoute) {\n    //   return null;\n    // }\n\n    if (parameters != null) {\n      final uri = Uri(path: page, queryParameters: parameters);\n      page = uri.toString();\n    }\n\n    return searchDelegate(id).toNamed(\n      page,\n      arguments: arguments,\n      id: id,\n      preventDuplicates: preventDuplicates,\n      parameters: parameters,\n    );\n  }\n\n  /// **Navigation.pushReplacementNamed()** shortcut.<br><br>\n  ///\n  /// Pop the current named `page` in the stack and push a new one in its place\n  ///\n  /// It has the advantage of not needing context, so you can call\n  /// from your business logic.\n  ///\n  /// You can send any type of value to the other route in the [arguments].\n  ///\n  /// [id] is for when you are using nested navigation,\n  /// as explained in documentation\n  ///\n  /// By default, GetX will prevent you from push a route that you already in,\n  /// if you want to push anyway, set [preventDuplicates] to false\n  ///\n  /// Note: Always put a slash on the route ('/page1'), to avoid unexpected errors\n  Future<T?>? offNamed<T>(\n    String page, {\n    dynamic arguments,\n    String? id,\n    Map<String, String>? parameters,\n  }) {\n    // if (preventDuplicates && page == currentRoute) {\n    //   return null;\n    // }\n\n    if (parameters != null) {\n      final uri = Uri(path: page, queryParameters: parameters);\n      page = uri.toString();\n    }\n    return searchDelegate(id).offNamed(\n      page,\n      arguments: arguments,\n      id: id,\n      // preventDuplicates: preventDuplicates,\n      parameters: parameters,\n    );\n  }\n\n  /// **Navigation.popUntil()** shortcut.<br><br>\n  ///\n  /// Calls pop several times in the stack until [predicate] returns true\n  ///\n  /// [id] is for when you are using nested navigation,\n  /// as explained in documentation\n  ///\n  /// [predicate] can be used like this:\n  /// `Get.until((route) => Get.currentRoute == '/home')`so when you get to home page,\n  ///\n  /// or also like this:\n  /// `Get.until((route) => !Get.isDialogOpen())`, to make sure the\n  /// dialog is closed\n  void until(bool Function(GetPage<dynamic>) predicate, {String? id}) {\n    // if (key.currentState.mounted) // add this if appear problems on future with route navigate\n    // when widget don't mounted\n    return searchDelegate(id).backUntil(predicate);\n  }\n\n  /// **Navigation.pushNamedAndRemoveUntil()** shortcut.<br><br>\n  ///\n  /// Push the given named `page`, and then pop several pages in the stack\n  /// until [predicate] returns true\n  ///\n  /// You can send any type of value to the other route in the [arguments].\n  ///\n  /// [id] is for when you are using nested navigation,\n  /// as explained in documentation\n  ///\n  /// [predicate] can be used like this:\n  /// `Get.offNamedUntil(page, ModalRoute.withName('/home'))`\n  /// to pop routes in stack until home,\n  /// or like this:\n  /// `Get.offNamedUntil((route) => !Get.isDialogOpen())`,\n  /// to make sure the dialog is closed\n  ///\n  /// Note: Always put a slash on the route name ('/page1'), to avoid unexpected errors\n  Future<T?>? offNamedUntil<T>(\n    String page,\n    bool Function(GetPage<dynamic>)? predicate, {\n    String? id,\n    dynamic arguments,\n    Map<String, String>? parameters,\n  }) {\n    if (parameters != null) {\n      final uri = Uri(path: page, queryParameters: parameters);\n      page = uri.toString();\n    }\n\n    return searchDelegate(id).offNamedUntil<T>(\n      page,\n      predicate: predicate,\n      id: id,\n      arguments: arguments,\n      parameters: parameters,\n    );\n  }\n\n  /// **Navigation.popAndPushNamed()** shortcut.<br><br>\n  ///\n  /// Pop the current named page and pushes a new `page` to the stack\n  /// in its place\n  ///\n  /// You can send any type of value to the other route in the [arguments].\n  /// It is very similar to `offNamed()` but use a different approach\n  ///\n  /// The `offNamed()` pop a page, and goes to the next. The\n  /// `offAndToNamed()` goes to the next page, and removes the previous one.\n  /// The route transition animation is different.\n  Future<T?>? offAndToNamed<T>(\n    String page, {\n    dynamic arguments,\n    String? id,\n    dynamic result,\n    Map<String, String>? parameters,\n  }) {\n    if (parameters != null) {\n      final uri = Uri(path: page, queryParameters: parameters);\n      page = uri.toString();\n    }\n    return searchDelegate(id).backAndtoNamed(\n      page,\n      arguments: arguments,\n      result: result,\n    );\n  }\n\n  /// **Navigation.removeRoute()** shortcut.<br><br>\n  ///\n  /// Remove a specific [route] from the stack\n  ///\n  /// [id] is for when you are using nested navigation,\n  /// as explained in documentation\n  void removeRoute(String name, {String? id}) {\n    return searchDelegate(id).removeRoute(name);\n  }\n\n  /// **Navigation.pushNamedAndRemoveUntil()** shortcut.<br><br>\n  ///\n  /// Push a named `page` and pop several pages in the stack\n  /// until [predicate] returns true. [predicate] is optional\n  ///\n  /// It has the advantage of not needing context, so you can\n  /// call from your business logic.\n  ///\n  /// You can send any type of value to the other route in the [arguments].\n  ///\n  /// [predicate] can be used like this:\n  /// `Get.until((route) => Get.currentRoute == '/home')`so when you get to home page,\n  /// or also like\n  /// `Get.until((route) => !Get.isDialogOpen())`, to make sure the dialog\n  /// is closed\n  ///\n  /// [id] is for when you are using nested navigation,\n  /// as explained in documentation\n  ///\n  /// Note: Always put a slash on the route ('/page1'), to avoid unexpected errors\n  Future<T?>? offAllNamed<T>(\n    String newRouteName, {\n    // bool Function(GetPage<dynamic>)? predicate,\n    dynamic arguments,\n    String? id,\n    Map<String, String>? parameters,\n  }) {\n    if (parameters != null) {\n      final uri = Uri(path: newRouteName, queryParameters: parameters);\n      newRouteName = uri.toString();\n    }\n\n    return searchDelegate(id).offAllNamed<T>(\n      newRouteName,\n      //predicate: predicate ?? (_) => false,\n      arguments: arguments,\n      id: id,\n      parameters: parameters,\n    );\n  }\n\n  /// Returns true if a Snackbar, Dialog or BottomSheet is currently OPEN\n  bool get isOverlaysOpen =>\n      (isSnackbarOpen || isDialogOpen! || isBottomSheetOpen!);\n\n  /// Returns true if there is no Snackbar, Dialog or BottomSheet open\n  bool get isOverlaysClosed =>\n      (!isSnackbarOpen && !isDialogOpen! && !isBottomSheetOpen!);\n\n  /// **Navigation.popUntil()** shortcut.<br><br>\n  ///\n  /// Pop the current page, snackbar, dialog or bottomsheet in the stack\n  ///\n  /// if your set [closeOverlays] to true, Get.back() will close the\n  /// currently open snackbar/dialog/bottomsheet AND the current page\n  ///\n  /// [id] is for when you are using nested navigation,\n  /// as explained in documentation\n  ///\n  /// It has the advantage of not needing context, so you can call\n  /// from your business logic.\n  void back<T>({\n    T? result,\n    bool canPop = true,\n    int times = 1,\n    String? id,\n  }) {\n    if (times < 1) {\n      times = 1;\n    }\n\n    if (times > 1) {\n      var count = 0;\n      return searchDelegate(id).backUntil((route) => count++ == times);\n    } else {\n      if (canPop) {\n        if (searchDelegate(id).canBack == true) {\n          return searchDelegate(id).back<T>(result);\n        }\n      } else {\n        return searchDelegate(id).back<T>(result);\n      }\n    }\n  }\n\n  /// Pop the current page, snackbar, dialog or bottomsheet in the stack\n  ///\n  /// if your set [closeOverlays] to true, Get.back() will close the\n  /// currently open snackbar/dialog/bottomsheet AND the current page\n  ///\n  /// [id] is for when you are using nested navigation,\n  /// as explained in documentation\n  ///\n  /// It has the advantage of not needing context, so you can call\n  /// from your business logic.\n  void backLegacy<T>({\n    T? result,\n    bool closeOverlays = false,\n    bool canPop = true,\n    int times = 1,\n    String? id,\n  }) {\n    if (closeOverlays) {\n      closeAllOverlays();\n    }\n\n    if (times < 1) {\n      times = 1;\n    }\n\n    if (times > 1) {\n      var count = 0;\n      return searchDelegate(id).navigatorKey.currentState?.popUntil((route) {\n        return count++ == times;\n      });\n    } else {\n      if (canPop) {\n        if (searchDelegate(id).navigatorKey.currentState?.canPop() == true) {\n          return searchDelegate(id).navigatorKey.currentState?.pop<T>(result);\n        }\n      } else {\n        return searchDelegate(id).navigatorKey.currentState?.pop<T>(result);\n      }\n    }\n  }\n\n  void closeAllDialogsAndBottomSheets(\n    String? id,\n  ) {\n    // It can not be divided, because dialogs and bottomsheets can not be consecutive\n    while ((isDialogOpen! && isBottomSheetOpen!)) {\n      closeOverlay(id: id);\n    }\n  }\n\n  void closeAllDialogs({\n    String? id,\n  }) {\n    while ((isDialogOpen!)) {\n      closeOverlay(id: id);\n    }\n  }\n\n  /// Close the currently open dialog, returning a [result], if provided\n  void closeDialog<T>({String? id, T? result}) {\n    // Stop if there is no dialog open\n    if (isDialogOpen == null || !isDialogOpen!) return;\n\n    closeOverlay(id: id, result: result);\n  }\n\n  void closeBottomSheet<T>({String? id, T? result}) {\n    // Stop if there is no bottomsheet open\n    if (isBottomSheetOpen == null || !isBottomSheetOpen!) return;\n\n    closeOverlay(id: id, result: result);\n  }\n\n  /// Close the current overlay returning the [result], if provided\n  void closeOverlay<T>({\n    String? id,\n    T? result,\n  }) {\n    searchDelegate(id).navigatorKey.currentState?.pop(result);\n  }\n\n  void closeAllBottomSheets({\n    String? id,\n  }) {\n    while ((isBottomSheetOpen!)) {\n      searchDelegate(id).navigatorKey.currentState?.pop();\n    }\n  }\n\n  void closeAllOverlays() {\n    closeAllDialogsAndBottomSheets(null);\n    closeAllSnackbars();\n  }\n\n  /// **Navigation.popUntil()** (with predicate) shortcut .<br><br>\n  ///\n  /// Close as many routes as defined by [times]\n  ///\n  /// [id] is for when you are using nested navigation,\n  /// as explained in documentation\n  void close<T extends Object>({\n    bool closeAll = true,\n    bool closeSnackbar = true,\n    bool closeDialog = true,\n    bool closeBottomSheet = true,\n    String? id,\n    T? result,\n  }) {\n    void handleClose(bool closeCondition, Function closeAllFunction,\n        Function closeSingleFunction,\n        [bool? isOpenCondition]) {\n      if (closeCondition) {\n        if (closeAll) {\n          closeAllFunction();\n        } else if (isOpenCondition == true) {\n          closeSingleFunction();\n        }\n      }\n    }\n\n    handleClose(closeSnackbar, closeAllSnackbars, closeCurrentSnackbar);\n    handleClose(closeDialog, closeAllDialogs, closeOverlay, isDialogOpen);\n    handleClose(closeBottomSheet, closeAllBottomSheets, closeOverlay,\n        isBottomSheetOpen);\n  }\n\n  /// **Navigation.pushReplacement()** shortcut .<br><br>\n  ///\n  /// Pop the current page and pushes a new `page` to the stack\n  ///\n  /// It has the advantage of not needing context,\n  /// so you can call from your business logic\n  ///\n  /// You can set a custom [transition], define a Tween [curve],\n  /// and a transition [duration].\n  ///\n  /// You can send any type of value to the other route in the [arguments].\n  ///\n  /// Just like native routing in Flutter, you can push a route\n  /// as a [fullscreenDialog],\n  ///\n  /// [id] is for when you are using nested navigation,\n  /// as explained in documentation\n  ///\n  /// If you want the same behavior of ios that pops a route when the user drag,\n  /// you can set [popGesture] to true\n  ///\n  /// If you're using the [BindingsInterface] api, you must define it here\n  ///\n  /// By default, GetX will prevent you from push a route that you already in,\n  /// if you want to push anyway, set [preventDuplicates] to false\n  Future<T?>? off<T>(\n    Widget Function() page, {\n    bool? opaque,\n    Transition? transition,\n    Curve? curve,\n    bool? popGesture,\n    String? id,\n    String? routeName,\n    dynamic arguments,\n    List<BindingsInterface> bindings = const [],\n    bool fullscreenDialog = false,\n    bool preventDuplicates = true,\n    Duration? duration,\n    double Function(BuildContext context)? gestureWidth,\n  }) {\n    routeName ??= \"/${page.runtimeType.toString()}\";\n    routeName = _cleanRouteName(routeName);\n    if (preventDuplicates && routeName == currentRoute) {\n      return null;\n    }\n    return searchDelegate(id).off(\n      page,\n      opaque: opaque ?? true,\n      transition: transition,\n      curve: curve,\n      popGesture: popGesture,\n      id: id,\n      routeName: routeName,\n      arguments: arguments,\n      bindings: bindings,\n      fullscreenDialog: fullscreenDialog,\n      preventDuplicates: preventDuplicates,\n      duration: duration,\n      gestureWidth: gestureWidth,\n    );\n  }\n\n  Future<T?> offUntil<T>(\n    Widget Function() page,\n    bool Function(GetPage) predicate, [\n    Object? arguments,\n    String? id,\n  ]) {\n    return searchDelegate(id).offUntil(\n      page,\n      predicate,\n      arguments,\n    );\n  }\n\n  ///\n  /// Push a `page` and pop several pages in the stack\n  /// until [predicate] returns true. [predicate] is optional\n  ///\n  /// It has the advantage of not needing context,\n  /// so you can call from your business logic\n  ///\n  /// You can set a custom [transition], a [curve] and a transition [duration].\n  ///\n  /// You can send any type of value to the other route in the [arguments].\n  ///\n  /// Just like native routing in Flutter, you can push a route\n  /// as a [fullscreenDialog],\n  ///\n  /// [predicate] can be used like this:\n  /// `Get.until((route) => Get.currentRoute == '/home')`so when you get to home page,\n  /// or also like\n  /// `Get.until((route) => !Get.isDialogOpen())`, to make sure the dialog\n  /// is closed\n  ///\n  /// [id] is for when you are using nested navigation,\n  /// as explained in documentation\n  ///\n  /// If you want the same behavior of ios that pops a route when the user drag,\n  /// you can set [popGesture] to true\n  ///\n  /// If you're using the [BindingsInterface] api, you must define it here\n  ///\n  /// By default, GetX will prevent you from push a route that you already in,\n  /// if you want to push anyway, set [preventDuplicates] to false\n  Future<T?>? offAll<T>(\n    Widget Function() page, {\n    bool Function(GetPage<dynamic>)? predicate,\n    bool? opaque,\n    bool? popGesture,\n    String? id,\n    String? routeName,\n    dynamic arguments,\n    List<BindingsInterface> bindings = const [],\n    bool fullscreenDialog = false,\n    Transition? transition,\n    Curve? curve,\n    Duration? duration,\n    double Function(BuildContext context)? gestureWidth,\n  }) {\n    routeName ??= \"/${page.runtimeType.toString()}\";\n    routeName = _cleanRouteName(routeName);\n    return searchDelegate(id).offAll<T>(\n      page,\n      predicate: predicate,\n      opaque: opaque ?? true,\n      popGesture: popGesture,\n      id: id,\n      //  routeName routeName,\n      arguments: arguments,\n      bindings: bindings,\n      fullscreenDialog: fullscreenDialog,\n      transition: transition,\n      curve: curve,\n      duration: duration,\n      gestureWidth: gestureWidth,\n    );\n  }\n\n  /// Takes a route [name] String generated by [to], [off], [offAll]\n  /// (and similar context navigation methods), cleans the extra chars and\n  /// accommodates the format.\n  /// TODO: check for a more \"appealing\" URL naming convention.\n  /// `() => MyHomeScreenView` becomes `/my-home-screen-view`.\n  String _cleanRouteName(String name) {\n    name = name.replaceAll('() => ', '');\n\n    /// uncomment for URL styling.\n    // name = name.paramCase!;\n    if (!name.startsWith('/')) {\n      name = '/$name';\n    }\n    return Uri.tryParse(name)?.toString() ?? name;\n  }\n  //TODO: Deprecated\n  // /// change default config of Get\n  // void config(\n  //     {bool? enableLog,\n  //     LogWriterCallback? logWriterCallback,\n  //     bool? defaultPopGesture,\n  //     bool? defaultOpaqueRoute,\n  //     Duration? defaultDurationTransition,\n  //     bool? defaultGlobalState,\n  //     Transition? defaultTransition}) {\n  //   if (enableLog != null) {\n  //     Get.isLogEnable = enableLog;\n  //   }\n  //   if (logWriterCallback != null) {\n  //     Get.log = logWriterCallback;\n  //   }\n  //   if (defaultPopGesture != null) {\n  //     _getxController.defaultPopGesture = defaultPopGesture;\n  //   }\n  //   if (defaultOpaqueRoute != null) {\n  //     _getxController.defaultOpaqueRoute = defaultOpaqueRoute;\n  //   }\n  //   if (defaultTransition != null) {\n  //     _getxController.defaultTransition = defaultTransition;\n  //   }\n\n  //   if (defaultDurationTransition != null) {\n  //     _getxController.defaultTransitionDuration = defaultDurationTransition;\n  //   }\n  // }\n\n  Future<void> updateLocale(Locale l) async {\n    Get.locale = l;\n    await forceAppUpdate();\n  }\n\n  /// As a rule, Flutter knows which widget to update,\n  /// so this command is rarely needed. We can mention situations\n  /// where you use const so that widgets are not updated with setState,\n  /// but you want it to be forcefully updated when an event like\n  /// language change happens. using context to make the widget dirty\n  /// for performRebuild() is a viable solution.\n  /// However, in situations where this is not possible, or at least,\n  /// is not desired by the developer, the only solution for updating\n  /// widgets that Flutter does not want to update is to use reassemble\n  /// to forcibly rebuild all widgets. Attention: calling this function will\n  /// reconstruct the application from the sketch, use this with caution.\n  /// Your entire application will be rebuilt, and touch events will not\n  /// work until the end of rendering.\n  Future<void> forceAppUpdate() async {\n    await engine.performReassemble();\n  }\n\n  void appUpdate() => rootController.update();\n\n  void changeTheme(ThemeData theme) {\n    rootController.setTheme(theme);\n  }\n\n  void changeThemeMode(ThemeMode themeMode) {\n    rootController.setThemeMode(themeMode);\n  }\n\n  GlobalKey<NavigatorState>? addKey(GlobalKey<NavigatorState> newKey) {\n    return rootController.addKey(newKey);\n  }\n\n  GetDelegate? nestedKey(String? key) {\n    return rootController.nestedKey(key);\n  }\n\n  GetDelegate searchDelegate(String? k) {\n    GetDelegate key;\n    if (k == null) {\n      key = Get.rootController.rootDelegate;\n    } else {\n      if (!keys.containsKey(k)) {\n        throw 'Route id ($k) not found';\n      }\n      key = keys[k]!;\n    }\n\n    // if (_key.listenersLength == 0 && !testMode) {\n    //   throw \"\"\"You are trying to use contextless navigation without\n    //   a GetMaterialApp or Get.key.\n    //   If you are testing your app, you can use:\n    //   [Get.testMode = true], or if you are running your app on\n    //   a physical device or emulator, you must exchange your [MaterialApp]\n    //   for a [GetMaterialApp].\n    //   \"\"\";\n    // }\n\n    return key;\n  }\n\n  /// give name from current route\n  String get currentRoute => routing.current;\n\n  /// give name from previous route\n  String get previousRoute => routing.previous;\n\n  /// check if snackbar is open\n  bool get isSnackbarOpen =>\n      SnackbarController.isSnackbarBeingShown; //routing.isSnackbar;\n\n  void closeAllSnackbars() {\n    SnackbarController.cancelAllSnackbars();\n  }\n\n  Future<void> closeCurrentSnackbar() async {\n    await SnackbarController.closeCurrentSnackbar();\n  }\n\n  /// check if dialog is open\n  bool? get isDialogOpen => routing.isDialog;\n\n  /// check if bottomsheet is open\n  bool? get isBottomSheetOpen => routing.isBottomSheet;\n\n  /// check a raw current route\n  Route<dynamic>? get rawRoute => routing.route;\n\n  /// check if default opaque route is enable\n  bool get isOpaqueRouteDefault => defaultOpaqueRoute;\n\n  /// give access to currentContext\n  BuildContext? get context => key.currentContext;\n\n  /// give access to current Overlay Context\n  BuildContext? get overlayContext {\n    BuildContext? overlay;\n    key.currentState?.overlay?.context.visitChildElements((element) {\n      overlay = element;\n    });\n    return overlay;\n  }\n\n  /// give access to Theme.of(context)\n  ThemeData get theme {\n    var theme = ThemeData.fallback();\n    if (context != null) {\n      theme = Theme.of(context!);\n    }\n    return theme;\n  }\n\n  /// The current null safe [WidgetsBinding]\n  WidgetsBinding get engine {\n    return WidgetsFlutterBinding.ensureInitialized();\n  }\n\n  /// The window to which this binding is bound.\n  ui.PlatformDispatcher get window => engine.platformDispatcher;\n\n  Locale? get deviceLocale => window.locale;\n\n  ///The number of device pixels for each logical pixel.\n  double get pixelRatio => window.implicitView!.devicePixelRatio;\n\n  Size get size => window.implicitView!.physicalSize / pixelRatio;\n\n  ///The horizontal extent of this size.\n  double get width => size.width;\n\n  ///The vertical extent of this size\n  double get height => size.height;\n\n  ///The distance from the top edge to the first unpadded pixel,\n  ///in physical pixels.\n  double get statusBarHeight => window.implicitView!.padding.top;\n\n  ///The distance from the bottom edge to the first unpadded pixel,\n  ///in physical pixels.\n  double get bottomBarHeight => window.implicitView!.padding.bottom;\n\n  ///The system-reported text scale.\n  double get textScaleFactor => window.textScaleFactor;\n\n  /// give access to TextTheme.of(context)\n  TextTheme get textTheme => theme.textTheme;\n\n  /// give access to Mediaquery.of(context)\n  MediaQueryData get mediaQuery => MediaQuery.of(context!);\n\n  /// Check if dark mode theme is enable\n  bool get isDarkMode => (theme.brightness == Brightness.dark);\n\n  /// Check if dark mode theme is enable on platform on android Q+\n  bool get isPlatformDarkMode =>\n      (ui.PlatformDispatcher.instance.platformBrightness == Brightness.dark);\n\n  /// give access to Theme.of(context).iconTheme.color\n  Color? get iconColor => theme.iconTheme.color;\n\n  /// give access to FocusScope.of(context)\n  FocusNode? get focusScope => FocusManager.instance.primaryFocus;\n\n  // /// give access to Immutable MediaQuery.of(context).size.height\n  // double get height => MediaQuery.of(context).size.height;\n\n  // /// give access to Immutable MediaQuery.of(context).size.width\n  // double get width => MediaQuery.of(context).size.width;\n\n  GlobalKey<NavigatorState> get key => rootController.key;\n\n  Map<String, GetDelegate> get keys => rootController.keys;\n\n  GetRootState get rootController => GetRootState.controller;\n\n  ConfigData get _getxController => GetRootState.controller.config;\n\n  bool? get defaultPopGesture => _getxController.defaultPopGesture;\n  bool get defaultOpaqueRoute => _getxController.defaultOpaqueRoute;\n\n  Transition? get defaultTransition => _getxController.defaultTransition;\n\n  Duration get defaultTransitionDuration {\n    return _getxController.defaultTransitionDuration;\n  }\n\n  Curve get defaultTransitionCurve => _getxController.defaultTransitionCurve;\n\n  Curve get defaultDialogTransitionCurve {\n    return _getxController.defaultDialogTransitionCurve;\n  }\n\n  Duration get defaultDialogTransitionDuration {\n    return _getxController.defaultDialogTransitionDuration;\n  }\n\n  Routing get routing => _getxController.routing;\n\n  bool get _shouldUseMock => GetTestMode.active && !GetRoot.treeInitialized;\n\n  /// give current arguments\n  dynamic get arguments {\n    return args();\n  }\n\n  T args<T>() {\n    if (_shouldUseMock) {\n      return GetTestMode.arguments as T;\n    }\n    return rootController.rootDelegate.arguments<T>();\n  }\n\n  // set parameters(Map<String, String?> newParameters) {\n  //   rootController.parameters = newParameters;\n  // }\n\n  // @Deprecated('Use GetTestMode.active=true instead')\n  set testMode(bool isTest) => GetTestMode.active = isTest;\n\n  // @Deprecated('Use GetTestMode.active instead')\n  bool get testMode => GetTestMode.active;\n\n  Map<String, String?> get parameters {\n    if (_shouldUseMock) {\n      return GetTestMode.parameters;\n    }\n\n    return rootController.rootDelegate.parameters;\n  }\n\n  /// Casts the stored router delegate to a desired type\n  TDelegate? delegate<TDelegate extends RouterDelegate<TPage>, TPage>() =>\n      _getxController.routerDelegate as TDelegate?;\n}\n\nextension OverlayExt on GetInterface {\n  Future<T> showOverlay<T>({\n    required Future<T> Function() asyncFunction,\n    Color opacityColor = Colors.black,\n    Widget? loadingWidget,\n    double opacity = .5,\n  }) async {\n    final navigatorState =\n        Navigator.of(Get.overlayContext!, rootNavigator: false);\n    final overlayState = navigatorState.overlay!;\n\n    final overlayEntryOpacity = OverlayEntry(builder: (context) {\n      return Opacity(\n          opacity: opacity,\n          child: Container(\n            color: opacityColor,\n          ));\n    });\n    final overlayEntryLoader = OverlayEntry(builder: (context) {\n      return loadingWidget ??\n          const Center(\n              child: SizedBox(\n            height: 90,\n            width: 90,\n            child: Text('Loading...'),\n          ));\n    });\n    overlayState.insert(overlayEntryOpacity);\n    overlayState.insert(overlayEntryLoader);\n\n    T data;\n\n    try {\n      data = await asyncFunction();\n    } on Exception catch (_) {\n      overlayEntryLoader.remove();\n      overlayEntryOpacity.remove();\n      rethrow;\n    }\n\n    overlayEntryLoader.remove();\n    overlayEntryOpacity.remove();\n    return data;\n  }\n}\n"
  },
  {
    "path": "lib/get_navigation/src/root/get_cupertino_app.dart",
    "content": "import 'package:flutter/cupertino.dart';\nimport 'package:flutter/foundation.dart';\nimport 'package:flutter/material.dart';\n\nimport '../../../get_core/get_core.dart';\nimport '../../../get_instance/get_instance.dart';\nimport '../../../get_state_manager/get_state_manager.dart';\nimport '../../../get_utils/get_utils.dart';\nimport '../../get_navigation.dart';\nimport 'get_root.dart';\n\nclass GetCupertinoApp extends StatelessWidget {\n  final GlobalKey<NavigatorState>? navigatorKey;\n  final Widget? home;\n  final Map<String, WidgetBuilder>? routes;\n  final String? initialRoute;\n  final RouteFactory? onGenerateRoute;\n  final InitialRouteListFactory? onGenerateInitialRoutes;\n  final RouteFactory? onUnknownRoute;\n  final List<NavigatorObserver>? navigatorObservers;\n  final TransitionBuilder? builder;\n  final String title;\n  final GenerateAppTitle? onGenerateTitle;\n  final CustomTransition? customTransition;\n  final Color? color;\n  final Map<String, Map<String, String>>? translationsKeys;\n  final Translations? translations;\n  final TextDirection? textDirection;\n  final Locale? locale;\n  final Locale? fallbackLocale;\n  final Iterable<LocalizationsDelegate<dynamic>>? localizationsDelegates;\n  final LocaleListResolutionCallback? localeListResolutionCallback;\n  final LocaleResolutionCallback? localeResolutionCallback;\n  final Iterable<Locale> supportedLocales;\n  final bool showPerformanceOverlay;\n  final bool checkerboardRasterCacheImages;\n  final bool checkerboardOffscreenLayers;\n  final bool showSemanticsDebugger;\n  final bool debugShowCheckedModeBanner;\n  final Map<LogicalKeySet, Intent>? shortcuts;\n  final ThemeData? highContrastTheme;\n  final ThemeData? highContrastDarkTheme;\n  final Map<Type, Action<Intent>>? actions;\n  final Function(Routing?)? routingCallback;\n  final Transition? defaultTransition;\n  final bool? opaqueRoute;\n  final VoidCallback? onInit;\n  final VoidCallback? onReady;\n  final VoidCallback? onDispose;\n  final bool? enableLog;\n  final LogWriterCallback? logWriterCallback;\n  final bool? popGesture;\n  final SmartManagement smartManagement;\n  final BindingsInterface? initialBinding;\n  final Duration? transitionDuration;\n  final bool? defaultGlobalState;\n  final List<GetPage>? getPages;\n  final GetPage? unknownRoute;\n  final RouteInformationProvider? routeInformationProvider;\n  final RouteInformationParser<Object>? routeInformationParser;\n  final RouterDelegate<Object>? routerDelegate;\n  final RouterConfig<Object>? routerConfig;\n  final BackButtonDispatcher? backButtonDispatcher;\n  final CupertinoThemeData? theme;\n  final bool useInheritedMediaQuery;\n  final List<Bind> binds;\n  final ScrollBehavior? scrollBehavior;\n\n  const GetCupertinoApp({\n    super.key,\n    this.theme,\n    this.navigatorKey,\n    this.home,\n    Map<String, Widget Function(BuildContext)> this.routes =\n        const <String, WidgetBuilder>{},\n    this.initialRoute,\n    this.onGenerateRoute,\n    this.onGenerateInitialRoutes,\n    this.onUnknownRoute,\n    List<NavigatorObserver> this.navigatorObservers =\n        const <NavigatorObserver>[],\n    this.builder,\n    this.translationsKeys,\n    this.translations,\n    this.textDirection,\n    this.title = '',\n    this.onGenerateTitle,\n    this.color,\n    this.customTransition,\n    this.onInit,\n    this.onDispose,\n    this.locale,\n    this.binds = const [],\n    this.scrollBehavior,\n    this.fallbackLocale,\n    this.localizationsDelegates,\n    this.localeListResolutionCallback,\n    this.localeResolutionCallback,\n    this.supportedLocales = const <Locale>[Locale('en', 'US')],\n    this.showPerformanceOverlay = false,\n    this.checkerboardRasterCacheImages = false,\n    this.checkerboardOffscreenLayers = false,\n    this.showSemanticsDebugger = false,\n    this.debugShowCheckedModeBanner = true,\n    this.shortcuts,\n    this.smartManagement = SmartManagement.full,\n    this.initialBinding,\n    this.useInheritedMediaQuery = false,\n    this.unknownRoute,\n    this.routingCallback,\n    this.defaultTransition,\n    this.onReady,\n    this.getPages,\n    this.opaqueRoute,\n    this.enableLog = kDebugMode,\n    this.logWriterCallback,\n    this.popGesture,\n    this.transitionDuration,\n    this.defaultGlobalState,\n    this.highContrastTheme,\n    this.highContrastDarkTheme,\n    this.actions,\n  })  : routeInformationProvider = null,\n        backButtonDispatcher = null,\n        routeInformationParser = null,\n        routerDelegate = null,\n        routerConfig = null;\n\n  const GetCupertinoApp.router({\n    super.key,\n    this.theme,\n    this.routeInformationProvider,\n    this.routeInformationParser,\n    this.routerDelegate,\n    this.routerConfig,\n    this.backButtonDispatcher,\n    this.builder,\n    this.title = '',\n    this.onGenerateTitle,\n    this.useInheritedMediaQuery = false,\n    this.color,\n    this.highContrastTheme,\n    this.highContrastDarkTheme,\n    this.locale,\n    this.localizationsDelegates,\n    this.localeListResolutionCallback,\n    this.localeResolutionCallback,\n    this.supportedLocales = const <Locale>[Locale('en', 'US')],\n    this.showPerformanceOverlay = false,\n    this.checkerboardRasterCacheImages = false,\n    this.checkerboardOffscreenLayers = false,\n    this.showSemanticsDebugger = false,\n    this.debugShowCheckedModeBanner = true,\n    this.shortcuts,\n    this.binds = const [],\n    this.scrollBehavior,\n    this.actions,\n    this.customTransition,\n    this.translationsKeys,\n    this.translations,\n    this.textDirection,\n    this.fallbackLocale,\n    this.routingCallback,\n    this.defaultTransition,\n    this.opaqueRoute,\n    this.onInit,\n    this.onReady,\n    this.onDispose,\n    this.enableLog = kDebugMode,\n    this.logWriterCallback,\n    this.popGesture,\n    this.smartManagement = SmartManagement.full,\n    this.initialBinding,\n    this.transitionDuration,\n    this.defaultGlobalState,\n    this.getPages,\n    this.navigatorObservers,\n    this.unknownRoute,\n  })  : navigatorKey = null,\n        onGenerateRoute = null,\n        home = null,\n        onGenerateInitialRoutes = null,\n        onUnknownRoute = null,\n        routes = null,\n        initialRoute = null;\n\n  @override\n  Widget build(BuildContext context) {\n    return GetRoot(\n      config: ConfigData(\n        backButtonDispatcher: backButtonDispatcher,\n        binds: binds,\n        customTransition: customTransition,\n        defaultGlobalState: defaultGlobalState,\n        defaultTransition: defaultTransition,\n        enableLog: enableLog,\n        fallbackLocale: fallbackLocale,\n        getPages: getPages,\n        home: home,\n        initialRoute: initialRoute,\n        locale: locale,\n        logWriterCallback: logWriterCallback,\n        navigatorKey: navigatorKey,\n        navigatorObservers: navigatorObservers,\n        onDispose: onDispose,\n        onInit: onInit,\n        onReady: onReady,\n        routeInformationParser: routeInformationParser,\n        routeInformationProvider: routeInformationProvider,\n        routerDelegate: routerDelegate,\n        routingCallback: routingCallback,\n        scaffoldMessengerKey: GlobalKey<ScaffoldMessengerState>(),\n        smartManagement: smartManagement,\n        transitionDuration: transitionDuration,\n        translations: translations,\n        translationsKeys: translationsKeys,\n        unknownRoute: unknownRoute,\n        defaultPopGesture: popGesture,\n      ),\n      child: Builder(builder: (context) {\n        final controller = GetRoot.of(context);\n        return CupertinoApp.router(\n          routerDelegate: controller.config.routerDelegate,\n          routeInformationParser: controller.config.routeInformationParser,\n          backButtonDispatcher: backButtonDispatcher,\n          routeInformationProvider: routeInformationProvider,\n          routerConfig: routerConfig,\n          key: controller.config.unikey,\n          builder: (context, child) => Directionality(\n            textDirection: textDirection ??\n                (rtlLanguages.contains(Get.locale?.languageCode)\n                    ? TextDirection.rtl\n                    : TextDirection.ltr),\n            child: builder == null\n                ? (child ?? const Material())\n                : builder!(context, child ?? const Material()),\n          ),\n          title: title,\n          onGenerateTitle: onGenerateTitle,\n          color: color,\n          theme: theme,\n          locale: Get.locale ?? locale,\n          localizationsDelegates: localizationsDelegates,\n          localeListResolutionCallback: localeListResolutionCallback,\n          localeResolutionCallback: localeResolutionCallback,\n          supportedLocales: supportedLocales,\n          showPerformanceOverlay: showPerformanceOverlay,\n          checkerboardRasterCacheImages: checkerboardRasterCacheImages,\n          checkerboardOffscreenLayers: checkerboardOffscreenLayers,\n          showSemanticsDebugger: showSemanticsDebugger,\n          debugShowCheckedModeBanner: debugShowCheckedModeBanner,\n          shortcuts: shortcuts,\n          scrollBehavior: scrollBehavior,\n        );\n      }),\n    );\n  }\n}\n"
  },
  {
    "path": "lib/get_navigation/src/root/get_material_app.dart",
    "content": "import 'package:flutter/foundation.dart';\nimport 'package:flutter/material.dart';\nimport 'package:get/instance_manager.dart';\n\nimport '../../../get_state_manager/get_state_manager.dart';\nimport '../../../get_utils/get_utils.dart';\nimport '../../get_navigation.dart';\nimport 'get_root.dart';\n\nclass GetMaterialApp extends StatelessWidget {\n  final GlobalKey<NavigatorState>? navigatorKey;\n  final GlobalKey<ScaffoldMessengerState>? scaffoldMessengerKey;\n  final Widget? home;\n  final Map<String, WidgetBuilder>? routes;\n  final String? initialRoute;\n  final RouteFactory? onGenerateRoute;\n  final InitialRouteListFactory? onGenerateInitialRoutes;\n  final RouteFactory? onUnknownRoute;\n  final List<NavigatorObserver>? navigatorObservers;\n  final TransitionBuilder? builder;\n  final String title;\n  final GenerateAppTitle? onGenerateTitle;\n  final ThemeData? theme;\n  final ThemeData? darkTheme;\n  final ThemeMode themeMode;\n  final CustomTransition? customTransition;\n  final Color? color;\n  final Map<String, Map<String, String>>? translationsKeys;\n  final Translations? translations;\n  final TextDirection? textDirection;\n  final Locale? locale;\n  final Locale? fallbackLocale;\n  final Iterable<LocalizationsDelegate<dynamic>>? localizationsDelegates;\n  final LocaleListResolutionCallback? localeListResolutionCallback;\n  final LocaleResolutionCallback? localeResolutionCallback;\n  final Iterable<Locale> supportedLocales;\n  final bool showPerformanceOverlay;\n  final bool checkerboardRasterCacheImages;\n  final bool checkerboardOffscreenLayers;\n  final bool showSemanticsDebugger;\n  final bool debugShowCheckedModeBanner;\n  final Map<LogicalKeySet, Intent>? shortcuts;\n  final ScrollBehavior? scrollBehavior;\n  final ThemeData? highContrastTheme;\n  final ThemeData? highContrastDarkTheme;\n  final Map<Type, Action<Intent>>? actions;\n  final bool debugShowMaterialGrid;\n  final ValueChanged<Routing?>? routingCallback;\n  final Transition? defaultTransition;\n  final bool? opaqueRoute;\n  final VoidCallback? onInit;\n  final VoidCallback? onReady;\n  final VoidCallback? onDispose;\n  final bool? enableLog;\n  final LogWriterCallback? logWriterCallback;\n  final bool? popGesture;\n  final SmartManagement smartManagement;\n  final List<Bind> binds;\n  final Duration? transitionDuration;\n  final bool? defaultGlobalState;\n  final List<GetPage>? getPages;\n  final GetPage? unknownRoute;\n  final RouteInformationProvider? routeInformationProvider;\n  final RouteInformationParser<Object>? routeInformationParser;\n  final RouterDelegate<Object>? routerDelegate;\n  final RouterConfig<Object>? routerConfig;\n  final BackButtonDispatcher? backButtonDispatcher;\n  final bool useInheritedMediaQuery;\n\n  const GetMaterialApp({\n    super.key,\n    this.navigatorKey,\n    this.scaffoldMessengerKey,\n    this.home,\n    Map<String, Widget Function(BuildContext)> this.routes =\n        const <String, WidgetBuilder>{},\n    this.initialRoute,\n    this.onGenerateRoute,\n    this.onGenerateInitialRoutes,\n    this.onUnknownRoute,\n    this.useInheritedMediaQuery = false,\n    List<NavigatorObserver> this.navigatorObservers =\n        const <NavigatorObserver>[],\n    this.builder,\n    this.textDirection,\n    this.title = '',\n    this.onGenerateTitle,\n    this.color,\n    this.theme,\n    this.darkTheme,\n    this.themeMode = ThemeMode.system,\n    this.locale,\n    this.fallbackLocale,\n    this.localizationsDelegates,\n    this.localeListResolutionCallback,\n    this.localeResolutionCallback,\n    this.supportedLocales = const <Locale>[Locale('en', 'US')],\n    this.debugShowMaterialGrid = false,\n    this.showPerformanceOverlay = false,\n    this.checkerboardRasterCacheImages = false,\n    this.checkerboardOffscreenLayers = false,\n    this.showSemanticsDebugger = false,\n    this.debugShowCheckedModeBanner = true,\n    this.shortcuts,\n    this.scrollBehavior,\n    this.customTransition,\n    this.translationsKeys,\n    this.translations,\n    this.onInit,\n    this.onReady,\n    this.onDispose,\n    this.routingCallback,\n    this.defaultTransition,\n    this.getPages,\n    this.opaqueRoute,\n    this.enableLog = kDebugMode,\n    this.logWriterCallback,\n    this.popGesture,\n    this.transitionDuration,\n    this.defaultGlobalState,\n    this.smartManagement = SmartManagement.full,\n    this.binds = const [],\n    this.unknownRoute,\n    this.highContrastTheme,\n    this.highContrastDarkTheme,\n    this.actions,\n  })  : routeInformationProvider = null,\n        backButtonDispatcher = null,\n        routeInformationParser = null,\n        routerDelegate = null,\n        routerConfig = null;\n\n  const GetMaterialApp.router({\n    super.key,\n    this.routeInformationProvider,\n    this.scaffoldMessengerKey,\n    this.routeInformationParser,\n    this.routerDelegate,\n    this.routerConfig,\n    this.backButtonDispatcher,\n    this.builder,\n    this.title = '',\n    this.onGenerateTitle,\n    this.color,\n    this.theme,\n    this.darkTheme,\n    this.useInheritedMediaQuery = false,\n    this.highContrastTheme,\n    this.highContrastDarkTheme,\n    this.themeMode = ThemeMode.system,\n    this.locale,\n    this.localizationsDelegates,\n    this.localeListResolutionCallback,\n    this.localeResolutionCallback,\n    this.supportedLocales = const <Locale>[Locale('en', 'US')],\n    this.debugShowMaterialGrid = false,\n    this.showPerformanceOverlay = false,\n    this.checkerboardRasterCacheImages = false,\n    this.checkerboardOffscreenLayers = false,\n    this.showSemanticsDebugger = false,\n    this.debugShowCheckedModeBanner = true,\n    this.shortcuts,\n    this.scrollBehavior,\n    this.actions,\n    this.customTransition,\n    this.translationsKeys,\n    this.translations,\n    this.textDirection,\n    this.fallbackLocale,\n    this.routingCallback,\n    this.defaultTransition,\n    this.opaqueRoute,\n    this.onInit,\n    this.onReady,\n    this.onDispose,\n    this.enableLog = kDebugMode,\n    this.logWriterCallback,\n    this.popGesture,\n    this.smartManagement = SmartManagement.full,\n    this.binds = const [],\n    this.transitionDuration,\n    this.defaultGlobalState,\n    this.getPages,\n    this.navigatorObservers,\n    this.unknownRoute,\n  })  : navigatorKey = null,\n        onGenerateRoute = null,\n        home = null,\n        onGenerateInitialRoutes = null,\n        onUnknownRoute = null,\n        routes = null,\n        initialRoute = null;\n\n  @override\n  Widget build(BuildContext context) {\n    return GetRoot(\n      config: ConfigData(\n        backButtonDispatcher: backButtonDispatcher,\n        binds: binds,\n        customTransition: customTransition,\n        defaultGlobalState: defaultGlobalState,\n        defaultTransition: defaultTransition,\n        enableLog: enableLog,\n        fallbackLocale: fallbackLocale,\n        getPages: getPages,\n        home: home,\n        initialRoute: initialRoute,\n        locale: locale,\n        logWriterCallback: logWriterCallback,\n        navigatorKey: navigatorKey,\n        navigatorObservers: navigatorObservers,\n        onDispose: onDispose,\n        onInit: onInit,\n        onReady: onReady,\n        routeInformationParser: routeInformationParser,\n        routeInformationProvider: routeInformationProvider,\n        routerDelegate: routerDelegate,\n        routingCallback: routingCallback,\n        scaffoldMessengerKey: scaffoldMessengerKey,\n        smartManagement: smartManagement,\n        transitionDuration: transitionDuration,\n        translations: translations,\n        translationsKeys: translationsKeys,\n        unknownRoute: unknownRoute,\n        theme: theme,\n        darkTheme: darkTheme,\n        themeMode: themeMode,\n        defaultPopGesture: popGesture,\n      ),\n      // binds: [\n      //   Bind.lazyPut<GetMaterialController>(\n      //     () => GetMaterialController(\n\n      //     ),\n      //     onClose: () {\n      //       Get.clearTranslations();\n      //       RouterReportManager.dispose();\n      //       Get.resetInstance(clearRouteBindings: true);\n      //     },\n      //   ),\n      //   ...binds,\n      // ],\n      child: Builder(builder: (context) {\n        final controller = GetRoot.of(context);\n        return MaterialApp.router(\n          routerDelegate: controller.config.routerDelegate,\n          routeInformationParser: controller.config.routeInformationParser,\n          backButtonDispatcher: backButtonDispatcher,\n          routeInformationProvider: routeInformationProvider,\n          routerConfig: routerConfig,\n          key: controller.config.unikey,\n          builder: (context, child) => Directionality(\n            textDirection: textDirection ??\n                (rtlLanguages.contains(Get.locale?.languageCode)\n                    ? TextDirection.rtl\n                    : TextDirection.ltr),\n            child: builder == null\n                ? (child ?? const Material())\n                : builder!(context, child ?? const Material()),\n          ),\n          title: title,\n          onGenerateTitle: onGenerateTitle,\n          color: color,\n          theme: controller.config.theme ?? ThemeData.fallback(),\n          darkTheme: controller.config.darkTheme ??\n              controller.config.theme ??\n              ThemeData.fallback(),\n          themeMode: controller.config.themeMode,\n          locale: Get.locale ?? locale,\n          scaffoldMessengerKey: controller.config.scaffoldMessengerKey,\n          localizationsDelegates: localizationsDelegates,\n          localeListResolutionCallback: localeListResolutionCallback,\n          localeResolutionCallback: localeResolutionCallback,\n          supportedLocales: supportedLocales,\n          debugShowMaterialGrid: debugShowMaterialGrid,\n          showPerformanceOverlay: showPerformanceOverlay,\n          checkerboardRasterCacheImages: checkerboardRasterCacheImages,\n          checkerboardOffscreenLayers: checkerboardOffscreenLayers,\n          showSemanticsDebugger: showSemanticsDebugger,\n          debugShowCheckedModeBanner: debugShowCheckedModeBanner,\n          shortcuts: shortcuts,\n          scrollBehavior: scrollBehavior,\n        );\n      }),\n    );\n  }\n}\n"
  },
  {
    "path": "lib/get_navigation/src/root/get_root.dart",
    "content": "import 'package:flutter/foundation.dart';\nimport 'package:flutter/material.dart';\nimport 'package:get/get_navigation/src/routes/test_kit.dart';\n\nimport '../../../get.dart';\nimport '../router_report.dart';\n\nclass ConfigData {\n  final ValueChanged<Routing?>? routingCallback;\n  final Transition? defaultTransition;\n  final VoidCallback? onInit;\n  final VoidCallback? onReady;\n  final VoidCallback? onDispose;\n  final bool? enableLog;\n  final LogWriterCallback? logWriterCallback;\n  final SmartManagement smartManagement;\n  final List<Bind> binds;\n  final Duration? transitionDuration;\n  final bool? defaultGlobalState;\n  final List<GetPage>? getPages;\n  final GetPage? unknownRoute;\n  final RouteInformationProvider? routeInformationProvider;\n  final RouteInformationParser<Object>? routeInformationParser;\n  final RouterDelegate<Object>? routerDelegate;\n  final BackButtonDispatcher? backButtonDispatcher;\n  final List<NavigatorObserver>? navigatorObservers;\n  final GlobalKey<NavigatorState>? navigatorKey;\n  final GlobalKey<ScaffoldMessengerState>? scaffoldMessengerKey;\n  final Map<String, Map<String, String>>? translationsKeys;\n  final Translations? translations;\n  final Locale? locale;\n  final Locale? fallbackLocale;\n  final String? initialRoute;\n  final CustomTransition? customTransition;\n  final Widget? home;\n  final bool testMode;\n  final Key? unikey;\n  final ThemeData? theme;\n  final ThemeData? darkTheme;\n  final ThemeMode? themeMode;\n  final bool? defaultPopGesture;\n  final bool defaultOpaqueRoute;\n  final Duration defaultTransitionDuration;\n  final Curve defaultTransitionCurve;\n  final Curve defaultDialogTransitionCurve;\n  final Duration defaultDialogTransitionDuration;\n  final Routing routing;\n  final Map<String, String?> parameters;\n  final SnackBarQueue snackBarQueue = SnackBarQueue();\n\n  ConfigData({\n    required this.routingCallback,\n    required this.defaultTransition,\n    required this.onInit,\n    required this.onReady,\n    required this.onDispose,\n    required this.enableLog,\n    required this.logWriterCallback,\n    required this.smartManagement,\n    required this.binds,\n    required this.transitionDuration,\n    required this.defaultGlobalState,\n    required this.getPages,\n    required this.unknownRoute,\n    required this.routeInformationProvider,\n    required this.routeInformationParser,\n    required this.routerDelegate,\n    required this.backButtonDispatcher,\n    required this.navigatorObservers,\n    required this.navigatorKey,\n    required this.scaffoldMessengerKey,\n    required this.translationsKeys,\n    required this.translations,\n    required this.locale,\n    required this.fallbackLocale,\n    required this.initialRoute,\n    required this.customTransition,\n    required this.home,\n    this.theme,\n    this.darkTheme,\n    this.themeMode,\n    this.unikey,\n    this.testMode = false,\n    this.defaultOpaqueRoute = true,\n    this.defaultTransitionDuration = const Duration(milliseconds: 300),\n    this.defaultTransitionCurve = Curves.easeOutQuad,\n    this.defaultDialogTransitionCurve = Curves.easeOutQuad,\n    this.defaultDialogTransitionDuration = const Duration(milliseconds: 300),\n    this.parameters = const {},\n    required this.defaultPopGesture,\n    Routing? routing,\n  }) : routing = routing ?? Routing();\n\n  ConfigData copyWith({\n    ValueChanged<Routing?>? routingCallback,\n    Transition? defaultTransition,\n    VoidCallback? onInit,\n    VoidCallback? onReady,\n    VoidCallback? onDispose,\n    bool? enableLog,\n    LogWriterCallback? logWriterCallback,\n    SmartManagement? smartManagement,\n    List<Bind>? binds,\n    Duration? transitionDuration,\n    bool? defaultGlobalState,\n    List<GetPage>? getPages,\n    GetPage? unknownRoute,\n    RouteInformationProvider? routeInformationProvider,\n    RouteInformationParser<Object>? routeInformationParser,\n    RouterDelegate<Object>? routerDelegate,\n    BackButtonDispatcher? backButtonDispatcher,\n    List<NavigatorObserver>? navigatorObservers,\n    GlobalKey<NavigatorState>? navigatorKey,\n    GlobalKey<ScaffoldMessengerState>? scaffoldMessengerKey,\n    Map<String, Map<String, String>>? translationsKeys,\n    Translations? translations,\n    Locale? locale,\n    Locale? fallbackLocale,\n    String? initialRoute,\n    CustomTransition? customTransition,\n    Widget? home,\n    bool? testMode,\n    Key? unikey,\n    ThemeData? theme,\n    ThemeData? darkTheme,\n    ThemeMode? themeMode,\n    bool? defaultPopGesture,\n    bool? defaultOpaqueRoute,\n    Duration? defaultTransitionDuration,\n    Curve? defaultTransitionCurve,\n    Curve? defaultDialogTransitionCurve,\n    Duration? defaultDialogTransitionDuration,\n    Routing? routing,\n    Map<String, String?>? parameters,\n  }) {\n    return ConfigData(\n      routingCallback: routingCallback ?? this.routingCallback,\n      defaultTransition: defaultTransition ?? this.defaultTransition,\n      onInit: onInit ?? this.onInit,\n      onReady: onReady ?? this.onReady,\n      onDispose: onDispose ?? this.onDispose,\n      enableLog: enableLog ?? this.enableLog,\n      logWriterCallback: logWriterCallback ?? this.logWriterCallback,\n      smartManagement: smartManagement ?? this.smartManagement,\n      binds: binds ?? this.binds,\n      transitionDuration: transitionDuration ?? this.transitionDuration,\n      defaultGlobalState: defaultGlobalState ?? this.defaultGlobalState,\n      getPages: getPages ?? this.getPages,\n      unknownRoute: unknownRoute ?? this.unknownRoute,\n      routeInformationProvider:\n          routeInformationProvider ?? this.routeInformationProvider,\n      routeInformationParser:\n          routeInformationParser ?? this.routeInformationParser,\n      routerDelegate: routerDelegate ?? this.routerDelegate,\n      backButtonDispatcher: backButtonDispatcher ?? this.backButtonDispatcher,\n      navigatorObservers: navigatorObservers ?? this.navigatorObservers,\n      navigatorKey: navigatorKey ?? this.navigatorKey,\n      scaffoldMessengerKey: scaffoldMessengerKey ?? this.scaffoldMessengerKey,\n      translationsKeys: translationsKeys ?? this.translationsKeys,\n      translations: translations ?? this.translations,\n      locale: locale ?? this.locale,\n      fallbackLocale: fallbackLocale ?? this.fallbackLocale,\n      initialRoute: initialRoute ?? this.initialRoute,\n      customTransition: customTransition ?? this.customTransition,\n      home: home ?? this.home,\n      testMode: testMode ?? this.testMode,\n      unikey: unikey ?? this.unikey,\n      theme: theme ?? this.theme,\n      darkTheme: darkTheme ?? this.darkTheme,\n      themeMode: themeMode ?? this.themeMode,\n      defaultPopGesture: defaultPopGesture ?? this.defaultPopGesture,\n      defaultOpaqueRoute: defaultOpaqueRoute ?? this.defaultOpaqueRoute,\n      defaultTransitionDuration:\n          defaultTransitionDuration ?? this.defaultTransitionDuration,\n      defaultTransitionCurve:\n          defaultTransitionCurve ?? this.defaultTransitionCurve,\n      defaultDialogTransitionCurve:\n          defaultDialogTransitionCurve ?? this.defaultDialogTransitionCurve,\n      defaultDialogTransitionDuration: defaultDialogTransitionDuration ??\n          this.defaultDialogTransitionDuration,\n      routing: routing ?? this.routing,\n      parameters: parameters ?? this.parameters,\n    );\n  }\n\n  @override\n  bool operator ==(Object other) {\n    if (identical(this, other)) return true;\n\n    return other is ConfigData &&\n        other.routingCallback == routingCallback &&\n        other.defaultTransition == defaultTransition &&\n        other.onInit == onInit &&\n        other.onReady == onReady &&\n        other.onDispose == onDispose &&\n        other.enableLog == enableLog &&\n        other.logWriterCallback == logWriterCallback &&\n        other.smartManagement == smartManagement &&\n        listEquals(other.binds, binds) &&\n        other.transitionDuration == transitionDuration &&\n        other.defaultGlobalState == defaultGlobalState &&\n        listEquals(other.getPages, getPages) &&\n        other.unknownRoute == unknownRoute &&\n        other.routeInformationProvider == routeInformationProvider &&\n        other.routeInformationParser == routeInformationParser &&\n        other.routerDelegate == routerDelegate &&\n        other.backButtonDispatcher == backButtonDispatcher &&\n        listEquals(other.navigatorObservers, navigatorObservers) &&\n        other.navigatorKey == navigatorKey &&\n        other.scaffoldMessengerKey == scaffoldMessengerKey &&\n        mapEquals(other.translationsKeys, translationsKeys) &&\n        other.translations == translations &&\n        other.locale == locale &&\n        other.fallbackLocale == fallbackLocale &&\n        other.initialRoute == initialRoute &&\n        other.customTransition == customTransition &&\n        other.home == home &&\n        other.testMode == testMode &&\n        other.unikey == unikey &&\n        other.theme == theme &&\n        other.darkTheme == darkTheme &&\n        other.themeMode == themeMode &&\n        other.defaultPopGesture == defaultPopGesture &&\n        other.defaultOpaqueRoute == defaultOpaqueRoute &&\n        other.defaultTransitionDuration == defaultTransitionDuration &&\n        other.defaultTransitionCurve == defaultTransitionCurve &&\n        other.defaultDialogTransitionCurve == defaultDialogTransitionCurve &&\n        other.defaultDialogTransitionDuration ==\n            defaultDialogTransitionDuration &&\n        other.routing == routing &&\n        mapEquals(other.parameters, parameters);\n  }\n\n  @override\n  int get hashCode {\n    return routingCallback.hashCode ^\n        defaultTransition.hashCode ^\n        onInit.hashCode ^\n        onReady.hashCode ^\n        onDispose.hashCode ^\n        enableLog.hashCode ^\n        logWriterCallback.hashCode ^\n        smartManagement.hashCode ^\n        binds.hashCode ^\n        transitionDuration.hashCode ^\n        defaultGlobalState.hashCode ^\n        getPages.hashCode ^\n        unknownRoute.hashCode ^\n        routeInformationProvider.hashCode ^\n        routeInformationParser.hashCode ^\n        routerDelegate.hashCode ^\n        backButtonDispatcher.hashCode ^\n        navigatorObservers.hashCode ^\n        navigatorKey.hashCode ^\n        scaffoldMessengerKey.hashCode ^\n        translationsKeys.hashCode ^\n        translations.hashCode ^\n        locale.hashCode ^\n        fallbackLocale.hashCode ^\n        initialRoute.hashCode ^\n        customTransition.hashCode ^\n        home.hashCode ^\n        testMode.hashCode ^\n        unikey.hashCode ^\n        theme.hashCode ^\n        darkTheme.hashCode ^\n        themeMode.hashCode ^\n        defaultPopGesture.hashCode ^\n        defaultOpaqueRoute.hashCode ^\n        defaultTransitionDuration.hashCode ^\n        defaultTransitionCurve.hashCode ^\n        defaultDialogTransitionCurve.hashCode ^\n        defaultDialogTransitionDuration.hashCode ^\n        routing.hashCode ^\n        parameters.hashCode;\n  }\n}\n\nclass GetRoot extends StatefulWidget {\n  const GetRoot({\n    super.key,\n    required this.config,\n    required this.child,\n  });\n  final ConfigData config;\n  final Widget child;\n  @override\n  State<GetRoot> createState() => GetRootState();\n\n  static bool get treeInitialized => GetRootState._controller != null;\n\n  static GetRootState of(BuildContext context) {\n    // Handles the case where the input context is a navigator element.\n    GetRootState? root;\n    if (context is StatefulElement && context.state is GetRootState) {\n      root = context.state as GetRootState;\n    }\n    root = context.findRootAncestorStateOfType<GetRootState>() ?? root;\n    assert(() {\n      if (root == null) {\n        throw FlutterError(\n          'GetRoot operation requested with a context that does not include a GetRoot.\\n'\n          'The context used must be that of a '\n          'widget that is a descendant of a GetRoot widget.',\n        );\n      }\n      return true;\n    }());\n    return root!;\n  }\n}\n\nclass GetRootState extends State<GetRoot> with WidgetsBindingObserver {\n  static GetRootState? _controller;\n  static GetRootState get controller {\n    if (_controller == null) {\n      throw Exception('GetRoot is not part of the three');\n    } else {\n      return _controller!;\n    }\n  }\n\n  late ConfigData config;\n\n  @override\n  void initState() {\n    config = widget.config;\n    GetRootState._controller = this;\n    Engine.instance.addObserver(this);\n    onInit();\n    super.initState();\n  }\n\n  // @override\n  // void didUpdateWidget(covariant GetRoot oldWidget) {\n  //   if (oldWidget.config != widget.config) {\n  //     config = widget.config;\n  //   }\n\n  //   super.didUpdateWidget(oldWidget);\n  // }\n\n  void onClose() {\n    config.onDispose?.call();\n    Get.clearTranslations();\n    config.snackBarQueue.disposeControllers();\n    RouterReportManager.instance.clearRouteKeys();\n    RouterReportManager.dispose();\n    Get.resetInstance(clearRouteBindings: true);\n    _controller = null;\n    Engine.instance.removeObserver(this);\n  }\n\n  @override\n  void dispose() {\n    onClose();\n    super.dispose();\n  }\n\n  void onInit() {\n    if (config.getPages == null && config.home == null) {\n      throw 'You need add pages or home';\n    }\n\n    if (config.routerDelegate == null) {\n      final newDelegate = GetDelegate.createDelegate(\n        pages: config.getPages ??\n            [\n              GetPage(\n                name: cleanRouteName(\"/${config.home.runtimeType}\"),\n                page: () => config.home!,\n              ),\n            ],\n        notFoundRoute: config.unknownRoute,\n        navigatorKey: config.navigatorKey,\n        navigatorObservers: (config.navigatorObservers == null\n            ? <NavigatorObserver>[\n                GetObserver(config.routingCallback, Get.routing)\n              ]\n            : <NavigatorObserver>[\n                GetObserver(config.routingCallback, config.routing),\n                ...config.navigatorObservers!\n              ]),\n      );\n      config = config.copyWith(routerDelegate: newDelegate);\n    }\n\n    if (config.routeInformationParser == null) {\n      final newRouteInformationParser =\n          GetInformationParser.createInformationParser(\n        initialRoute: config.initialRoute ??\n            config.getPages?.first.name ??\n            cleanRouteName(\"/${config.home.runtimeType}\"),\n      );\n\n      config =\n          config.copyWith(routeInformationParser: newRouteInformationParser);\n    }\n\n    if (config.locale != null) Get.locale = config.locale;\n\n    if (config.fallbackLocale != null) {\n      Get.fallbackLocale = config.fallbackLocale;\n    }\n\n    if (config.translations != null) {\n      Get.addTranslations(config.translations!.keys);\n    } else if (config.translationsKeys != null) {\n      Get.addTranslations(config.translationsKeys!);\n    }\n\n    Get.smartManagement = config.smartManagement;\n    config.onInit?.call();\n\n    Get.isLogEnable = config.enableLog ?? kDebugMode;\n    Get.log = config.logWriterCallback ?? defaultLogWriterCallback;\n\n    if (config.defaultTransition == null) {\n      config = config.copyWith(defaultTransition: getThemeTransition());\n    }\n\n    // defaultOpaqueRoute = config.opaqueRoute ?? true;\n    // defaultPopGesture = config.popGesture ?? GetPlatform.isIOS;\n    // defaultTransitionDuration =\n    //     config.transitionDuration ?? Duration(milliseconds: 300);\n\n    Future(() => onReady());\n  }\n\n  set parameters(Map<String, String?> newParameters) {\n    // rootController.parameters = newParameters;\n    config = config.copyWith(parameters: newParameters);\n  }\n\n  set testMode(bool isTest) {\n    config = config.copyWith(testMode: isTest);\n    GetTestMode.active = isTest;\n  }\n\n  void onReady() {\n    config.onReady?.call();\n  }\n\n  Transition? getThemeTransition() {\n    final platform = context.theme.platform;\n    final matchingTransition =\n        Get.theme.pageTransitionsTheme.builders[platform];\n    switch (matchingTransition) {\n      case CupertinoPageTransitionsBuilder():\n        return Transition.cupertino;\n      case ZoomPageTransitionsBuilder():\n        return Transition.zoom;\n      case FadeUpwardsPageTransitionsBuilder():\n        return Transition.fade;\n      case OpenUpwardsPageTransitionsBuilder():\n        return Transition.native;\n      default:\n        return null;\n    }\n  }\n\n  @override\n  void didChangeLocales(List<Locale>? locales) {\n    Get.asap(() {\n      final locale = Get.deviceLocale;\n      if (locale != null) {\n        Get.updateLocale(locale);\n      }\n    });\n  }\n\n  void setTheme(ThemeData value) {\n    if (config.darkTheme == null) {\n      config = config.copyWith(theme: value);\n    } else {\n      if (value.brightness == Brightness.light) {\n        config = config.copyWith(theme: value);\n      } else {\n        config = config.copyWith(darkTheme: value);\n      }\n    }\n    update();\n  }\n\n  void setThemeMode(ThemeMode value) {\n    config = config.copyWith(themeMode: value);\n    update();\n  }\n\n  void restartApp() {\n    config = config.copyWith(unikey: UniqueKey());\n    update();\n  }\n\n  void update() {\n    context.visitAncestorElements((element) {\n      element.markNeedsBuild();\n      return false;\n    });\n  }\n\n  GlobalKey<NavigatorState> get key => rootDelegate.navigatorKey;\n\n  GetDelegate get rootDelegate => config.routerDelegate as GetDelegate;\n\n  RouteInformationParser<Object> get informationParser =>\n      config.routeInformationParser!;\n\n  GlobalKey<NavigatorState>? addKey(GlobalKey<NavigatorState> newKey) {\n    rootDelegate.navigatorKey = newKey;\n    return key;\n  }\n\n  Map<String, GetDelegate> keys = {};\n\n  GetDelegate? nestedKey(String? key) {\n    if (key == null) {\n      return rootDelegate;\n    }\n    keys.putIfAbsent(\n      key,\n      () => GetDelegate(\n        showHashOnUrl: true,\n        //debugLabel: 'Getx nested key: ${key.toString()}',\n        pages: RouteDecoder.fromRoute(key).currentChildren ?? [],\n      ),\n    );\n    return keys[key];\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return widget.child;\n  }\n\n  String cleanRouteName(String name) {\n    name = name.replaceAll('() => ', '');\n\n    /// uncomment for URL styling.\n    // name = name.paramCase!;\n    if (!name.startsWith('/')) {\n      name = '/$name';\n    }\n    return Uri.tryParse(name)?.toString() ?? name;\n  }\n}\n"
  },
  {
    "path": "lib/get_navigation/src/root/internacionalization.dart",
    "content": "const List<String> rtlLanguages = <String>[\n  'ar', // Arabic\n  'fa', // Farsi\n  'he', // Hebrew\n  'ps', // Pashto\n  'ur',\n];\n\nabstract class Translations {\n  Map<String, Map<String, String>> get keys;\n}\n"
  },
  {
    "path": "lib/get_navigation/src/router_report.dart",
    "content": "import 'dart:collection';\n\nimport '../../get.dart';\n\nclass RouterReportManager<T> {\n  /// Holds a reference to `Get.reference` when the Instance was\n  /// created to manage the memory.\n  final Map<T?, List<String>> _routesKey = {};\n\n  /// Stores the onClose() references of instances created with `Get.create()`\n  /// using the `Get.reference`.\n  /// Experimental feature to keep the lifecycle and memory management with\n  /// non-singleton instances.\n  final Map<T?, HashSet<Function>> _routesByCreate = {};\n\n  static RouterReportManager? _instance;\n\n  RouterReportManager._();\n\n  static RouterReportManager get instance =>\n      _instance ??= RouterReportManager._();\n\n  static void dispose() {\n    _instance = null;\n  }\n\n  void printInstanceStack() {\n    Get.log(_routesKey.toString());\n  }\n\n  T? _current;\n\n  // ignore: use_setters_to_change_properties\n  void reportCurrentRoute(T newRoute) {\n    _current = newRoute;\n  }\n\n  /// Links a Class instance [S] (or [tag]) to the current route.\n  /// Requires usage of `GetMaterialApp`.\n  void reportDependencyLinkedToRoute(String dependencyKey) {\n    if (_current == null) return;\n    if (_routesKey.containsKey(_current)) {\n      _routesKey[_current!]!.add(dependencyKey);\n    } else {\n      _routesKey[_current] = <String>[dependencyKey];\n    }\n  }\n\n  void clearRouteKeys() {\n    _routesKey.clear();\n    _routesByCreate.clear();\n  }\n\n  void appendRouteByCreate(GetLifeCycleMixin i) {\n    _routesByCreate[_current] ??= HashSet<Function>();\n    // _routesByCreate[Get.reference]!.add(i.onDelete as Function);\n    _routesByCreate[_current]!.add(i.onDelete);\n  }\n\n  void reportRouteDispose(T disposed) {\n    if (Get.smartManagement != SmartManagement.onlyBuilder) {\n      // Engine.instance.addPostFrameCallback((_) {\n      // Future.microtask(() {\n      _removeDependencyByRoute(disposed);\n      // });\n    }\n  }\n\n  void reportRouteWillDispose(T disposed) {\n    final keysToRemove = <String>[];\n\n    _routesKey[disposed]?.forEach(keysToRemove.add);\n\n    /// Removes `Get.create()` instances registered in `routeName`.\n    if (_routesByCreate.containsKey(disposed)) {\n      for (final onClose in _routesByCreate[disposed]!) {\n        // assure the [DisposableInterface] instance holding a reference\n        // to onClose() wasn't disposed.\n        onClose();\n      }\n      _routesByCreate[disposed]!.clear();\n      _routesByCreate.remove(disposed);\n    }\n\n    for (final element in keysToRemove) {\n      Get.markAsDirty(key: element);\n\n      //_routesKey.remove(element);\n    }\n\n    keysToRemove.clear();\n  }\n\n  /// Clears from memory registered Instances associated with [routeName] when\n  /// using `Get.smartManagement` as [SmartManagement.full] or\n  /// [SmartManagement.keepFactory]\n  /// Meant for internal usage of `GetPageRoute` and `GetDialogRoute`\n  void _removeDependencyByRoute(T routeName) {\n    final keysToRemove = <String>[];\n\n    _routesKey[routeName]?.forEach(keysToRemove.add);\n\n    /// Removes `Get.create()` instances registered in `routeName`.\n    if (_routesByCreate.containsKey(routeName)) {\n      for (final onClose in _routesByCreate[routeName]!) {\n        // assure the [DisposableInterface] instance holding a reference\n        // to onClose() wasn't disposed.\n        onClose();\n      }\n      _routesByCreate[routeName]!.clear();\n      _routesByCreate.remove(routeName);\n    }\n\n    for (final element in keysToRemove) {\n      final value = Get.delete(key: element);\n      if (value) {\n        _routesKey[routeName]?.remove(element);\n      }\n    }\n\n    _routesKey.remove(routeName);\n\n    keysToRemove.clear();\n  }\n}\n"
  },
  {
    "path": "lib/get_navigation/src/routes/circular_reveal_clipper.dart",
    "content": "import 'dart:math' show sqrt, max;\nimport 'dart:ui' show lerpDouble;\n\nimport 'package:flutter/material.dart';\n\nclass CircularRevealClipper extends CustomClipper<Path> {\n  final double fraction;\n  final Alignment? centerAlignment;\n  final Offset? centerOffset;\n  final double? minRadius;\n  final double? maxRadius;\n\n  CircularRevealClipper({\n    required this.fraction,\n    this.centerAlignment,\n    this.centerOffset,\n    this.minRadius,\n    this.maxRadius,\n  });\n\n  @override\n  Path getClip(Size size) {\n    final center = centerAlignment?.alongSize(size) ??\n        centerOffset ??\n        Offset(size.width / 2, size.height / 2);\n    final minRadius = this.minRadius ?? 0;\n    final maxRadius = this.maxRadius ?? calcMaxRadius(size, center);\n\n    return Path()\n      ..addOval(\n        Rect.fromCircle(\n          center: center,\n          radius: lerpDouble(minRadius, maxRadius, fraction)!,\n        ),\n      );\n  }\n\n  @override\n  bool shouldReclip(CustomClipper<Path> oldClipper) => true;\n\n  static double calcMaxRadius(Size size, Offset center) {\n    final w = max(center.dx, size.width - center.dx);\n    final h = max(center.dy, size.height - center.dy);\n    return sqrt(w * w + h * h);\n  }\n}\n"
  },
  {
    "path": "lib/get_navigation/src/routes/custom_transition.dart",
    "content": "import 'package:flutter/widgets.dart';\n\n// ignore: one_member_abstracts\nabstract class CustomTransition {\n  Widget buildTransition(\n    BuildContext context,\n    Curve? curve,\n    Alignment? alignment,\n    Animation<double> animation,\n    Animation<double> secondaryAnimation,\n    Widget child,\n  );\n}\n"
  },
  {
    "path": "lib/get_navigation/src/routes/default_route.dart",
    "content": "import 'package:flutter/cupertino.dart';\n\nimport '../../../get.dart';\nimport '../router_report.dart';\n\n@optionalTypeArgs\nmixin RouteReportMixin<T extends StatefulWidget> on State<T> {\n  @override\n  void initState() {\n    super.initState();\n    RouterReportManager.instance.reportCurrentRoute(this);\n  }\n\n  @override\n  void dispose() {\n    super.dispose();\n    RouterReportManager.instance.reportRouteDispose(this);\n  }\n}\n\nmixin PageRouteReportMixin<T> on Route<T> {\n  @override\n  void install() {\n    super.install();\n    RouterReportManager.instance.reportCurrentRoute(this);\n  }\n\n  @override\n  void dispose() {\n    super.dispose();\n    RouterReportManager.instance.reportRouteDispose(this);\n  }\n}\n\nclass GetPageRoute<T> extends PageRoute<T>\n    with GetPageRouteTransitionMixin<T>, PageRouteReportMixin {\n  /// Creates a page route for use in an iOS designed app.\n  ///\n  /// The [builder], [maintainState], and [fullscreenDialog] arguments must not\n  /// be null.\n  GetPageRoute({\n    super.settings,\n    this.transitionDuration = const Duration(milliseconds: 300),\n    this.reverseTransitionDuration = const Duration(milliseconds: 300),\n    this.opaque = true,\n    this.parameter,\n    this.gestureWidth,\n    this.curve,\n    this.alignment,\n    this.transition,\n    this.popGesture,\n    this.customTransition,\n    this.barrierDismissible = false,\n    this.barrierColor,\n    BindingsInterface? binding,\n    List<BindingsInterface> bindings = const [],\n    this.binds,\n    this.routeName,\n    this.page,\n    this.title,\n    this.showCupertinoParallax = true,\n    this.barrierLabel,\n    this.maintainState = true,\n    super.fullscreenDialog,\n    this.middlewares,\n  })  : bindings = (binding == null) ? bindings : [...bindings, binding],\n        _middlewareRunner = MiddlewareRunner(middlewares);\n\n  @override\n  final Duration transitionDuration;\n  @override\n  final Duration reverseTransitionDuration;\n\n  final GetPageBuilder? page;\n  final String? routeName;\n  //final String reference;\n  final CustomTransition? customTransition;\n  final List<BindingsInterface> bindings;\n  final Map<String, String>? parameter;\n  final List<Bind>? binds;\n\n  @override\n  final bool showCupertinoParallax;\n\n  @override\n  final bool opaque;\n  final bool? popGesture;\n\n  @override\n  final bool barrierDismissible;\n  final Transition? transition;\n  final Curve? curve;\n  final Alignment? alignment;\n  final List<GetMiddleware>? middlewares;\n\n  @override\n  final Color? barrierColor;\n\n  @override\n  final String? barrierLabel;\n\n  @override\n  final bool maintainState;\n\n  final MiddlewareRunner _middlewareRunner;\n\n  @override\n  void dispose() {\n    super.dispose();\n    _middlewareRunner.runOnPageDispose();\n    _child = null;\n  }\n\n  Widget? _child;\n\n  Widget _getChild() {\n    if (_child != null) return _child!;\n\n    final localBinds = [if (binds != null) ...binds!];\n\n    final bindingsToBind = _middlewareRunner\n        .runOnBindingsStart(bindings.isNotEmpty ? bindings : localBinds);\n\n    final pageToBuild = _middlewareRunner.runOnPageBuildStart(page)!;\n\n    if (bindingsToBind != null && bindingsToBind.isNotEmpty) {\n      if (bindingsToBind is List<BindingsInterface>) {\n        for (final item in bindingsToBind) {\n          final dep = item.dependencies();\n          if (dep is List<Bind>) {\n            _child = Binds(\n              binds: dep,\n              child: _middlewareRunner.runOnPageBuilt(pageToBuild()),\n            );\n          }\n        }\n      } else if (bindingsToBind is List<Bind>) {\n        _child = Binds(\n          binds: bindingsToBind,\n          child: _middlewareRunner.runOnPageBuilt(pageToBuild()),\n        );\n      }\n    }\n\n    return _child ??= _middlewareRunner.runOnPageBuilt(pageToBuild());\n  }\n\n  @override\n  Widget buildContent(BuildContext context) {\n    return _getChild();\n  }\n\n  @override\n  final String? title;\n\n  @override\n  String get debugLabel => '${super.debugLabel}(${settings.name})';\n\n  @override\n  final double Function(BuildContext context)? gestureWidth;\n}\n"
  },
  {
    "path": "lib/get_navigation/src/routes/default_transitions.dart",
    "content": "import 'package:flutter/cupertino.dart';\nimport 'package:flutter/material.dart';\n\nimport 'circular_reveal_clipper.dart';\n\nclass LeftToRightFadeTransition {\n  Widget buildTransitions(\n      BuildContext context,\n      Curve? curve,\n      Alignment? alignment,\n      Animation<double> animation,\n      Animation<double> secondaryAnimation,\n      Widget child) {\n    return SlideTransition(\n      position: Tween<Offset>(\n        begin: const Offset(-1.0, 0.0),\n        end: Offset.zero,\n      ).animate(animation),\n      child: FadeTransition(\n        opacity: animation,\n        child: SlideTransition(\n            position: Tween<Offset>(\n              begin: Offset.zero,\n              end: const Offset(1.0, 0.0),\n            ).animate(secondaryAnimation),\n            child: child),\n      ),\n    );\n  }\n}\n\nclass RightToLeftFadeTransition {\n  Widget buildTransitions(\n      BuildContext context,\n      Curve? curve,\n      Alignment? alignment,\n      Animation<double> animation,\n      Animation<double> secondaryAnimation,\n      Widget child) {\n    return SlideTransition(\n      position: Tween<Offset>(\n        begin: const Offset(1.0, 0.0),\n        end: Offset.zero,\n      ).animate(animation),\n      child: FadeTransition(\n        opacity: animation,\n        child: SlideTransition(\n            position: Tween<Offset>(\n              begin: Offset.zero,\n              end: const Offset(-1.0, 0.0),\n            ).animate(secondaryAnimation),\n            child: child),\n      ),\n    );\n  }\n}\n\nclass NoTransition {\n  Widget buildTransitions(\n      BuildContext context,\n      Curve curve,\n      Alignment alignment,\n      Animation<double> animation,\n      Animation<double> secondaryAnimation,\n      Widget child) {\n    return child;\n  }\n}\n\nclass FadeInTransition {\n  Widget buildTransitions(\n      BuildContext context,\n      Curve? curve,\n      Alignment? alignment,\n      Animation<double> animation,\n      Animation<double> secondaryAnimation,\n      Widget child) {\n    return FadeTransition(opacity: animation, child: child);\n  }\n}\n\nclass SlideDownTransition {\n  Widget buildTransitions(\n      BuildContext context,\n      Curve? curve,\n      Alignment? alignment,\n      Animation<double> animation,\n      Animation<double> secondaryAnimation,\n      Widget child) {\n    return SlideTransition(\n      position: Tween<Offset>(\n        begin: const Offset(0.0, 1.0),\n        end: Offset.zero,\n      ).animate(animation),\n      child: child,\n    );\n  }\n}\n\nclass SlideLeftTransition {\n  Widget buildTransitions(\n      BuildContext context,\n      Curve? curve,\n      Alignment? alignment,\n      Animation<double> animation,\n      Animation<double> secondaryAnimation,\n      Widget child) {\n    return SlideTransition(\n      position: Tween<Offset>(\n        begin: const Offset(-1.0, 0.0),\n        end: Offset.zero,\n      ).animate(animation),\n      child: child,\n    );\n  }\n}\n\nclass SlideRightTransition {\n  Widget buildTransitions(\n      BuildContext context,\n      Curve? curve,\n      Alignment? alignment,\n      Animation<double> animation,\n      Animation<double> secondaryAnimation,\n      Widget child) {\n    return SlideTransition(\n      position: Tween<Offset>(\n        begin: const Offset(1.0, 0.0),\n        end: Offset.zero,\n      ).animate(animation),\n      child: child,\n    );\n  }\n}\n\nclass SlideTopTransition {\n  Widget buildTransitions(\n      BuildContext context,\n      Curve? curve,\n      Alignment? alignment,\n      Animation<double> animation,\n      Animation<double> secondaryAnimation,\n      Widget child) {\n    return SlideTransition(\n      position: Tween<Offset>(\n        begin: const Offset(0.0, -1.0),\n        end: Offset.zero,\n      ).animate(animation),\n      child: child,\n    );\n  }\n}\n\nclass ZoomInTransition {\n  Widget buildTransitions(\n      BuildContext context,\n      Curve? curve,\n      Alignment? alignment,\n      Animation<double> animation,\n      Animation<double> secondaryAnimation,\n      Widget child) {\n    return ScaleTransition(\n      scale: animation,\n      child: child,\n    );\n  }\n}\n\nclass SizeTransitions {\n  Widget buildTransitions(\n      BuildContext context,\n      Curve curve,\n      Alignment? alignment,\n      Animation<double> animation,\n      Animation<double> secondaryAnimation,\n      Widget child) {\n    return Align(\n      alignment: Alignment.center,\n      child: SizeTransition(\n        sizeFactor: CurvedAnimation(\n          parent: animation,\n          curve: curve,\n        ),\n        child: child,\n      ),\n    );\n  }\n}\n\nclass CircularRevealTransition {\n  Widget buildTransitions(\n      BuildContext context,\n      Curve? curve,\n      Alignment? alignment,\n      Animation<double> animation,\n      Animation<double> secondaryAnimation,\n      Widget child) {\n    return ClipPath(\n      clipper: CircularRevealClipper(\n        fraction: animation.value,\n        centerAlignment: Alignment.center,\n        centerOffset: Offset.zero,\n        minRadius: 0,\n        maxRadius: 800,\n      ),\n      child: child,\n    );\n  }\n}\n"
  },
  {
    "path": "lib/get_navigation/src/routes/get_information_parser.dart",
    "content": "import 'package:flutter/foundation.dart';\nimport 'package:flutter/widgets.dart';\n\nimport '../../../get.dart';\n\nclass GetInformationParser extends RouteInformationParser<RouteDecoder> {\n  factory GetInformationParser.createInformationParser(\n      {String initialRoute = '/'}) {\n    return GetInformationParser(initialRoute: initialRoute);\n  }\n\n  final String initialRoute;\n\n  GetInformationParser({\n    required this.initialRoute,\n  }) {\n    Get.log('GetInformationParser is created !');\n  }\n  @override\n  SynchronousFuture<RouteDecoder> parseRouteInformation(\n    RouteInformation routeInformation,\n  ) {\n    final uri = routeInformation.uri;\n    var location = uri.toString();\n    if (location == '/') {\n      //check if there is a corresponding page\n      //if not, relocate to initialRoute\n      if (!(Get.rootController.rootDelegate)\n          .registeredRoutes\n          .any((element) => element.name == '/')) {\n        location = initialRoute;\n      }\n    } else if (location.isEmpty) {\n      location = initialRoute;\n    }\n\n    Get.log('GetInformationParser: route location: $location');\n\n    return SynchronousFuture(RouteDecoder.fromRoute(location));\n  }\n\n  @override\n  RouteInformation restoreRouteInformation(RouteDecoder configuration) {\n    return RouteInformation(\n      uri: Uri.tryParse(configuration.pageSettings?.name ?? ''),\n      state: null,\n    );\n  }\n}\n"
  },
  {
    "path": "lib/get_navigation/src/routes/get_navigation_interface.dart",
    "content": "import 'package:flutter/widgets.dart';\n\nimport '../../../get_instance/src/bindings_interface.dart';\nimport '../routes/get_route.dart';\nimport '../routes/transitions_type.dart';\n\n/// Enables the user to customize the intended pop behavior\n///\n/// Goes to either the previous _activePages entry or the previous page entry\n///\n/// e.g. if the user navigates to these pages\n/// 1) /home\n/// 2) /home/products/1234\n///\n/// when popping on [History] mode, it will emulate a browser back button.\n///\n/// so the new _activePages stack will be:\n/// 1) /home\n///\n/// when popping on [Page] mode, it will only remove the last part of the route\n/// so the new _activePages stack will be:\n/// 1) /home\n/// 2) /home/products\n///\n/// another pop will change the _activePages stack to:\n/// 1) /home\nenum PopMode {\n  history,\n  page,\n}\n\n/// Enables the user to customize the behavior when pushing multiple routes that\n/// shouldn't be duplicates\nenum PreventDuplicateHandlingMode {\n  /// Removes the _activePages entries until it reaches the old route\n  popUntilOriginalRoute,\n\n  /// Simply don't push the new route\n  doNothing,\n\n  /// Recommended - Moves the old route entry to the front\n  ///\n  /// With this mode, you guarantee there will be only one\n  /// route entry for each location\n  reorderRoutes,\n\n  recreate,\n}\n\nmixin IGetNavigation {\n  Future<T?> to<T>(\n    Widget Function() page, {\n    bool? opaque,\n    Transition? transition,\n    Curve? curve,\n    Duration? duration,\n    String? id,\n    String? routeName,\n    bool fullscreenDialog = false,\n    dynamic arguments,\n    List<BindingsInterface> bindings = const [],\n    bool preventDuplicates = true,\n    bool? popGesture,\n    bool showCupertinoParallax = true,\n    double Function(BuildContext context)? gestureWidth,\n  });\n\n  Future<void> popModeUntil(\n    String fullRoute, {\n    PopMode popMode = PopMode.history,\n  });\n\n  Future<T?> off<T>(\n    Widget Function() page, {\n    bool? opaque,\n    Transition? transition,\n    Curve? curve,\n    Duration? duration,\n    String? id,\n    String? routeName,\n    bool fullscreenDialog = false,\n    dynamic arguments,\n    List<BindingsInterface> bindings = const [],\n    bool preventDuplicates = true,\n    bool? popGesture,\n    bool showCupertinoParallax = true,\n    double Function(BuildContext context)? gestureWidth,\n  });\n\n  Future<T?>? offAll<T>(\n    Widget Function() page, {\n    bool Function(GetPage route)? predicate,\n    bool opaque = true,\n    bool? popGesture,\n    String? id,\n    String? routeName,\n    dynamic arguments,\n    List<BindingsInterface> bindings = const [],\n    bool fullscreenDialog = false,\n    Transition? transition,\n    Curve? curve,\n    Duration? duration,\n    bool showCupertinoParallax = true,\n    double Function(BuildContext context)? gestureWidth,\n  });\n\n  Future<T?> toNamed<T>(\n    String page, {\n    dynamic arguments,\n    String? id,\n    bool preventDuplicates = true,\n    Map<String, String>? parameters,\n  });\n\n  Future<T?> offNamed<T>(\n    String page, {\n    dynamic arguments,\n    String? id,\n    Map<String, String>? parameters,\n  });\n\n  Future<T?>? offAllNamed<T>(\n    String newRouteName, {\n    // bool Function(GetPage route)? predicate,\n    dynamic arguments,\n    String? id,\n    Map<String, String>? parameters,\n  });\n\n  Future<T?>? offNamedUntil<T>(\n    String page, {\n    bool Function(GetPage route)? predicate,\n    dynamic arguments,\n    String? id,\n    Map<String, String>? parameters,\n  });\n\n  Future<T?> toNamedAndOffUntil<T>(\n    String page,\n    bool Function(GetPage) predicate, [\n    Object? data,\n  ]);\n\n  Future<T?> offUntil<T>(\n    Widget Function() page,\n    bool Function(GetPage) predicate, [\n    Object? arguments,\n  ]);\n\n  void removeRoute<T>(String name);\n\n  void back<T>([T? result]);\n\n  Future<R?> backAndtoNamed<T, R>(String page, {T? result, Object? arguments});\n\n  void backUntil(bool Function(GetPage) predicate);\n\n  void goToUnknownPage([bool clearPages = true]);\n}\n"
  },
  {
    "path": "lib/get_navigation/src/routes/get_navigator.dart",
    "content": "import 'package:flutter/widgets.dart';\n\nclass GetNavigator extends Navigator {\n  GetNavigator({\n    super.key,\n    bool Function(Route<dynamic>, dynamic)? onPopPage,\n    required super.pages,\n    List<NavigatorObserver>? observers,\n    super.reportsRouteUpdateToEngine,\n    TransitionDelegate? transitionDelegate,\n    super.initialRoute,\n    super.restorationScopeId,\n  }) : super(\n          // ignore: deprecated_member_use\n          onPopPage: onPopPage ??\n              (route, result) {\n                final didPop = route.didPop(result);\n                if (!didPop) {\n                  return false;\n                }\n                return true;\n              },\n          observers: [\n            // GetObserver(null, Get.routing),\n            HeroController(),\n            ...?observers,\n          ],\n          transitionDelegate:\n              transitionDelegate ?? const DefaultTransitionDelegate<dynamic>(),\n        );\n}\n"
  },
  {
    "path": "lib/get_navigation/src/routes/get_route.dart",
    "content": "// ignore_for_file: overridden_fields\n\nimport 'dart:async';\n\nimport 'package:flutter/cupertino.dart';\nimport 'package:flutter/foundation.dart';\nimport 'package:flutter/material.dart';\n\nimport '../../../get_instance/src/bindings_interface.dart';\nimport '../../../get_state_manager/src/simple/get_state.dart';\nimport '../../get_navigation.dart';\n\nclass GetPage<T> extends Page<T> {\n  final GetPageBuilder page;\n  final bool? popGesture;\n  final Map<String, String>? parameters;\n  final String? title;\n  final Transition? transition;\n  final Curve curve;\n  final bool? participatesInRootNavigator;\n  final Alignment? alignment;\n  final bool maintainState;\n  final bool opaque;\n  final double Function(BuildContext context)? gestureWidth;\n  final BindingsInterface? binding;\n  final List<BindingsInterface> bindings;\n  final List<Bind> binds;\n  final CustomTransition? customTransition;\n  final Duration? transitionDuration;\n  final Duration? reverseTransitionDuration;\n  final bool fullscreenDialog;\n  final bool preventDuplicates;\n  final Completer<T?>? completer;\n  // @override\n  // final LocalKey? key;\n\n  // @override\n  // RouteSettings get settings => this;\n\n  @override\n  final Object? arguments;\n\n  @override\n  final String name;\n\n  final bool inheritParentPath;\n\n  final List<GetPage> children;\n  final List<GetMiddleware> middlewares;\n  final PathDecoded path;\n  final GetPage? unknownRoute;\n  final bool showCupertinoParallax;\n\n  final PreventDuplicateHandlingMode preventDuplicateHandlingMode;\n\n  static void _defaultPopInvokedHandler(bool didPop, Object? result) {}\n\n  GetPage({\n    required this.name,\n    required this.page,\n    this.title,\n    this.participatesInRootNavigator,\n    this.gestureWidth,\n    // RouteSettings settings,\n    this.maintainState = true,\n    this.curve = Curves.linear,\n    this.alignment,\n    this.parameters,\n    this.opaque = true,\n    this.transitionDuration,\n    this.reverseTransitionDuration,\n    this.popGesture,\n    this.binding,\n    this.bindings = const [],\n    this.binds = const [],\n    this.transition,\n    this.customTransition,\n    this.fullscreenDialog = false,\n    this.children = const <GetPage>[],\n    this.middlewares = const [],\n    this.unknownRoute,\n    this.arguments,\n    this.showCupertinoParallax = true,\n    this.preventDuplicates = true,\n    this.preventDuplicateHandlingMode =\n        PreventDuplicateHandlingMode.reorderRoutes,\n    this.completer,\n    this.inheritParentPath = true,\n    LocalKey? key,\n    super.canPop,\n    super.onPopInvoked = _defaultPopInvokedHandler,\n    super.restorationId,\n  })  : path = _nameToRegex(name),\n        assert(name.startsWith('/'),\n            'It is necessary to start route name [$name] with a slash: /$name'),\n        super(\n          key: key ?? ValueKey(name),\n          name: name,\n          // arguments: Get.arguments,\n        );\n  // settings = RouteSettings(name: name, arguments: Get.arguments);\n\n  GetPage<T> copyWith({\n    LocalKey? key,\n    String? name,\n    GetPageBuilder? page,\n    bool? popGesture,\n    Map<String, String>? parameters,\n    String? title,\n    Transition? transition,\n    Curve? curve,\n    Alignment? alignment,\n    bool? maintainState,\n    bool? opaque,\n    List<BindingsInterface>? bindings,\n    BindingsInterface? binding,\n    List<Bind>? binds,\n    CustomTransition? customTransition,\n    Duration? transitionDuration,\n    Duration? reverseTransitionDuration,\n    bool? fullscreenDialog,\n    RouteSettings? settings,\n    List<GetPage<T>>? children,\n    GetPage? unknownRoute,\n    List<GetMiddleware>? middlewares,\n    bool? preventDuplicates,\n    final double Function(BuildContext context)? gestureWidth,\n    bool? participatesInRootNavigator,\n    Object? arguments,\n    bool? showCupertinoParallax,\n    Completer<T?>? completer,\n    bool? inheritParentPath,\n    bool? canPop,\n    PopInvokedWithResultCallback<T>? onPopInvoked,\n    String? restorationId,\n  }) {\n    return GetPage(\n      key: key ?? this.key,\n      participatesInRootNavigator:\n          participatesInRootNavigator ?? this.participatesInRootNavigator,\n      preventDuplicates: preventDuplicates ?? this.preventDuplicates,\n      name: name ?? this.name,\n      page: page ?? this.page,\n      popGesture: popGesture ?? this.popGesture,\n      parameters: parameters ?? this.parameters,\n      title: title ?? this.title,\n      transition: transition ?? this.transition,\n      curve: curve ?? this.curve,\n      alignment: alignment ?? this.alignment,\n      maintainState: maintainState ?? this.maintainState,\n      opaque: opaque ?? this.opaque,\n      bindings: bindings ?? this.bindings,\n      binds: binds ?? this.binds,\n      binding: binding ?? this.binding,\n      customTransition: customTransition ?? this.customTransition,\n      transitionDuration: transitionDuration ?? this.transitionDuration,\n      reverseTransitionDuration:\n          reverseTransitionDuration ?? this.reverseTransitionDuration,\n      fullscreenDialog: fullscreenDialog ?? this.fullscreenDialog,\n      children: children ?? this.children,\n      unknownRoute: unknownRoute ?? this.unknownRoute,\n      middlewares: middlewares ?? this.middlewares,\n      gestureWidth: gestureWidth ?? this.gestureWidth,\n      arguments: arguments ?? this.arguments,\n      showCupertinoParallax:\n          showCupertinoParallax ?? this.showCupertinoParallax,\n      completer: completer ?? this.completer,\n      inheritParentPath: inheritParentPath ?? this.inheritParentPath,\n      canPop: canPop ?? this.canPop,\n      onPopInvoked: onPopInvoked ?? this.onPopInvoked,\n      restorationId: restorationId ?? restorationId,\n    );\n  }\n\n  @override\n  Route<T> createRoute(BuildContext context) {\n    // return GetPageRoute<T>(settings: this, page: page);\n    final page = PageRedirect(\n      route: this,\n      settings: this,\n      unknownRoute: unknownRoute,\n    ).getPageToRoute<T>(this, unknownRoute, context);\n\n    return page;\n  }\n\n  static PathDecoded _nameToRegex(String path) {\n    var keys = <String?>[];\n\n    String recursiveReplace(Match pattern) {\n      var buffer = StringBuffer('(?:');\n\n      if (pattern[1] != null) buffer.write('.');\n      buffer.write('([\\\\w%+-._~!\\$&\\'()*,;=:@]+))');\n      if (pattern[3] != null) buffer.write('?');\n\n      keys.add(pattern[2]);\n      return \"$buffer\";\n    }\n\n    var stringPath = '$path/?'\n        .replaceAllMapped(RegExp(r'(\\.)?:(\\w+)(\\?)?'), recursiveReplace)\n        .replaceAll('//', '/');\n\n    return PathDecoded(RegExp('^$stringPath\\$'), keys);\n  }\n\n  @override\n  bool operator ==(Object other) {\n    if (identical(this, other)) return true;\n    return other is GetPage<T> && other.key == key;\n  }\n\n  @override\n  String toString() =>\n      '${objectRuntimeType(this, 'Page')}(\"$name\", $key, $arguments)';\n\n  @override\n  int get hashCode {\n    return key.hashCode;\n  }\n}\n\n@immutable\nclass PathDecoded {\n  final RegExp regex;\n  final List<String?> keys;\n  const PathDecoded(this.regex, this.keys);\n\n  @override\n  int get hashCode => regex.hashCode;\n\n  @override\n  bool operator ==(Object other) {\n    if (identical(this, other)) return true;\n\n    return other is PathDecoded &&\n        other.regex == regex; // && listEquals(other.keys, keys);\n  }\n}\n"
  },
  {
    "path": "lib/get_navigation/src/routes/get_router_delegate.dart",
    "content": "import 'dart:async';\n\nimport 'package:flutter/foundation.dart';\nimport 'package:flutter/material.dart';\n\nimport '../../../get_instance/src/bindings_interface.dart';\nimport '../../../get_utils/src/platform/platform.dart';\nimport '../../../route_manager.dart';\n\nclass GetDelegate extends RouterDelegate<RouteDecoder>\n    with\n        ChangeNotifier,\n        PopNavigatorRouterDelegateMixin<RouteDecoder>,\n        IGetNavigation {\n  factory GetDelegate.createDelegate({\n    GetPage<dynamic>? notFoundRoute,\n    List<GetPage> pages = const [],\n    List<NavigatorObserver>? navigatorObservers,\n    TransitionDelegate<dynamic>? transitionDelegate,\n    PopMode backButtonPopMode = PopMode.history,\n    PreventDuplicateHandlingMode preventDuplicateHandlingMode =\n        PreventDuplicateHandlingMode.reorderRoutes,\n    GlobalKey<NavigatorState>? navigatorKey,\n  }) {\n    return GetDelegate(\n      notFoundRoute: notFoundRoute,\n      navigatorObservers: navigatorObservers,\n      transitionDelegate: transitionDelegate,\n      backButtonPopMode: backButtonPopMode,\n      preventDuplicateHandlingMode: preventDuplicateHandlingMode,\n      pages: pages,\n      navigatorKey: navigatorKey,\n    );\n  }\n\n  final List<RouteDecoder> _activePages = <RouteDecoder>[];\n  final PopMode backButtonPopMode;\n  final PreventDuplicateHandlingMode preventDuplicateHandlingMode;\n\n  final GetPage notFoundRoute;\n\n  final List<NavigatorObserver>? navigatorObservers;\n  final TransitionDelegate<dynamic>? transitionDelegate;\n\n  final Iterable<GetPage> Function(RouteDecoder currentNavStack)?\n      pickPagesForRootNavigator;\n\n  List<RouteDecoder> get activePages => _activePages;\n\n  final _routeTree = ParseRouteTree(routes: []);\n\n  List<GetPage> get registeredRoutes => _routeTree.routes;\n\n  void addPages(List<GetPage> getPages) {\n    _routeTree.addRoutes(getPages);\n  }\n\n  void clearRouteTree() {\n    _routeTree.routes.clear();\n  }\n\n  void addPage(GetPage getPage) {\n    _routeTree.addRoute(getPage);\n  }\n\n  void removePage(GetPage getPage) {\n    _routeTree.removeRoute(getPage);\n  }\n\n  RouteDecoder matchRoute(String name, {PageSettings? arguments}) {\n    return _routeTree.matchRoute(name, arguments: arguments);\n  }\n\n  // GlobalKey<NavigatorState> get navigatorKey => Get.key;\n\n  @override\n  GlobalKey<NavigatorState> navigatorKey;\n\n  final String? restorationScopeId;\n\n  GetDelegate({\n    GetPage? notFoundRoute,\n    this.navigatorObservers,\n    this.transitionDelegate,\n    this.backButtonPopMode = PopMode.history,\n    this.preventDuplicateHandlingMode =\n        PreventDuplicateHandlingMode.reorderRoutes,\n    this.pickPagesForRootNavigator,\n    this.restorationScopeId,\n    bool showHashOnUrl = false,\n    GlobalKey<NavigatorState>? navigatorKey,\n    required List<GetPage> pages,\n  })  : navigatorKey = navigatorKey ?? GlobalKey<NavigatorState>(),\n        notFoundRoute = notFoundRoute ??= GetPage(\n          name: '/404',\n          page: () => const Scaffold(\n            body: Center(child: Text('Route not found')),\n          ),\n        ) {\n    if (!showHashOnUrl && GetPlatform.isWeb) setUrlStrategy();\n    addPages(pages);\n    addPage(notFoundRoute);\n    Get.log('GetDelegate is created !');\n  }\n\n  Future<RouteDecoder?> runMiddleware(RouteDecoder config) async {\n    final middlewares = config.currentTreeBranch.last.middlewares;\n    if (middlewares.isEmpty) {\n      return config;\n    }\n    var iterator = config;\n    for (var item in middlewares) {\n      var redirectRes = await item.redirectDelegate(iterator);\n\n      if (redirectRes == null) {\n        config.route?.completer?.complete();\n        return null;\n      }\n      if (config != redirectRes) {\n        config.route?.completer?.complete();\n        Get.log('Redirect to ${redirectRes.pageSettings?.name}');\n      }\n\n      iterator = redirectRes;\n      // Stop the iteration over the middleware if we changed page\n      // and that redirectRes is not the same as the current config.\n      if (config != redirectRes) {\n        break;\n      }\n    }\n    // If the target is not the same as the source, we need\n    // to run the middlewares for the new route.\n    if (iterator != config) {\n      return await runMiddleware(iterator);\n    }\n    return iterator;\n  }\n\n  Future<void> _unsafeHistoryAdd(RouteDecoder config) async {\n    final res = await runMiddleware(config);\n    if (res == null) return;\n    _activePages.add(res);\n  }\n\n  // Future<T?> _unsafeHistoryRemove<T>(RouteDecoder config, T result) async {\n  //   var index = _activePages.indexOf(config);\n  //   if (index >= 0) return _unsafeHistoryRemoveAt(index, result);\n  //   return null;\n  // }\n\n  Future<T?> _unsafeHistoryRemoveAt<T>(int index, T result) async {\n    if (index == _activePages.length - 1 && _activePages.length > 1) {\n      //removing WILL update the current route\n      final toCheck = _activePages[_activePages.length - 2];\n      final resMiddleware = await runMiddleware(toCheck);\n      if (resMiddleware == null) return null;\n      _activePages[_activePages.length - 2] = resMiddleware;\n    }\n\n    final completer = _activePages.removeAt(index).route?.completer;\n    if (completer?.isCompleted == false) completer!.complete(result);\n\n    return completer?.future as T?;\n  }\n\n  T arguments<T>() {\n    return currentConfiguration?.pageSettings?.arguments as T;\n  }\n\n  Map<String, String> get parameters {\n    return currentConfiguration?.pageSettings?.params ?? {};\n  }\n\n  PageSettings? get pageSettings {\n    return currentConfiguration?.pageSettings;\n  }\n\n  Future<void> _pushHistory(RouteDecoder config) async {\n    if (config.route!.preventDuplicates) {\n      final originalEntryIndex = _activePages.indexWhere(\n          (element) => element.pageSettings?.name == config.pageSettings?.name);\n      if (originalEntryIndex >= 0) {\n        switch (preventDuplicateHandlingMode) {\n          case PreventDuplicateHandlingMode.popUntilOriginalRoute:\n            popModeUntil(config.pageSettings!.name, popMode: PopMode.page);\n            break;\n          case PreventDuplicateHandlingMode.reorderRoutes:\n            await _unsafeHistoryRemoveAt(originalEntryIndex, null);\n            await _unsafeHistoryAdd(config);\n            break;\n          case PreventDuplicateHandlingMode.doNothing:\n          default:\n            break;\n        }\n        return;\n      }\n    }\n    await _unsafeHistoryAdd(config);\n  }\n\n  Future<T?> _popHistory<T>(T result) async {\n    if (!_canPopHistory()) return null;\n    return await _doPopHistory(result);\n  }\n\n  Future<T?> _doPopHistory<T>(T result) async {\n    return _unsafeHistoryRemoveAt<T>(_activePages.length - 1, result);\n  }\n\n  Future<T?> _popPage<T>(T result) async {\n    if (!_canPopPage()) return null;\n    return await _doPopPage(result);\n  }\n\n  // returns the popped page\n  Future<T?> _doPopPage<T>(T result) async {\n    final currentBranch = currentConfiguration?.currentTreeBranch;\n    if (currentBranch != null && currentBranch.length > 1) {\n      //remove last part only\n      final remaining = currentBranch.take(currentBranch.length - 1);\n      final prevHistoryEntry = _activePages.length > 1\n          ? _activePages[_activePages.length - 2]\n          : null;\n\n      //check if current route is the same as the previous route\n      if (prevHistoryEntry != null) {\n        //if so, pop the entire _activePages entry\n        final newLocation = remaining.last.name;\n        final prevLocation = prevHistoryEntry.pageSettings?.name;\n        if (newLocation == prevLocation) {\n          //pop the entire _activePages entry\n          return await _popHistory(result);\n        }\n      }\n\n      //create a new route with the remaining tree branch\n      final res = await _popHistory<T>(result);\n      await _pushHistory(\n        RouteDecoder(\n          remaining.toList(),\n          null,\n          //TOOD: persist state??\n        ),\n      );\n      return res;\n    } else {\n      //remove entire entry\n      return await _popHistory(result);\n    }\n  }\n\n  Future<T?> _pop<T>(PopMode mode, T result) async {\n    switch (mode) {\n      case PopMode.history:\n        return await _popHistory<T>(result);\n      case PopMode.page:\n        return await _popPage<T>(result);\n    }\n  }\n\n  Future<T?> popHistory<T>(T result) async {\n    return await _popHistory<T>(result);\n  }\n\n  bool _canPopHistory() {\n    return _activePages.length > 1;\n  }\n\n  Future<bool> canPopHistory() {\n    return SynchronousFuture(_canPopHistory());\n  }\n\n  bool _canPopPage() {\n    final currentTreeBranch = currentConfiguration?.currentTreeBranch;\n    if (currentTreeBranch == null) return false;\n    return currentTreeBranch.length > 1 ? true : _canPopHistory();\n  }\n\n  Future<bool> canPopPage() {\n    return SynchronousFuture(_canPopPage());\n  }\n\n  bool _canPop(mode) {\n    switch (mode) {\n      case PopMode.history:\n        return _canPopHistory();\n      case PopMode.page:\n      default:\n        return _canPopPage();\n    }\n  }\n\n  /// gets the visual pages from the current _activePages entry\n  ///\n  /// visual pages must have [GetPage.participatesInRootNavigator] set to true\n  Iterable<GetPage> getVisualPages(RouteDecoder? currentHistory) {\n    final res = currentHistory!.currentTreeBranch\n        .where((r) => r.participatesInRootNavigator != null);\n    if (res.isEmpty) {\n      //default behavior, all routes participate in root navigator\n      return _activePages.map((e) => e.route!);\n    } else {\n      //user specified at least one participatesInRootNavigator\n      return res\n          .where((element) => element.participatesInRootNavigator == true);\n    }\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    final currentHistory = currentConfiguration;\n    final pages = currentHistory == null\n        ? <GetPage>[]\n        : pickPagesForRootNavigator?.call(currentHistory).toList() ??\n            getVisualPages(currentHistory).toList();\n    if (pages.isEmpty) {\n      return ColoredBox(\n        color: Theme.of(context).scaffoldBackgroundColor,\n      );\n    }\n    return GetNavigator(\n      key: navigatorKey,\n      onPopPage: _onPopVisualRoute,\n      pages: pages,\n      observers: navigatorObservers,\n      transitionDelegate:\n          transitionDelegate ?? const DefaultTransitionDelegate<dynamic>(),\n    );\n  }\n\n  @override\n  Future<void> goToUnknownPage([bool clearPages = false]) async {\n    if (clearPages) _activePages.clear();\n\n    final pageSettings = _buildPageSettings(notFoundRoute.name);\n    final routeDecoder = _getRouteDecoder(pageSettings);\n\n    _push(routeDecoder!);\n  }\n\n  @protected\n  void _popWithResult<T>([T? result]) {\n    final completer = _activePages.removeLast().route?.completer;\n    if (completer?.isCompleted == false) completer!.complete(result);\n  }\n\n  @override\n  Future<T?> toNamed<T>(\n    String page, {\n    dynamic arguments,\n    dynamic id,\n    bool preventDuplicates = true,\n    Map<String, String>? parameters,\n  }) async {\n    final args = _buildPageSettings(page, arguments);\n    final route = _getRouteDecoder<T>(args);\n    if (route != null) {\n      return _push<T>(route);\n    } else {\n      goToUnknownPage();\n    }\n    return null;\n  }\n\n  @override\n  Future<T?> to<T>(\n    Widget Function() page, {\n    bool? opaque,\n    Transition? transition,\n    Curve? curve,\n    Duration? duration,\n    String? id,\n    String? routeName,\n    bool fullscreenDialog = false,\n    dynamic arguments,\n    List<BindingsInterface> bindings = const [],\n    bool preventDuplicates = true,\n    bool? popGesture,\n    bool showCupertinoParallax = true,\n    double Function(BuildContext context)? gestureWidth,\n    bool rebuildStack = true,\n    PreventDuplicateHandlingMode preventDuplicateHandlingMode =\n        PreventDuplicateHandlingMode.reorderRoutes,\n  }) async {\n    routeName ??= _cleanRouteName(\"/${page.runtimeType}\");\n    // if (preventDuplicateHandlingMode ==\n    //PreventDuplicateHandlingMode.Recreate) {\n    //   routeName = routeName + page.hashCode.toString();\n    // }\n\n    final getPage = GetPage<T>(\n      name: routeName,\n      opaque: opaque ?? true,\n      page: page,\n      gestureWidth: gestureWidth,\n      showCupertinoParallax: showCupertinoParallax,\n      popGesture: popGesture ?? Get.defaultPopGesture,\n      transition: transition ?? Get.defaultTransition,\n      curve: curve ?? Get.defaultTransitionCurve,\n      fullscreenDialog: fullscreenDialog,\n      bindings: bindings,\n      transitionDuration: duration ?? Get.defaultTransitionDuration,\n      preventDuplicateHandlingMode: preventDuplicateHandlingMode,\n    );\n\n    _routeTree.addRoute(getPage);\n    final args = _buildPageSettings(routeName, arguments);\n    final route = _getRouteDecoder<T>(args);\n    final result = await _push<T>(\n      route!,\n      rebuildStack: rebuildStack,\n    );\n    _routeTree.removeRoute(getPage);\n    return result;\n  }\n\n  @override\n  Future<T?> off<T>(\n    Widget Function() page, {\n    bool? opaque,\n    Transition? transition,\n    Curve? curve,\n    Duration? duration,\n    String? id,\n    String? routeName,\n    bool fullscreenDialog = false,\n    dynamic arguments,\n    List<BindingsInterface> bindings = const [],\n    bool preventDuplicates = true,\n    bool? popGesture,\n    bool showCupertinoParallax = true,\n    double Function(BuildContext context)? gestureWidth,\n  }) async {\n    routeName ??= _cleanRouteName(\"/${page.runtimeType}\");\n    final route = GetPage<T>(\n      name: routeName,\n      opaque: opaque ?? true,\n      page: page,\n      gestureWidth: gestureWidth,\n      showCupertinoParallax: showCupertinoParallax,\n      popGesture: popGesture ?? Get.defaultPopGesture,\n      transition: transition ?? Get.defaultTransition,\n      curve: curve ?? Get.defaultTransitionCurve,\n      fullscreenDialog: fullscreenDialog,\n      bindings: bindings,\n      transitionDuration: duration ?? Get.defaultTransitionDuration,\n    );\n\n    final args = _buildPageSettings(routeName, arguments);\n    return _replace(args, route);\n  }\n\n  @override\n  Future<T?>? offAll<T>(\n    Widget Function() page, {\n    bool Function(GetPage route)? predicate,\n    bool opaque = true,\n    bool? popGesture,\n    String? id,\n    String? routeName,\n    dynamic arguments,\n    List<BindingsInterface> bindings = const [],\n    bool fullscreenDialog = false,\n    Transition? transition,\n    Curve? curve,\n    Duration? duration,\n    bool showCupertinoParallax = true,\n    double Function(BuildContext context)? gestureWidth,\n  }) async {\n    routeName ??= _cleanRouteName(\"/${page.runtimeType}\");\n    final route = GetPage<T>(\n      name: routeName,\n      opaque: opaque,\n      page: page,\n      gestureWidth: gestureWidth,\n      showCupertinoParallax: showCupertinoParallax,\n      popGesture: popGesture ?? Get.defaultPopGesture,\n      transition: transition ?? Get.defaultTransition,\n      curve: curve ?? Get.defaultTransitionCurve,\n      fullscreenDialog: fullscreenDialog,\n      bindings: bindings,\n      transitionDuration: duration ?? Get.defaultTransitionDuration,\n    );\n\n    final args = _buildPageSettings(routeName, arguments);\n\n    final newPredicate = predicate ?? (route) => false;\n\n    while (_activePages.length > 1 && !newPredicate(_activePages.last.route!)) {\n      _popWithResult();\n    }\n\n    return _replace(args, route);\n  }\n\n  @override\n  Future<T?>? offAllNamed<T>(\n    String newRouteName, {\n    // bool Function(GetPage route)? predicate,\n    dynamic arguments,\n    String? id,\n    Map<String, String>? parameters,\n  }) async {\n    final args = _buildPageSettings(newRouteName, arguments);\n    final route = _getRouteDecoder<T>(args);\n    if (route == null) return null;\n\n    while (_activePages.length > 1) {\n      _activePages.removeLast();\n    }\n\n    return _replaceNamed(route);\n  }\n\n  @override\n  Future<T?>? offNamedUntil<T>(\n    String page, {\n    bool Function(GetPage route)? predicate,\n    dynamic arguments,\n    String? id,\n    Map<String, String>? parameters,\n  }) async {\n    final args = _buildPageSettings(page, arguments);\n    final route = _getRouteDecoder<T>(args);\n    if (route == null) return null;\n\n    final newPredicate = predicate ?? (route) => false;\n\n    while (_activePages.length > 1 && !newPredicate(_activePages.last.route!)) {\n      _activePages.removeLast();\n    }\n\n    return _push(route);\n  }\n\n  @override\n  Future<T?> offNamed<T>(\n    String page, {\n    dynamic arguments,\n    String? id,\n    Map<String, String>? parameters,\n  }) async {\n    final args = _buildPageSettings(page, arguments);\n    final route = _getRouteDecoder<T>(args);\n    if (route == null) return null;\n    _popWithResult();\n    return _push<T>(route);\n  }\n\n  @override\n  Future<T?> toNamedAndOffUntil<T>(\n    String page,\n    bool Function(GetPage) predicate, [\n    Object? data,\n  ]) async {\n    final arguments = _buildPageSettings(page, data);\n\n    final route = _getRouteDecoder<T>(arguments);\n\n    if (route == null) return null;\n\n    while (_activePages.isNotEmpty && !predicate(_activePages.last.route!)) {\n      _popWithResult();\n    }\n\n    return _push<T>(route);\n  }\n\n  @override\n  Future<T?> offUntil<T>(\n    Widget Function() page,\n    bool Function(GetPage) predicate, [\n    Object? arguments,\n  ]) async {\n    while (_activePages.isNotEmpty && !predicate(_activePages.last.route!)) {\n      _popWithResult();\n    }\n\n    return to<T>(page, arguments: arguments);\n  }\n\n  @override\n  void removeRoute<T>(String name) {\n    _activePages.remove(RouteDecoder.fromRoute(name));\n  }\n\n  bool get canBack {\n    return _activePages.length > 1;\n  }\n\n  void _checkIfCanBack() {\n    assert(() {\n      if (!canBack) {\n        final last = _activePages.last;\n        final name = last.route?.name;\n        throw 'The page $name cannot be popped';\n      }\n      return true;\n    }());\n  }\n\n  @override\n  Future<R?> backAndtoNamed<T, R>(String page,\n      {T? result, Object? arguments}) async {\n    final args = _buildPageSettings(page, arguments);\n    final route = _getRouteDecoder<R>(args);\n    if (route == null) return null;\n    _popWithResult<T>(result);\n    return _push<R>(route);\n  }\n\n  /// Removes routes according to [PopMode]\n  /// until it reaches the specific [fullRoute],\n  /// DOES NOT remove the [fullRoute]\n  @override\n  Future<void> popModeUntil(\n    String fullRoute, {\n    PopMode popMode = PopMode.history,\n  }) async {\n    // remove history or page entries until you meet route\n    var iterator = currentConfiguration;\n    while (_canPop(popMode) && iterator != null) {\n      //the next line causes wasm compile error if included in the while loop\n      //https://github.com/flutter/flutter/issues/140110\n      if (iterator.pageSettings?.name == fullRoute) {\n        break;\n      }\n      await _pop(popMode, null);\n      // replace iterator\n      iterator = currentConfiguration;\n    }\n    notifyListeners();\n  }\n\n  @override\n  void backUntil(bool Function(GetPage) predicate) {\n    while (_activePages.length > 1 && !predicate(_activePages.last.route!)) {\n      _popWithResult();\n    }\n\n    notifyListeners();\n  }\n\n  Future<T?> _replace<T>(PageSettings arguments, GetPage<T> page) async {\n    final index = _activePages.length > 1 ? _activePages.length - 1 : 0;\n    _routeTree.addRoute(page);\n\n    final activePage = _getRouteDecoder(arguments);\n\n    // final activePage = _configureRouterDecoder<T>(route!, arguments);\n\n    _activePages[index] = activePage!;\n\n    notifyListeners();\n    final result = await activePage.route?.completer?.future as Future<T?>?;\n    _routeTree.removeRoute(page);\n\n    return result;\n  }\n\n  Future<T?> _replaceNamed<T>(RouteDecoder activePage) async {\n    final index = _activePages.length > 1 ? _activePages.length - 1 : 0;\n    // final activePage = _configureRouterDecoder<T>(page, arguments);\n    _activePages[index] = activePage;\n\n    notifyListeners();\n    final result = await activePage.route?.completer?.future as Future<T?>?;\n    return result;\n  }\n\n  /// Takes a route [name] String generated by [to], [off], [offAll]\n  /// (and similar context navigation methods), cleans the extra chars and\n  /// accommodates the format.\n  /// TODO: check for a more \"appealing\" URL naming convention.\n  /// `() => MyHomeScreenView` becomes `/my-home-screen-view`.\n  String _cleanRouteName(String name) {\n    name = name.replaceAll('() => ', '');\n\n    /// uncomment for URL styling.\n    // name = name.paramCase!;\n    if (!name.startsWith('/')) {\n      name = '/$name';\n    }\n    return Uri.tryParse(name)?.toString() ?? name;\n  }\n\n  PageSettings _buildPageSettings(String page, [Object? data]) {\n    var uri = Uri.parse(page);\n    return PageSettings(uri, data);\n  }\n\n  @protected\n  RouteDecoder? _getRouteDecoder<T>(PageSettings arguments) {\n    var page = arguments.uri.path;\n    final parameters = arguments.params;\n    if (parameters.isNotEmpty) {\n      final uri = Uri(path: page, queryParameters: parameters);\n      page = uri.toString();\n    }\n\n    final decoder = _routeTree.matchRoute(page, arguments: arguments);\n    final route = decoder.route;\n    if (route == null) return null;\n\n    return _configureRouterDecoder<T>(decoder, arguments);\n  }\n\n  @protected\n  RouteDecoder _configureRouterDecoder<T>(\n      RouteDecoder decoder, PageSettings arguments) {\n    final parameters =\n        arguments.params.isEmpty ? arguments.query : arguments.params;\n    arguments.params.addAll(arguments.query);\n    if (decoder.parameters.isEmpty) {\n      decoder.parameters.addAll(parameters);\n    }\n\n    decoder.route = decoder.route?.copyWith(\n      completer: _activePages.isEmpty ? null : Completer<T?>(),\n      arguments: arguments,\n      parameters: parameters,\n      key: ValueKey(arguments.name),\n    );\n\n    return decoder;\n  }\n\n  Future<T?> _push<T>(RouteDecoder decoder, {bool rebuildStack = true}) async {\n    var res = await runMiddleware(decoder);\n    if (res == null) return null;\n    // final res = mid ?? decoder;\n    // if (res == null) res = decoder;\n\n    final preventDuplicateHandlingMode =\n        res.route?.preventDuplicateHandlingMode ??\n            PreventDuplicateHandlingMode.reorderRoutes;\n\n    final onStackPage = _activePages\n        .firstWhereOrNull((element) => element.route?.key == res.route?.key);\n\n    /// There are no duplicate routes in the stack\n    if (onStackPage == null) {\n      _activePages.add(res);\n    } else {\n      /// There are duplicate routes, reorder\n      switch (preventDuplicateHandlingMode) {\n        case PreventDuplicateHandlingMode.doNothing:\n          break;\n        case PreventDuplicateHandlingMode.reorderRoutes:\n          _activePages.remove(onStackPage);\n          _activePages.add(res);\n          break;\n        case PreventDuplicateHandlingMode.popUntilOriginalRoute:\n          while (_activePages.last == onStackPage) {\n            _popWithResult();\n          }\n          break;\n        case PreventDuplicateHandlingMode.recreate:\n          _activePages.remove(onStackPage);\n          _activePages.add(res);\n      }\n    }\n    if (rebuildStack) {\n      notifyListeners();\n    }\n\n    return decoder.route?.completer?.future as Future<T?>?;\n  }\n\n  @override\n  Future<void> setNewRoutePath(RouteDecoder configuration) async {\n    final page = configuration.route;\n    if (page == null) {\n      goToUnknownPage();\n      return;\n    } else {\n      _push(configuration);\n    }\n  }\n\n  @override\n  RouteDecoder? get currentConfiguration {\n    if (_activePages.isEmpty) return null;\n    final route = _activePages.last;\n    return route;\n  }\n\n  Future<bool> handlePopupRoutes({\n    Object? result,\n  }) async {\n    Route? currentRoute;\n    navigatorKey.currentState!.popUntil((route) {\n      currentRoute = route;\n      return true;\n    });\n    if (currentRoute is PopupRoute) {\n      return await navigatorKey.currentState!.maybePop(result);\n    }\n    return false;\n  }\n\n  @override\n  Future<bool> popRoute({\n    Object? result,\n    PopMode? popMode,\n  }) async {\n    //Returning false will cause the entire app to be popped.\n    final wasPopup = await handlePopupRoutes(result: result);\n    if (wasPopup) return true;\n\n    if (_canPop(popMode ?? backButtonPopMode)) {\n      await _pop(popMode ?? backButtonPopMode, result);\n      notifyListeners();\n      return true;\n    }\n\n    return super.popRoute();\n  }\n\n  @override\n  void back<T>([T? result]) {\n    _checkIfCanBack();\n    _popWithResult<T>(result);\n    notifyListeners();\n  }\n\n  bool _onPopVisualRoute(Route<dynamic> route, dynamic result) {\n    final didPop = route.didPop(result);\n    if (!didPop) {\n      return false;\n    }\n    _popWithResult(result);\n    // final settings = route.settings;\n    // if (settings is GetPage) {\n    //   final config = _activePages.cast<RouteDecoder?>().firstWhere(\n    //         (element) => element?.route == settings,\n    //         orElse: () => null,\n    //       );\n    //   if (config != null) {\n    //     _removeHistoryEntry(config, result);\n    //   }\n    // }\n    notifyListeners();\n    //return !route.navigator!.userGestureInProgress;\n    return true;\n  }\n}\n"
  },
  {
    "path": "lib/get_navigation/src/routes/get_transition_mixin.dart",
    "content": "import 'dart:math';\nimport 'dart:ui';\n\nimport 'package:flutter/cupertino.dart';\nimport 'package:flutter/foundation.dart';\nimport 'package:flutter/gestures.dart';\nimport 'package:flutter/material.dart';\n\nimport '../../../get.dart';\nimport '../root/get_root.dart';\n\nconst double _kBackGestureWidth = 20.0;\n\nconst double _kMinFlingVelocity = 1; // Screen widths per second.\n\n// An eyeballed value for the maximum time it takes for a page to animate\n// forward if the user releases a page mid swipe.\nconst int _kMaxMidSwipePageForwardAnimationTime = 800; // Milliseconds.\n\n// The maximum time for a page to get reset to it's original position if the\n// user releases a page mid swipe.\nconst int _kMaxPageBackAnimationTime = 300; // Milliseconds.\n\nclass GetBackGestureDetector<T> extends StatefulWidget {\n  const GetBackGestureDetector({\n    super.key,\n    required this.limitedSwipe,\n    required this.gestureWidth,\n    required this.initialOffset,\n    required this.popGestureEnable,\n    required this.onStartPopGesture,\n    required this.child,\n  });\n\n  final bool limitedSwipe;\n  final double gestureWidth;\n  final double initialOffset;\n\n  final Widget child;\n  final ValueGetter<bool> popGestureEnable;\n  final ValueGetter<GetBackGestureController<T>> onStartPopGesture;\n\n  @override\n  GetBackGestureDetectorState<T> createState() =>\n      GetBackGestureDetectorState<T>();\n}\n\nclass GetBackGestureDetectorState<T> extends State<GetBackGestureDetector<T>> {\n  GetBackGestureController<T>? _backGestureController;\n\n  void _handleDragStart(DragStartDetails details) {\n    assert(mounted);\n    assert(_backGestureController == null);\n    _backGestureController = widget.onStartPopGesture();\n  }\n\n  void _handleDragUpdate(DragUpdateDetails details) {\n    assert(mounted);\n    assert(_backGestureController != null);\n    _backGestureController!.dragUpdate(\n      _convertToLogical(details.primaryDelta! / context.size!.width),\n    );\n  }\n\n  void _handleDragEnd(DragEndDetails details) {\n    assert(mounted);\n    assert(_backGestureController != null);\n    _backGestureController!.dragEnd(_convertToLogical(\n      details.velocity.pixelsPerSecond.dx / context.size!.width,\n    ));\n    _backGestureController = null;\n  }\n\n  void _handleDragCancel() {\n    assert(mounted);\n    // This can be called even if start is not called, paired with the \"down\"\n    // event that we don't consider here.\n    _backGestureController?.dragEnd(0);\n    _backGestureController = null;\n  }\n\n  double _convertToLogical(double value) {\n    switch (Directionality.of(context)) {\n      case TextDirection.rtl:\n        return -value;\n      case TextDirection.ltr:\n        return value;\n    }\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    assert(debugCheckHasDirectionality(context));\n\n    final gestureDetector = RawGestureDetector(\n      behavior: HitTestBehavior.translucent,\n      gestures: {\n        _DirectionalityDragGestureRecognizer:\n            GestureRecognizerFactoryWithHandlers<\n                _DirectionalityDragGestureRecognizer>(\n          () {\n            final directionality = Directionality.of(context);\n            return _DirectionalityDragGestureRecognizer(\n              debugOwner: this,\n              isRTL: directionality == TextDirection.rtl,\n              isLTR: directionality == TextDirection.ltr,\n              hasbackGestureController: () => _backGestureController != null,\n              popGestureEnable: widget.popGestureEnable,\n            );\n          },\n          (directionalityDragGesture) => directionalityDragGesture\n            ..onStart = _handleDragStart\n            ..onUpdate = _handleDragUpdate\n            ..onEnd = _handleDragEnd\n            ..onCancel = _handleDragCancel,\n        )\n      },\n    );\n\n    return Stack(\n      fit: StackFit.passthrough,\n      children: [\n        widget.child,\n        if (widget.limitedSwipe)\n          PositionedDirectional(\n            start: widget.initialOffset,\n            width: _dragAreaWidth(context),\n            top: 0,\n            bottom: 0,\n            child: gestureDetector,\n          )\n        else\n          Positioned.fill(child: gestureDetector),\n      ],\n    );\n  }\n\n  double _dragAreaWidth(BuildContext context) {\n    // For devices with notches, the drag area needs to be larger on the side\n    // that has the notch.\n    final dragAreaWidth = Directionality.of(context) == TextDirection.ltr\n        ? context.mediaQuery.padding.left\n        : context.mediaQuery.padding.right;\n    return max(dragAreaWidth, widget.gestureWidth);\n  }\n}\n\nclass GetBackGestureController<T> {\n  GetBackGestureController({\n    required this.navigator,\n    required this.controller,\n  }) {\n    navigator.didStartUserGesture();\n  }\n\n  final AnimationController controller;\n  final NavigatorState navigator;\n\n  /// The drag gesture has changed by [delta]. The total range of the\n  /// drag should be 0.0 to 1.0.\n  void dragUpdate(double delta) {\n    controller.value -= delta;\n  }\n\n  /// The drag gesture has ended with a horizontal motion of [velocity] as a\n  /// fraction of screen width per second.\n  void dragEnd(double velocity) {\n    // Fling in the appropriate direction.\n    // AnimationController.fling is guaranteed to\n    // take at least one frame.\n    //\n    // This curve has been determined through rigorously eyeballing native iOS\n    // animations.\n    const Curve animationCurve = Curves.fastLinearToSlowEaseIn;\n    final bool animateForward;\n\n    // If the user releases the page before mid screen with sufficient velocity,\n    // or after mid screen, we should animate the page out. Otherwise, the page\n    // should be animated back in.\n    if (velocity.abs() >= _kMinFlingVelocity) {\n      animateForward = velocity <= 0;\n    } else {\n      animateForward = controller.value > 0.5;\n    }\n\n    if (animateForward) {\n      // The closer the panel is to dismissing, the shorter the animation is.\n      // We want to cap the animation time, but we want to use a linear curve\n      // to determine it.\n      final droppedPageForwardAnimationTime = min(\n        lerpDouble(_kMaxMidSwipePageForwardAnimationTime, 0, controller.value)!\n            .floor(),\n        _kMaxPageBackAnimationTime,\n      );\n      controller.animateTo(1.0,\n          duration: Duration(milliseconds: droppedPageForwardAnimationTime),\n          curve: animationCurve);\n    } else {\n      // This route is destined to pop at this point. Reuse navigator's pop.\n      Get.back();\n\n      // The popping may have finished inline if already at the\n      // target destination.\n      if (controller.isAnimating) {\n        // Otherwise, use a custom popping animation duration and curve.\n        final droppedPageBackAnimationTime = lerpDouble(\n                0, _kMaxMidSwipePageForwardAnimationTime, controller.value)!\n            .floor();\n        controller.animateBack(0.0,\n            duration: Duration(milliseconds: droppedPageBackAnimationTime),\n            curve: animationCurve);\n      }\n    }\n\n    if (controller.isAnimating) {\n      // Keep the userGestureInProgress in true state so we don't change the\n      // curve of the page transition mid-flight since CupertinoPageTransition\n      // depends on userGestureInProgress.\n      late AnimationStatusListener animationStatusCallback;\n      animationStatusCallback = (status) {\n        navigator.didStopUserGesture();\n        controller.removeStatusListener(animationStatusCallback);\n      };\n      controller.addStatusListener(animationStatusCallback);\n    } else {\n      navigator.didStopUserGesture();\n    }\n  }\n}\n\nmixin GetPageRouteTransitionMixin<T> on PageRoute<T> {\n  ValueNotifier<String?>? _previousTitle;\n\n  @override\n  Color? get barrierColor => null;\n\n  @override\n  String? get barrierLabel => null;\n\n  double Function(BuildContext context)? get gestureWidth;\n\n  /// True if an iOS-style back swipe pop gesture is currently\n  /// underway for this route.\n  ///\n  /// See also:\n  ///\n  ///  * [isPopGestureInProgress], which returns true if a Cupertino pop gesture\n  ///    is currently underway for specific route.\n  ///  * [popGestureEnabled], which returns true if a user-triggered pop gesture\n  ///    would be allowed.\n  //bool get popGestureInProgress => isPopGestureInProgress(this);\n\n  /// The title string of the previous [CupertinoPageRoute].\n  ///\n  /// The [ValueListenable]'s value is readable after the route is installed\n  /// onto a [Navigator]. The [ValueListenable] will also notify its listeners\n  /// if the value changes (such as by replacing the previous route).\n  ///\n  /// The [ValueListenable] itself will be null before the route is installed.\n  /// Its content value will be null if the previous route has no title or\n  /// is not a [CupertinoPageRoute].\n  ///\n  /// See also:\n  ///\n  ///  * [ValueListenableBuilder], which can be used to listen and rebuild\n  ///    widgets based on a ValueListenable.\n  ValueListenable<String?> get previousTitle {\n    assert(\n      _previousTitle != null,\n      '''\nCannot read the previousTitle for a route that has not yet been installed''',\n    );\n    return _previousTitle!;\n  }\n\n  bool get showCupertinoParallax;\n\n  /// {@template flutter.cupertino.CupertinoRouteTransitionMixin.title}\n  /// A title string for this route.\n  ///\n  /// Used to auto-populate [CupertinoNavigationBar] and\n  /// [CupertinoSliverNavigationBar]'s `middle`/`largeTitle` widgets when\n  /// one is not manually supplied.\n  /// {@endtemplate}\n  String? get title;\n\n  @override\n  // A relatively rigorous eyeball estimation.\n  Duration get transitionDuration;\n\n  @override\n  Duration get reverseTransitionDuration;\n\n  /// Builds the primary contents of the route.\n  @protected\n  Widget buildContent(BuildContext context);\n\n  @override\n  Widget buildPage(BuildContext context, Animation<double> animation,\n      Animation<double> secondaryAnimation) {\n    final child = buildContent(context);\n    final Widget result = Semantics(\n      scopesRoute: true,\n      explicitChildNodes: true,\n      child: child,\n    );\n    return result;\n  }\n\n  @override\n  Widget buildTransitions(BuildContext context, Animation<double> animation,\n      Animation<double> secondaryAnimation, Widget child) {\n    return buildPageTransitions<T>(\n        this, context, animation, secondaryAnimation, child);\n  }\n\n  @override\n  bool canTransitionTo(TransitionRoute<dynamic> nextRoute) {\n    // Don't perform outgoing animation if the next route is a\n    // fullscreen dialog.\n    return (nextRoute is GetPageRouteTransitionMixin &&\n            !nextRoute.fullscreenDialog &&\n            nextRoute.showCupertinoParallax) ||\n        (nextRoute is CupertinoRouteTransitionMixin &&\n            !nextRoute.fullscreenDialog) ||\n        (nextRoute is CupertinoSheetRoute &&\n            !nextRoute.fullscreenDialog);\n  }\n\n  @override\n  void didChangePrevious(Route<dynamic>? previousRoute) {\n    final previousTitleString = previousRoute is CupertinoRouteTransitionMixin\n        ? previousRoute.title\n        : null;\n    if (_previousTitle == null) {\n      _previousTitle = ValueNotifier<String?>(previousTitleString);\n    } else {\n      _previousTitle!.value = previousTitleString;\n    }\n    super.didChangePrevious(previousRoute);\n  }\n\n  static bool canSwipe(GetPageRoute route) =>\n      route.popGesture ?? Get.defaultPopGesture ?? GetPlatform.isIOS;\n\n  /// Returns a [CupertinoFullscreenDialogTransition] if [route] is a full\n  /// screen dialog, otherwise a [CupertinoPageTransition] is returned.\n  ///\n  /// Used by [CupertinoPageRoute.buildTransitions].\n  ///\n  /// This method can be applied to any [PageRoute], not just\n  /// [CupertinoPageRoute]. It's typically used to provide a Cupertino style\n  /// horizontal transition for material widgets when the target platform\n  /// is [TargetPlatform.iOS].\n  ///\n  /// See also:\n  ///\n  ///  * [CupertinoPageTransitionsBuilder], which uses this method to define a\n  ///    [PageTransitionsBuilder] for the [PageTransitionsTheme].\n  static Widget buildPageTransitions<T>(\n    PageRoute<T> rawRoute,\n    BuildContext context,\n    Animation<double> animation,\n    Animation<double> secondaryAnimation,\n    Widget child, {\n    bool limitedSwipe = false,\n    double initialOffset = 0,\n  }) {\n    // Check if the route has an animation that's currently participating\n    // in a back swipe gesture.\n    //\n    // In the middle of a back gesture drag, let the transition be linear to\n    // match finger motions.\n    final route = rawRoute as GetPageRoute<T>;\n    final linearTransition = route.popGestureInProgress;\n    final finalCurve = route.curve ?? Get.defaultTransitionCurve;\n    final hasCurve = route.curve != null;\n    if (route.fullscreenDialog && route.transition == null) {\n      return CupertinoFullscreenDialogTransition(\n        primaryRouteAnimation: hasCurve\n            ? CurvedAnimation(parent: animation, curve: finalCurve)\n            : animation,\n        secondaryRouteAnimation: secondaryAnimation,\n        linearTransition: linearTransition,\n        child: child,\n      );\n    } else {\n      if (route.customTransition != null) {\n        return route.customTransition!.buildTransition(\n          context,\n          finalCurve,\n          route.alignment,\n          animation,\n          secondaryAnimation,\n          GetBackGestureDetector<T>(\n            popGestureEnable: () =>\n                _isPopGestureEnabled(route, canSwipe(route), context),\n            onStartPopGesture: () {\n              assert(_isPopGestureEnabled(route, canSwipe(route), context));\n              return _startPopGesture(route);\n            },\n            limitedSwipe: limitedSwipe,\n            gestureWidth:\n                route.gestureWidth?.call(context) ?? _kBackGestureWidth,\n            initialOffset: initialOffset,\n            child: child,\n          ),\n        );\n      }\n\n      /// Apply the curve by default...\n      final iosAnimation = animation;\n      animation = CurvedAnimation(parent: animation, curve: finalCurve);\n\n      switch (route.transition ?? Get.defaultTransition) {\n        case Transition.leftToRight:\n          return SlideLeftTransition().buildTransitions(\n              context,\n              route.curve,\n              route.alignment,\n              animation,\n              secondaryAnimation,\n              GetBackGestureDetector<T>(\n                popGestureEnable: () =>\n                    _isPopGestureEnabled(route, canSwipe(route), context),\n                onStartPopGesture: () {\n                  assert(_isPopGestureEnabled(route, canSwipe(route), context));\n                  return _startPopGesture(route);\n                },\n                limitedSwipe: limitedSwipe,\n                gestureWidth:\n                    route.gestureWidth?.call(context) ?? _kBackGestureWidth,\n                initialOffset: initialOffset,\n                child: child,\n              ));\n\n        case Transition.downToUp:\n          return SlideDownTransition().buildTransitions(\n              context,\n              route.curve,\n              route.alignment,\n              animation,\n              secondaryAnimation,\n              GetBackGestureDetector<T>(\n                popGestureEnable: () =>\n                    _isPopGestureEnabled(route, canSwipe(route), context),\n                onStartPopGesture: () {\n                  assert(_isPopGestureEnabled(route, canSwipe(route), context));\n                  return _startPopGesture(route);\n                },\n                limitedSwipe: limitedSwipe,\n                gestureWidth:\n                    route.gestureWidth?.call(context) ?? _kBackGestureWidth,\n                initialOffset: initialOffset,\n                child: child,\n              ));\n\n        case Transition.upToDown:\n          return SlideTopTransition().buildTransitions(\n              context,\n              route.curve,\n              route.alignment,\n              animation,\n              secondaryAnimation,\n              GetBackGestureDetector<T>(\n                popGestureEnable: () =>\n                    _isPopGestureEnabled(route, canSwipe(route), context),\n                onStartPopGesture: () {\n                  assert(_isPopGestureEnabled(route, canSwipe(route), context));\n                  return _startPopGesture(route);\n                },\n                limitedSwipe: limitedSwipe,\n                gestureWidth:\n                    route.gestureWidth?.call(context) ?? _kBackGestureWidth,\n                initialOffset: initialOffset,\n                child: child,\n              ));\n\n        case Transition.noTransition:\n          return GetBackGestureDetector<T>(\n            popGestureEnable: () =>\n                _isPopGestureEnabled(route, canSwipe(route), context),\n            onStartPopGesture: () {\n              assert(_isPopGestureEnabled(route, canSwipe(route), context));\n              return _startPopGesture(route);\n            },\n            limitedSwipe: limitedSwipe,\n            gestureWidth:\n                route.gestureWidth?.call(context) ?? _kBackGestureWidth,\n            initialOffset: initialOffset,\n            child: child,\n          );\n\n        case Transition.rightToLeft:\n          return SlideRightTransition().buildTransitions(\n              context,\n              route.curve,\n              route.alignment,\n              animation,\n              secondaryAnimation,\n              GetBackGestureDetector<T>(\n                popGestureEnable: () =>\n                    _isPopGestureEnabled(route, canSwipe(route), context),\n                onStartPopGesture: () {\n                  assert(_isPopGestureEnabled(route, canSwipe(route), context));\n                  return _startPopGesture(route);\n                },\n                limitedSwipe: limitedSwipe,\n                gestureWidth:\n                    route.gestureWidth?.call(context) ?? _kBackGestureWidth,\n                initialOffset: initialOffset,\n                child: child,\n              ));\n\n        case Transition.zoom:\n          return ZoomInTransition().buildTransitions(\n              context,\n              route.curve,\n              route.alignment,\n              animation,\n              secondaryAnimation,\n              GetBackGestureDetector<T>(\n                popGestureEnable: () =>\n                    _isPopGestureEnabled(route, canSwipe(route), context),\n                onStartPopGesture: () {\n                  assert(_isPopGestureEnabled(route, canSwipe(route), context));\n                  return _startPopGesture(route);\n                },\n                limitedSwipe: limitedSwipe,\n                gestureWidth:\n                    route.gestureWidth?.call(context) ?? _kBackGestureWidth,\n                initialOffset: initialOffset,\n                child: child,\n              ));\n\n        case Transition.fadeIn:\n          return FadeInTransition().buildTransitions(\n              context,\n              route.curve,\n              route.alignment,\n              animation,\n              secondaryAnimation,\n              GetBackGestureDetector<T>(\n                popGestureEnable: () =>\n                    _isPopGestureEnabled(route, canSwipe(route), context),\n                onStartPopGesture: () {\n                  assert(_isPopGestureEnabled(route, canSwipe(route), context));\n                  return _startPopGesture(route);\n                },\n                limitedSwipe: limitedSwipe,\n                gestureWidth:\n                    route.gestureWidth?.call(context) ?? _kBackGestureWidth,\n                initialOffset: initialOffset,\n                child: child,\n              ));\n\n        case Transition.rightToLeftWithFade:\n          return RightToLeftFadeTransition().buildTransitions(\n              context,\n              route.curve,\n              route.alignment,\n              animation,\n              secondaryAnimation,\n              GetBackGestureDetector<T>(\n                popGestureEnable: () =>\n                    _isPopGestureEnabled(route, canSwipe(route), context),\n                onStartPopGesture: () {\n                  assert(_isPopGestureEnabled(route, canSwipe(route), context));\n                  return _startPopGesture(route);\n                },\n                limitedSwipe: limitedSwipe,\n                gestureWidth:\n                    route.gestureWidth?.call(context) ?? _kBackGestureWidth,\n                initialOffset: initialOffset,\n                child: child,\n              ));\n\n        case Transition.leftToRightWithFade:\n          return LeftToRightFadeTransition().buildTransitions(\n              context,\n              route.curve,\n              route.alignment,\n              animation,\n              secondaryAnimation,\n              GetBackGestureDetector<T>(\n                popGestureEnable: () =>\n                    _isPopGestureEnabled(route, canSwipe(route), context),\n                onStartPopGesture: () {\n                  assert(_isPopGestureEnabled(route, canSwipe(route), context));\n                  return _startPopGesture(route);\n                },\n                limitedSwipe: limitedSwipe,\n                gestureWidth:\n                    route.gestureWidth?.call(context) ?? _kBackGestureWidth,\n                initialOffset: initialOffset,\n                child: child,\n              ));\n\n        case Transition.cupertino:\n          return CupertinoPageTransition(\n              primaryRouteAnimation: animation,\n              secondaryRouteAnimation: secondaryAnimation,\n              linearTransition: linearTransition,\n              child: GetBackGestureDetector<T>(\n                popGestureEnable: () =>\n                    _isPopGestureEnabled(route, canSwipe(route), context),\n                onStartPopGesture: () {\n                  assert(_isPopGestureEnabled(route, canSwipe(route), context));\n                  return _startPopGesture(route);\n                },\n                limitedSwipe: limitedSwipe,\n                gestureWidth:\n                    route.gestureWidth?.call(context) ?? _kBackGestureWidth,\n                initialOffset: initialOffset,\n                child: child,\n              ));\n\n        case Transition.size:\n          return SizeTransitions().buildTransitions(\n              context,\n              route.curve!,\n              route.alignment,\n              animation,\n              secondaryAnimation,\n              GetBackGestureDetector<T>(\n                popGestureEnable: () =>\n                    _isPopGestureEnabled(route, canSwipe(route), context),\n                onStartPopGesture: () {\n                  assert(_isPopGestureEnabled(route, canSwipe(route), context));\n                  return _startPopGesture(route);\n                },\n                limitedSwipe: limitedSwipe,\n                gestureWidth:\n                    route.gestureWidth?.call(context) ?? _kBackGestureWidth,\n                initialOffset: initialOffset,\n                child: child,\n              ));\n\n        case Transition.fade:\n          return const FadeUpwardsPageTransitionsBuilder().buildTransitions(\n              route,\n              context,\n              animation,\n              secondaryAnimation,\n              GetBackGestureDetector<T>(\n                popGestureEnable: () =>\n                    _isPopGestureEnabled(route, canSwipe(route), context),\n                onStartPopGesture: () {\n                  assert(_isPopGestureEnabled(route, canSwipe(route), context));\n                  return _startPopGesture(route);\n                },\n                limitedSwipe: limitedSwipe,\n                gestureWidth:\n                    route.gestureWidth?.call(context) ?? _kBackGestureWidth,\n                initialOffset: initialOffset,\n                child: child,\n              ));\n\n        case Transition.topLevel:\n          return const ZoomPageTransitionsBuilder().buildTransitions(\n              route,\n              context,\n              animation,\n              secondaryAnimation,\n              GetBackGestureDetector<T>(\n                popGestureEnable: () =>\n                    _isPopGestureEnabled(route, canSwipe(route), context),\n                onStartPopGesture: () {\n                  assert(_isPopGestureEnabled(route, canSwipe(route), context));\n                  return _startPopGesture(route);\n                },\n                limitedSwipe: limitedSwipe,\n                gestureWidth:\n                    route.gestureWidth?.call(context) ?? _kBackGestureWidth,\n                initialOffset: initialOffset,\n                child: child,\n              ));\n\n        case Transition.native:\n          return const PageTransitionsTheme().buildTransitions(\n              route,\n              context,\n              iosAnimation,\n              secondaryAnimation,\n              GetBackGestureDetector<T>(\n                popGestureEnable: () =>\n                    _isPopGestureEnabled(route, canSwipe(route), context),\n                onStartPopGesture: () {\n                  assert(_isPopGestureEnabled(route, canSwipe(route), context));\n                  return _startPopGesture(route);\n                },\n                limitedSwipe: limitedSwipe,\n                gestureWidth:\n                    route.gestureWidth?.call(context) ?? _kBackGestureWidth,\n                initialOffset: initialOffset,\n                child: child,\n              ));\n\n        case Transition.circularReveal:\n          return CircularRevealTransition().buildTransitions(\n              context,\n              route.curve,\n              route.alignment,\n              animation,\n              secondaryAnimation,\n              GetBackGestureDetector<T>(\n                popGestureEnable: () =>\n                    _isPopGestureEnabled(route, canSwipe(route), context),\n                onStartPopGesture: () {\n                  assert(_isPopGestureEnabled(route, canSwipe(route), context));\n                  return _startPopGesture(route);\n                },\n                limitedSwipe: limitedSwipe,\n                gestureWidth:\n                    route.gestureWidth?.call(context) ?? _kBackGestureWidth,\n                initialOffset: initialOffset,\n                child: child,\n              ));\n\n        default:\n          final customTransition = GetRoot.of(context).config.customTransition;\n\n          if (customTransition != null) {\n            return customTransition.buildTransition(context, route.curve,\n                route.alignment, animation, secondaryAnimation, child);\n          }\n\n          PageTransitionsTheme pageTransitionsTheme =\n              Theme.of(context).pageTransitionsTheme;\n\n          return pageTransitionsTheme.buildTransitions(\n              route,\n              context,\n              iosAnimation,\n              secondaryAnimation,\n              GetBackGestureDetector<T>(\n                popGestureEnable: () =>\n                    _isPopGestureEnabled(route, canSwipe(route), context),\n                onStartPopGesture: () {\n                  assert(\n                    _isPopGestureEnabled(route, canSwipe(route), context),\n                  );\n                  return _startPopGesture(route);\n                },\n                limitedSwipe: limitedSwipe,\n                gestureWidth:\n                    route.gestureWidth?.call(context) ?? _kBackGestureWidth,\n                initialOffset: initialOffset,\n                child: child,\n              ));\n      }\n    }\n  }\n\n  // Called by GetBackGestureDetector when a pop (\"back\") drag start\n  // gesture is detected. The returned controller handles all of the subsequent\n  // drag events.\n  /// True if an iOS-style back swipe pop gesture is currently\n  /// underway for [route].\n  ///\n  /// This just check the route's [NavigatorState.userGestureInProgress].\n  ///\n  /// See also:\n  ///\n  ///  * [popGestureEnabled], which returns true if a user-triggered pop gesture\n  ///    would be allowed.\n  static bool isPopGestureInProgress(BuildContext context) {\n    final route = ModalRoute.of(context)!;\n    return route.navigator!.userGestureInProgress;\n  }\n\n  static bool _isPopGestureEnabled<T>(\n      PageRoute<T> route, bool canSwipe, BuildContext context) {\n    // If there's nothing to go back to, then obviously we don't support\n    // the back gesture.\n    if (route.isFirst) return false;\n    // If the route wouldn't actually pop if we popped it, then the gesture\n    // would be really confusing (or would skip internal routes),\n    // so disallow it.\n    if (route.willHandlePopInternally) return false;\n    // support [PopScope]\n    if (route.popDisposition == RoutePopDisposition.doNotPop) return false;\n    // Fullscreen dialogs aren't dismissible by back swipe.\n    if (route.fullscreenDialog) return false;\n    // If we're in an animation already, we cannot be manually swiped.\n    if (route.animation!.status != AnimationStatus.completed) return false;\n    // If we're being popped into, we also cannot be swiped until the pop above\n    // it completes. This translates to our secondary animation being\n    // dismissed.\n    if (route.secondaryAnimation!.status != AnimationStatus.dismissed) {\n      return false;\n    }\n    // If we're in a gesture already, we cannot start another.\n    if (GetPageRouteTransitionMixin.isPopGestureInProgress(context)) {\n      return false;\n    }\n\n    // Don't perfome swipe if canSwipe be false\n    if (!canSwipe) return false;\n\n    // Looks like a back gesture would be welcome!\n    return true;\n  }\n\n  static GetBackGestureController<T> _startPopGesture<T>(\n    PageRoute<T> route,\n  ) {\n    return GetBackGestureController<T>(\n      navigator: route.navigator!,\n      controller: route.controller!, // protected access\n    );\n  }\n}\n\nclass _DirectionalityDragGestureRecognizer\n    extends HorizontalDragGestureRecognizer {\n  final ValueGetter<bool> popGestureEnable;\n  final ValueGetter<bool> hasbackGestureController;\n  final bool isRTL;\n  final bool isLTR;\n\n  _DirectionalityDragGestureRecognizer({\n    required this.isRTL,\n    required this.isLTR,\n    required this.popGestureEnable,\n    required this.hasbackGestureController,\n    super.debugOwner,\n  });\n\n  @override\n  void handleEvent(PointerEvent event) {\n    final dx = event.delta.dx;\n    if (hasbackGestureController() ||\n        popGestureEnable() && (isRTL && dx < 0 || isLTR && dx > 0 || dx == 0)) {\n      super.handleEvent(event);\n    } else {\n      stopTrackingPointer(event.pointer);\n    }\n  }\n}\n"
  },
  {
    "path": "lib/get_navigation/src/routes/index.dart",
    "content": "export 'circular_reveal_clipper.dart';\nexport 'custom_transition.dart';\nexport 'default_route.dart';\nexport 'default_transitions.dart';\nexport 'get_information_parser.dart';\nexport 'get_navigation_interface.dart';\nexport 'get_navigator.dart';\nexport 'get_route.dart';\nexport 'get_router_delegate.dart';\nexport 'get_transition_mixin.dart';\nexport 'modules.dart';\nexport 'observers/route_observer.dart';\nexport 'page_settings.dart';\nexport 'parse_route.dart';\nexport 'route_middleware.dart';\nexport 'route_report.dart';\nexport 'router_outlet.dart';\nexport 'transitions_type.dart';\nexport 'url_strategy/url_strategy.dart';\n"
  },
  {
    "path": "lib/get_navigation/src/routes/modules.dart",
    "content": "import 'package:flutter/material.dart';\n\nimport '../../../instance_manager.dart';\nimport '../router_report.dart';\n\nclass Dependencies {\n  void lazyPut<S>(InstanceBuilderCallback<S> builder,\n      {String? tag, bool fenix = false}) {\n    Get.lazyPut<S>(builder, tag: tag, fenix: fenix);\n  }\n\n  S call<S>() {\n    return find<S>();\n  }\n\n  void spawn<S>(InstanceBuilderCallback<S> builder,\n          {String? tag, bool permanent = true}) =>\n      Get.spawn<S>(builder, tag: tag, permanent: permanent);\n\n  S find<S>({String? tag}) => Get.find<S>(tag: tag);\n\n  S put<S>(S dependency,\n          {String? tag,\n          bool permanent = false,\n          InstanceBuilderCallback<S>? builder}) =>\n      Get.put<S>(dependency, tag: tag, permanent: permanent);\n\n  Future<bool> delete<S>({String? tag, bool force = false}) async =>\n      Get.delete<S>(tag: tag, force: force);\n\n  Future<void> deleteAll({bool force = false}) async =>\n      Get.deleteAll(force: force);\n\n  void reloadAll({bool force = false}) => Get.reloadAll(force: force);\n\n  void reload<S>({String? tag, String? key, bool force = false}) =>\n      Get.reload<S>(tag: tag, key: key, force: force);\n\n  bool isRegistered<S>({String? tag}) => Get.isRegistered<S>(tag: tag);\n\n  bool isPrepared<S>({String? tag}) => Get.isPrepared<S>(tag: tag);\n\n  void replace<P>(P child, {String? tag}) {\n    final info = Get.getInstanceInfo<P>(tag: tag);\n    final permanent = (info.isPermanent ?? false);\n    delete<P>(tag: tag, force: permanent);\n    put(child, tag: tag, permanent: permanent);\n  }\n\n  void lazyReplace<P>(InstanceBuilderCallback<P> builder,\n      {String? tag, bool? fenix}) {\n    final info = Get.getInstanceInfo<P>(tag: tag);\n    final permanent = (info.isPermanent ?? false);\n    delete<P>(tag: tag, force: permanent);\n    lazyPut(builder, tag: tag, fenix: fenix ?? permanent);\n  }\n}\n\nabstract class Module extends StatefulWidget {\n  const Module({super.key});\n\n  Widget view(BuildContext context);\n\n  void dependencies(Dependencies i);\n\n  @override\n  ModuleState createState() => ModuleState();\n}\n\nclass ModuleState extends State<Module> {\n  @override\n  void initState() {\n    RouterReportManager.instance.reportCurrentRoute(this);\n    widget.dependencies(Dependencies());\n    super.initState();\n  }\n\n  @override\n  void dispose() {\n    RouterReportManager.instance.reportRouteDispose(this);\n    super.dispose();\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return widget.view(context);\n  }\n}\n"
  },
  {
    "path": "lib/get_navigation/src/routes/new_path_route.dart",
    "content": "import 'dart:async';\n\nimport 'package:flutter/widgets.dart';\n\nimport 'get_route.dart';\n\nclass RouteMatcher {\n  final RouteNode _root = RouteNode('/', '/');\n\n  RouteNode addRoute(String path) {\n    final segments = _parsePath(path);\n    var currentNode = _root;\n\n    for (final segment in segments) {\n      final existingChild = currentNode.findChild(segment);\n      if (existingChild != null) {\n        currentNode = existingChild;\n      } else {\n        final newChild = RouteNode(segment, path);\n        currentNode.addChild(newChild);\n        currentNode = newChild;\n      }\n    }\n    return currentNode;\n  }\n\n  void removeRoute(String path) {\n    final segments = _parsePath(path);\n    var currentNode = _root;\n    RouteNode? nodeToDelete;\n\n    // Traverse the tree to find the node to delete\n    for (final segment in segments) {\n      final child = currentNode.findChild(segment);\n      if (child == null) {\n        return; // Node not found, nothing to delete\n      }\n      if (child.nodeSegments.length == segments.length) {\n        nodeToDelete = child;\n        break;\n      }\n      currentNode = child;\n    }\n\n    if (nodeToDelete == null) {\n      return; // Node not found, nothing to delete\n    }\n\n    final parent = nodeToDelete.parent!;\n    parent.nodeSegments.remove(nodeToDelete);\n  }\n\n  RouteNode? _findChild(RouteNode currentNode, String segment) {\n    return currentNode.nodeSegments\n        .firstWhereOrNull((node) => node.matches(segment));\n  }\n\n  MatchResult? matchRoute(String path) {\n    final uri = Uri.parse(path);\n    final segments = _parsePath(uri.path);\n    var currentNode = _root;\n    final parameters = <String, String>{};\n    final urlParameters = uri.queryParameters;\n\n    for (final segment in segments) {\n      if (segment.isEmpty) continue;\n      final child = _findChild(currentNode, segment);\n      if (child == null) {\n        return null;\n      } else {\n        if (child.path.startsWith(':')) {\n          parameters[child.path.substring(1)] = segment;\n        }\n\n        if (child.nodeSegments.length == segments.length) {\n          return null;\n        }\n\n        currentNode = child;\n      }\n    }\n\n    return MatchResult(\n      currentNode,\n      parameters,\n      path,\n      urlParameters: urlParameters,\n    );\n  }\n\n  List<String> _parsePath(String path) {\n    return path.split('/').where((segment) => segment.isNotEmpty).toList();\n  }\n}\n\nclass RouteTreeResult {\n  final GetPage? route;\n  final MatchResult matchResult;\n\n  RouteTreeResult({\n    required this.route,\n    required this.matchResult,\n  });\n\n  @override\n  String toString() {\n    return 'RouteTreeResult(route: $route, matchResult: $matchResult)';\n  }\n\n  RouteTreeResult configure(String page, Object? arguments) {\n    return copyWith(\n        route: route?.copyWith(\n      key: ValueKey(page),\n      settings: RouteSettings(name: page, arguments: arguments),\n      completer: Completer(),\n      arguments: arguments,\n    ));\n  }\n\n  RouteTreeResult copyWith({\n    GetPage? route,\n    MatchResult? matchResult,\n  }) {\n    return RouteTreeResult(\n      route: route ?? this.route,\n      matchResult: matchResult ?? this.matchResult,\n    );\n  }\n}\n\nclass RouteTree {\n  static final instance = RouteTree();\n  final Map<String, GetPage> tree = {};\n  final RouteMatcher matcher = RouteMatcher();\n\n  void addRoute(GetPage route) {\n    matcher.addRoute(route.name);\n    tree[route.name] = route;\n    handleChild(route);\n  }\n\n  void addRoutes(List<GetPage> routes) {\n    for (var route in routes) {\n      addRoute(route);\n    }\n  }\n\n  void handleChild(GetPage route) {\n    final children = route.children;\n    for (var child in children) {\n      final middlewares = List.of(route.middlewares);\n      final bindings = List.of(route.bindings);\n      middlewares.addAll(child.middlewares);\n      bindings.addAll(child.bindings);\n      child = child.copyWith(middlewares: middlewares, bindings: bindings);\n      if (child.inheritParentPath) {\n        child = child.copyWith(\n            name: ('${route.path}/${child.path}').replaceAll(r'//', '/'));\n      }\n      addRoute(child);\n    }\n  }\n\n  void removeRoute(GetPage route) {\n    matcher.removeRoute(route.name);\n    tree.remove(route.name);\n  }\n\n  void removeRoutes(List<GetPage> routes) {\n    for (var route in routes) {\n      removeRoute(route);\n    }\n  }\n\n  RouteTreeResult? matchRoute(String path) {\n    final matchResult = matcher.matchRoute(path);\n    if (matchResult != null) {\n      final route = tree[matchResult.node.originalPath];\n      return RouteTreeResult(\n        route: route,\n        matchResult: matchResult,\n      );\n    }\n    return null;\n  }\n}\n\n/// A class representing the result of a route matching operation.\nclass MatchResult {\n  /// The route found that matches the result\n  final RouteNode node;\n\n  /// The current path of match, eg: adding 'user/:id' the match result for 'user/123' will be: 'user/123'\n  final String currentPath;\n\n  /// Route parameters eg: adding 'user/:id' the match result for 'user/123' will be: {id: 123}\n  final Map<String, String> parameters;\n\n  /// Route url parameters eg: adding 'user' the match result for 'user?foo=bar' will be: {foo: bar}\n  final Map<String, String> urlParameters;\n\n  MatchResult(this.node, this.parameters, this.currentPath,\n      {this.urlParameters = const {}});\n\n  @override\n  String toString() =>\n      'MatchResult(node: $node, currentPath: $currentPath, parameters: $parameters, urlParameters: $urlParameters)';\n}\n\n// A class representing a node in a routing tree.\nclass RouteNode {\n  String path;\n  String originalPath;\n  RouteNode? parent;\n  List<RouteNode> nodeSegments = [];\n\n  RouteNode(this.path, this.originalPath, {this.parent});\n\n  bool get isRoot => parent == null;\n\n  String get fullPath {\n    if (isRoot) {\n      return '/';\n    } else {\n      final parentPath = parent?.fullPath == '/' ? '' : parent?.fullPath;\n      return '$parentPath/$path';\n    }\n  }\n\n  bool get hasChildren => nodeSegments.isNotEmpty;\n\n  void addChild(RouteNode child) {\n    nodeSegments.add(child);\n    child.parent = this;\n  }\n\n  RouteNode? findChild(String name) {\n    return nodeSegments.firstWhereOrNull((node) => node.path == name);\n  }\n\n  bool matches(String name) {\n    return name == path || path == '*' || path.startsWith(':');\n  }\n\n  @override\n  String toString() =>\n      'RouteNode(name: $path, nodeSegments: $nodeSegments, fullPath: $fullPath )';\n}\n\nextension Foo<T> on Iterable<T> {\n  T? firstWhereOrNull(bool Function(T element) test) {\n    for (var element in this) {\n      if (test(element)) return element;\n    }\n    return null;\n  }\n}\n"
  },
  {
    "path": "lib/get_navigation/src/routes/observers/route_observer.dart",
    "content": "import 'package:flutter/widgets.dart';\n\nimport '../../../../get_core/get_core.dart';\nimport '../../../../instance_manager.dart';\nimport '../../../get_navigation.dart';\nimport '../../dialog/dialog_route.dart';\nimport '../../router_report.dart';\n\n/// Extracts the name of a route based on it's instance type\n/// or null if not possible.\nString? _extractRouteName(Route? route) {\n  if (route?.settings.name != null) {\n    return route!.settings.name;\n  }\n\n  if (route is GetPageRoute) {\n    return route.routeName;\n  }\n\n  if (route is GetDialogRoute) {\n    return 'DIALOG ${route.hashCode}';\n  }\n\n  if (route is GetModalBottomSheetRoute) {\n    return 'BOTTOMSHEET ${route.hashCode}';\n  }\n\n  return null;\n}\n\nclass GetObserver extends NavigatorObserver {\n  final Function(Routing?)? routing;\n\n  final Routing? _routeSend;\n\n  GetObserver([this.routing, this._routeSend]);\n\n  @override\n  void didPop(Route route, Route? previousRoute) {\n    super.didPop(route, previousRoute);\n    final currentRoute = _RouteData.ofRoute(route);\n    final newRoute = _RouteData.ofRoute(previousRoute);\n\n    if (currentRoute.isBottomSheet || currentRoute.isDialog) {\n      Get.log(\"CLOSE ${currentRoute.name}\");\n    } else if (currentRoute.isGetPageRoute) {\n      Get.log(\"CLOSE TO ROUTE ${currentRoute.name}\");\n    }\n    if (previousRoute != null) {\n      RouterReportManager.instance.reportCurrentRoute(previousRoute);\n    }\n\n    // Here we use a 'inverse didPush set', meaning that we use\n    // previous route instead of 'route' because this is\n    // a 'inverse push'\n    _routeSend?.update((value) {\n      // Only PageRoute is allowed to change current value\n      if (previousRoute is PageRoute) {\n        value.current = _extractRouteName(previousRoute) ?? '';\n        value.previous = newRoute.name ?? '';\n      } else if (value.previous.isNotEmpty) {\n        value.current = value.previous;\n      }\n\n      value.args = previousRoute?.settings.arguments;\n      value.route = previousRoute;\n      value.isBack = true;\n      value.removed = '';\n      value.isBottomSheet = newRoute.isBottomSheet;\n      value.isDialog = newRoute.isDialog;\n    });\n\n    routing?.call(_routeSend);\n  }\n\n  @override\n  void didPush(Route route, Route? previousRoute) {\n    super.didPush(route, previousRoute);\n    final newRoute = _RouteData.ofRoute(route);\n\n    if (newRoute.isBottomSheet || newRoute.isDialog) {\n      Get.log(\"OPEN ${newRoute.name}\");\n    } else if (newRoute.isGetPageRoute) {\n      Get.log(\"GOING TO ROUTE ${newRoute.name}\");\n    }\n\n    RouterReportManager.instance.reportCurrentRoute(route);\n    _routeSend?.update((value) {\n      if (route is PageRoute) {\n        value.current = newRoute.name ?? '';\n      }\n      final previousRouteName = _extractRouteName(previousRoute);\n      if (previousRouteName != null) {\n        value.previous = previousRouteName;\n      }\n\n      value.args = route.settings.arguments;\n      value.route = route;\n      value.isBack = false;\n      value.removed = '';\n      value.isBottomSheet =\n          newRoute.isBottomSheet ? true : value.isBottomSheet ?? false;\n      value.isDialog = newRoute.isDialog ? true : value.isDialog ?? false;\n    });\n\n    if (routing != null) {\n      routing!(_routeSend);\n    }\n  }\n\n  @override\n  void didRemove(Route route, Route? previousRoute) {\n    super.didRemove(route, previousRoute);\n    final routeName = _extractRouteName(route);\n    final currentRoute = _RouteData.ofRoute(route);\n    final previousRouteName = _extractRouteName(previousRoute);\n\n    Get.log(\"REMOVING ROUTE $routeName\");\n    Get.log(\"PREVIOUS ROUTE $previousRouteName\");\n\n    _routeSend?.update((value) {\n      value.route = previousRoute;\n      value.isBack = false;\n      value.removed = routeName ?? '';\n      value.previous = previousRouteName ?? '';\n      value.isBottomSheet =\n          currentRoute.isBottomSheet ? false : value.isBottomSheet;\n      value.isDialog = currentRoute.isDialog ? false : value.isDialog;\n    });\n\n    if (route is GetPageRoute) {\n      RouterReportManager.instance.reportRouteWillDispose(route);\n    }\n    routing?.call(_routeSend);\n  }\n\n  @override\n  void didReplace({Route? newRoute, Route? oldRoute}) {\n    super.didReplace(newRoute: newRoute, oldRoute: oldRoute);\n    final newName = _extractRouteName(newRoute);\n    final oldName = _extractRouteName(oldRoute);\n    final currentRoute = _RouteData.ofRoute(oldRoute);\n\n    Get.log(\"REPLACE ROUTE $oldName\");\n    Get.log(\"NEW ROUTE $newName\");\n\n    if (newRoute != null) {\n      RouterReportManager.instance.reportCurrentRoute(newRoute);\n    }\n\n    _routeSend?.update((value) {\n      // Only PageRoute is allowed to change current value\n      if (newRoute is PageRoute) {\n        value.current = newName ?? '';\n      }\n\n      value.args = newRoute?.settings.arguments;\n      value.route = newRoute;\n      value.isBack = false;\n      value.removed = '';\n      value.previous = oldName ?? '';\n      value.isBottomSheet =\n          currentRoute.isBottomSheet ? false : value.isBottomSheet;\n      value.isDialog = currentRoute.isDialog ? false : value.isDialog;\n    });\n    if (oldRoute is GetPageRoute) {\n      RouterReportManager.instance.reportRouteWillDispose(oldRoute);\n    }\n\n    routing?.call(_routeSend);\n  }\n}\n\n//TODO: Use copyWith, and remove mutate variables\nclass Routing {\n  String current;\n  String previous;\n  dynamic args;\n  String removed;\n  Route<dynamic>? route;\n  bool? isBack;\n  bool? isBottomSheet;\n  bool? isDialog;\n\n  Routing({\n    this.current = '',\n    this.previous = '',\n    this.args,\n    this.removed = '',\n    this.route,\n    this.isBack,\n    this.isBottomSheet,\n    this.isDialog,\n  });\n\n  void update(void Function(Routing value) fn) {\n    fn(this);\n  }\n}\n\n/// This is basically a util for rules about 'what a route is'\nclass _RouteData {\n  final bool isGetPageRoute;\n  final bool isBottomSheet;\n  final bool isDialog;\n  final String? name;\n\n  const _RouteData({\n    required this.name,\n    required this.isGetPageRoute,\n    required this.isBottomSheet,\n    required this.isDialog,\n  });\n\n  factory _RouteData.ofRoute(Route? route) {\n    return _RouteData(\n      name: _extractRouteName(route),\n      isGetPageRoute: route is GetPageRoute,\n      isDialog: route is GetDialogRoute,\n      isBottomSheet: route is GetModalBottomSheetRoute,\n    );\n  }\n}\n"
  },
  {
    "path": "lib/get_navigation/src/routes/page_settings.dart",
    "content": "import 'package:flutter/widgets.dart';\n\nimport '../../../route_manager.dart';\n\nextension PageArgExt on BuildContext {\n  RouteSettings? get settings {\n    return ModalRoute.of(this)!.settings;\n  }\n\n  PageSettings? get pageSettings {\n    final args = ModalRoute.of(this)?.settings.arguments;\n    if (args is PageSettings) {\n      return args;\n    }\n    return null;\n  }\n\n  dynamic get arguments {\n    final args = settings?.arguments;\n    if (args is PageSettings) {\n      return args.arguments;\n    } else {\n      return args;\n    }\n  }\n\n  Map<String, String> get params {\n    final args = settings?.arguments;\n    if (args is PageSettings) {\n      return args.params;\n    } else {\n      return {};\n    }\n  }\n\n  Router get router {\n    return Router.of(this);\n  }\n\n  String get location {\n    final parser = router.routeInformationParser;\n    final config = delegate.currentConfiguration;\n    return parser?.restoreRouteInformation(config)?.uri.toString() ?? '/';\n  }\n\n  GetDelegate get delegate {\n    return router.routerDelegate as GetDelegate;\n  }\n}\n\nclass PageSettings extends RouteSettings {\n  PageSettings(\n    this.uri, [\n    Object? arguments,\n  ]) : super(arguments: arguments);\n\n  @override\n  String get name => '$uri';\n\n  final Uri uri;\n\n  final params = <String, String>{};\n\n  String get path => uri.path;\n\n  List<String> get paths => uri.pathSegments;\n\n  Map<String, String> get query => uri.queryParameters;\n\n  Map<String, List<String>> get queries => uri.queryParametersAll;\n\n  @override\n  String toString() => name;\n\n  PageSettings copy({\n    Uri? uri,\n    Object? arguments,\n  }) {\n    return PageSettings(\n      uri ?? this.uri,\n      arguments ?? this.arguments,\n    );\n  }\n\n  @override\n  bool operator ==(Object other) {\n    if (identical(this, other)) return true;\n\n    return other is PageSettings &&\n        other.uri == uri &&\n        other.arguments == arguments;\n  }\n\n  @override\n  int get hashCode => uri.hashCode ^ arguments.hashCode;\n}\n"
  },
  {
    "path": "lib/get_navigation/src/routes/parse_route.dart",
    "content": "import 'package:flutter/foundation.dart';\n\nimport '../../../get.dart';\n\n@immutable\nclass RouteDecoder {\n  const RouteDecoder(\n    this.currentTreeBranch,\n    this.pageSettings,\n  );\n  final List<GetPage> currentTreeBranch;\n  final PageSettings? pageSettings;\n\n  factory RouteDecoder.fromRoute(String location) {\n    var uri = Uri.parse(location);\n    final args = PageSettings(uri);\n    final decoder =\n        (Get.rootController.rootDelegate).matchRoute(location, arguments: args);\n    decoder.route = decoder.route?.copyWith(\n      completer: null,\n      arguments: args,\n      parameters: args.params,\n    );\n    return decoder;\n  }\n\n  GetPage? get route =>\n      currentTreeBranch.isEmpty ? null : currentTreeBranch.last;\n\n  GetPage routeOrUnknown(GetPage onUnknow) =>\n      currentTreeBranch.isEmpty ? onUnknow : currentTreeBranch.last;\n\n  set route(GetPage? getPage) {\n    if (getPage == null) return;\n    if (currentTreeBranch.isEmpty) {\n      currentTreeBranch.add(getPage);\n    } else {\n      currentTreeBranch[currentTreeBranch.length - 1] = getPage;\n    }\n  }\n\n  List<GetPage>? get currentChildren => route?.children;\n\n  Map<String, String> get parameters => pageSettings?.params ?? {};\n\n  dynamic get args {\n    return pageSettings?.arguments;\n  }\n\n  T? arguments<T>() {\n    final args = pageSettings?.arguments;\n    if (args is T) {\n      return pageSettings?.arguments as T;\n    } else {\n      return null;\n    }\n  }\n\n  // void replaceArguments(Object? arguments) {\n  //   final newRoute = route;\n  //   if (newRoute != null) {\n  //     final index = currentTreeBranch.indexOf(newRoute);\n  //     currentTreeBranch[index] = newRoute.copyWith(arguments: arguments);\n  //   }\n  // }\n\n  @override\n  bool operator ==(Object other) {\n    if (identical(this, other)) return true;\n\n    return other is RouteDecoder &&\n        listEquals(other.currentTreeBranch, currentTreeBranch) &&\n        other.pageSettings == pageSettings;\n  }\n\n  @override\n  int get hashCode => currentTreeBranch.hashCode ^ pageSettings.hashCode;\n\n  @override\n  String toString() =>\n      'RouteDecoder(currentTreeBranch: $currentTreeBranch, pageSettings: $pageSettings)';\n}\n\nclass ParseRouteTree {\n  ParseRouteTree({\n    required this.routes,\n  });\n\n  final List<GetPage> routes;\n\n  RouteDecoder matchRoute(String name, {PageSettings? arguments}) {\n    final uri = Uri.parse(name);\n    final split = uri.path.split('/').where((element) => element.isNotEmpty);\n    var curPath = '/';\n    final cumulativePaths = <String>[\n      '/',\n    ];\n    for (var item in split) {\n      if (curPath.endsWith('/')) {\n        curPath += item;\n      } else {\n        curPath += '/$item';\n      }\n      cumulativePaths.add(curPath);\n    }\n\n    final treeBranch = cumulativePaths\n        .map((e) => MapEntry(e, _findRoute(e)))\n        .where((element) => element.value != null)\n\n        ///Prevent page be disposed\n        .map((e) => MapEntry(e.key, e.value!.copyWith(key: ValueKey(e.key))))\n        .toList();\n\n    final params = Map<String, String>.from(uri.queryParameters);\n    if (treeBranch.isNotEmpty) {\n      //route is found, do further parsing to get nested query params\n      final lastRoute = treeBranch.last;\n      final parsedParams = _parseParams(name, lastRoute.value.path);\n      if (parsedParams.isNotEmpty) {\n        params.addAll(parsedParams);\n      }\n      //copy parameters to all pages.\n      final mappedTreeBranch = treeBranch\n          .map(\n            (e) => e.value.copyWith(\n              parameters: {\n                if (e.value.parameters != null) ...e.value.parameters!,\n                ...params,\n              },\n              name: e.key,\n            ),\n          )\n          .toList();\n      arguments?.params.clear();\n      arguments?.params.addAll(params);\n      return RouteDecoder(\n        mappedTreeBranch,\n        arguments,\n      );\n    }\n\n    arguments?.params.clear();\n    arguments?.params.addAll(params);\n\n    //route not found\n    return RouteDecoder(\n      treeBranch.map((e) => e.value).toList(),\n      arguments,\n    );\n  }\n\n  void addRoutes<T>(List<GetPage<T>> getPages) {\n    for (final route in getPages) {\n      addRoute(route);\n    }\n  }\n\n  void removeRoutes<T>(List<GetPage<T>> getPages) {\n    for (final route in getPages) {\n      removeRoute(route);\n    }\n  }\n\n  void removeRoute<T>(GetPage<T> route) {\n    routes.remove(route);\n    for (var page in _flattenPage(route)) {\n      removeRoute(page);\n    }\n  }\n\n  void addRoute<T>(GetPage<T> route) {\n    routes.add(route);\n\n    // Add Page children.\n    for (var page in _flattenPage(route)) {\n      addRoute(page);\n    }\n  }\n\n  List<GetPage> _flattenPage(GetPage route) {\n    final result = <GetPage>[];\n    if (route.children.isEmpty) {\n      return result;\n    }\n\n    final parentPath = route.name;\n    for (var page in route.children) {\n      // Add Parent middlewares to children\n      final parentMiddlewares = [\n        if (page.middlewares.isNotEmpty) ...page.middlewares,\n        if (route.middlewares.isNotEmpty) ...route.middlewares\n      ];\n\n      final parentBindings = [\n        if (page.binding != null) page.binding!,\n        if (page.bindings.isNotEmpty) ...page.bindings,\n        if (route.bindings.isNotEmpty) ...route.bindings\n      ];\n\n      final parentBinds = [\n        if (page.binds.isNotEmpty) ...page.binds,\n        if (route.binds.isNotEmpty) ...route.binds\n      ];\n\n      result.add(\n        _addChild(\n          page,\n          parentPath,\n          parentMiddlewares,\n          parentBindings,\n          parentBinds,\n        ),\n      );\n\n      final children = _flattenPage(page);\n      for (var child in children) {\n        result.add(_addChild(\n          child,\n          parentPath,\n          [\n            ...parentMiddlewares,\n            if (child.middlewares.isNotEmpty) ...child.middlewares,\n          ],\n          [\n            ...parentBindings,\n            if (child.binding != null) child.binding!,\n            if (child.bindings.isNotEmpty) ...child.bindings,\n          ],\n          [\n            ...parentBinds,\n            if (child.binds.isNotEmpty) ...child.binds,\n          ],\n        ));\n      }\n    }\n    return result;\n  }\n\n  /// Change the Path for a [GetPage]\n  GetPage _addChild(\n    GetPage origin,\n    String parentPath,\n    List<GetMiddleware> middlewares,\n    List<BindingsInterface> bindings,\n    List<Bind> binds,\n  ) {\n    return origin.copyWith(\n      middlewares: middlewares,\n      name: origin.inheritParentPath\n          ? (parentPath + origin.name).replaceAll(r'//', '/')\n          : origin.name,\n      bindings: bindings,\n      binds: binds,\n      // key:\n    );\n  }\n\n  GetPage? _findRoute(String name) {\n    final value = routes.firstWhereOrNull(\n      (route) => route.path.regex.hasMatch(name),\n    );\n\n    return value;\n  }\n\n  Map<String, String> _parseParams(String path, PathDecoded routePath) {\n    final params = <String, String>{};\n    var idx = path.indexOf('?');\n    final uri = Uri.tryParse(path);\n    if (uri == null) return params;\n    if (idx > -1) {\n      params.addAll(uri.queryParameters);\n    }\n    var paramsMatch = routePath.regex.firstMatch(uri.path);\n    if (paramsMatch == null) {\n      return params;\n    }\n    for (var i = 0; i < routePath.keys.length; i++) {\n      var param = Uri.decodeQueryComponent(paramsMatch[i + 1]!);\n      params[routePath.keys[i]!] = param;\n    }\n    return params;\n  }\n}\n\nextension FirstWhereOrNullExt<T> on List<T> {\n  /// The first element satisfying [test], or `null` if there are none.\n  T? firstWhereOrNull(bool Function(T element) test) {\n    for (var element in this) {\n      if (test(element)) return element;\n    }\n    return null;\n  }\n}\n"
  },
  {
    "path": "lib/get_navigation/src/routes/route_middleware.dart",
    "content": "import 'dart:async';\n\nimport 'package:flutter/cupertino.dart';\n\nimport '../../../get.dart';\n\n/// The Page Middlewares.\n/// The Functions will be called in this order\n/// (( [redirect] -> [onPageCalled] -> [onBindingsStart] ->\n/// [onPageBuildStart] -> [onPageBuilt] -> [onPageDispose] ))\nabstract class GetMiddleware {\n  GetMiddleware({this.priority = 0});\n\n  /// The Order of the Middlewares to run.\n  ///\n  /// {@tool snippet}\n  /// This Middewares will be called in this order.\n  /// ```dart\n  /// final middlewares = [\n  ///   GetMiddleware(priority: 2),\n  ///   GetMiddleware(priority: 5),\n  ///   GetMiddleware(priority: 4),\n  ///   GetMiddleware(priority: -8),\n  /// ];\n  /// ```\n  ///  -8 => 2 => 4 => 5\n  /// {@end-tool}\n  final int priority;\n\n  /// This function will be called when the page of\n  /// the called route is being searched for.\n  /// It take RouteSettings as a result an redirect to the new settings or\n  /// give it null and there will be no redirecting.\n  /// {@tool snippet}\n  /// ```dart\n  /// GetPage redirect(String route) {\n  ///   final authService = Get.find<AuthService>();\n  ///   return authService.authed.value ? null : RouteSettings(name: '/login');\n  /// }\n  /// ```\n  /// {@end-tool}\n  RouteSettings? redirect(String? route) => null;\n\n  /// Similar to [redirect],\n  /// This function will be called when the router delegate changes the\n  /// current route.\n  ///\n  /// The default implmentation is to navigate to\n  /// the input route, with no redirection.\n  ///\n  /// if this returns null, the navigation is stopped,\n  /// and no new routes are pushed.\n  /// {@tool snippet}\n  /// ```dart\n  /// GetNavConfig? redirect(GetNavConfig route) {\n  ///   final authService = Get.find<AuthService>();\n  ///   return authService.authed.value ? null : RouteSettings(name: '/login');\n  /// }\n  /// ```\n  /// {@end-tool}\n  FutureOr<RouteDecoder?> redirectDelegate(RouteDecoder route) => (route);\n\n  /// This function will be called when this Page is called\n  /// you can use it to change something about the page or give it new page\n  /// {@tool snippet}\n  /// ```dart\n  /// GetPage onPageCalled(GetPage page) {\n  ///   final authService = Get.find<AuthService>();\n  ///   return page.copyWith(title: 'Welcome ${authService.UserName}');\n  /// }\n  /// ```\n  /// {@end-tool}\n  GetPage? onPageCalled(GetPage? page) => page;\n\n  /// This function will be called right before the [BindingsInterface] are initialize.\n  /// Here you can change [BindingsInterface] for this page\n  /// {@tool snippet}\n  /// ```dart\n  /// List<Bindings> onBindingsStart(List<Bindings> bindings) {\n  ///   final authService = Get.find<AuthService>();\n  ///   if (authService.isAdmin) {\n  ///     bindings.add(AdminBinding());\n  ///   }\n  ///   return bindings;\n  /// }\n  /// ```\n  /// {@end-tool}\n  List<R>? onBindingsStart<R>(List<R>? bindings) => bindings;\n\n  /// This function will be called right after the [BindingsInterface] are initialize.\n  GetPageBuilder? onPageBuildStart(GetPageBuilder? page) => page;\n\n  /// This function will be called right after the\n  /// GetPage.page function is called and will give you the result\n  /// of the function. and take the widget that will be showed.\n  Widget onPageBuilt(Widget page) => page;\n\n  void onPageDispose() {}\n}\n\nclass MiddlewareRunner {\n  MiddlewareRunner(List<GetMiddleware>? middlewares)\n      : _middlewares = middlewares != null\n            ? (List.of(middlewares)..sort(_compareMiddleware))\n            : const [];\n\n  final List<GetMiddleware> _middlewares;\n\n  static int _compareMiddleware(GetMiddleware a, GetMiddleware b) =>\n      a.priority.compareTo(b.priority);\n\n  GetPage? runOnPageCalled(GetPage? page) {\n    for (final middleware in _middlewares) {\n      page = middleware.onPageCalled(page);\n    }\n    return page;\n  }\n\n  RouteSettings? runRedirect(String? route) {\n    for (final middleware in _middlewares) {\n      final redirectTo = middleware.redirect(route);\n      if (redirectTo != null) {\n        return redirectTo;\n      }\n    }\n    return null;\n  }\n\n  List<R>? runOnBindingsStart<R>(List<R>? bindings) {\n    for (final middleware in _middlewares) {\n      bindings = middleware.onBindingsStart(bindings);\n    }\n    return bindings;\n  }\n\n  GetPageBuilder? runOnPageBuildStart(GetPageBuilder? page) {\n    for (final middleware in _middlewares) {\n      page = middleware.onPageBuildStart(page);\n    }\n    return page;\n  }\n\n  Widget runOnPageBuilt(Widget page) {\n    for (final middleware in _middlewares) {\n      page = middleware.onPageBuilt(page);\n    }\n    return page;\n  }\n\n  void runOnPageDispose() {\n    for (final middleware in _middlewares) {\n      middleware.onPageDispose();\n    }\n  }\n}\n\nclass PageRedirect {\n  GetPage? route;\n  GetPage? unknownRoute;\n  RouteSettings? settings;\n  bool isUnknown;\n\n  PageRedirect({\n    this.route,\n    this.unknownRoute,\n    this.isUnknown = false,\n    this.settings,\n  });\n\n  // redirect all pages that needes redirecting\n  GetPageRoute<T> getPageToRoute<T>(\n      GetPage rou, GetPage? unk, BuildContext context) {\n    while (needRecheck(context)) {}\n    final r = (isUnknown ? unk : rou)!;\n\n    return GetPageRoute<T>(\n      page: r.page,\n      parameter: r.parameters,\n      alignment: r.alignment,\n      title: r.title,\n      maintainState: r.maintainState,\n      routeName: r.name,\n      settings: r,\n      curve: r.curve,\n      showCupertinoParallax: r.showCupertinoParallax,\n      gestureWidth: r.gestureWidth,\n      opaque: r.opaque,\n      customTransition: r.customTransition,\n      bindings: r.bindings,\n      binding: r.binding,\n      binds: r.binds,\n      transitionDuration: r.transitionDuration ?? Get.defaultTransitionDuration,\n      reverseTransitionDuration:\n          r.reverseTransitionDuration ?? Get.defaultTransitionDuration,\n      // performIncomeAnimation: _r.performIncomeAnimation,\n      // performOutGoingAnimation: _r.performOutGoingAnimation,\n      transition: r.transition,\n      popGesture: r.popGesture,\n      fullscreenDialog: r.fullscreenDialog,\n      middlewares: r.middlewares,\n    );\n  }\n\n  /// check if redirect is needed\n  bool needRecheck(BuildContext context) {\n    if (settings == null && route != null) {\n      settings = route;\n    }\n    final match = context.delegate.matchRoute(settings!.name!);\n\n    // No Match found\n    if (match.route == null) {\n      isUnknown = true;\n      return false;\n    }\n\n    // No middlewares found return match.\n    if (match.route!.middlewares.isEmpty) {\n      return false;\n    }\n\n    final runner = MiddlewareRunner(match.route!.middlewares);\n    route = runner.runOnPageCalled(match.route);\n    addPageParameter(route!);\n\n    final newSettings = runner.runRedirect(settings!.name);\n    if (newSettings == null) {\n      return false;\n    }\n    settings = newSettings;\n    return true;\n  }\n\n  void addPageParameter(GetPage route) {\n    if (route.parameters == null) return;\n\n    final parameters = Map<String, String?>.from(Get.parameters);\n    parameters.addEntries(route.parameters!.entries);\n    // Get.parameters = parameters;\n  }\n}\n"
  },
  {
    "path": "lib/get_navigation/src/routes/route_report.dart",
    "content": "import 'package:flutter/material.dart';\n\nimport '../router_report.dart';\nimport 'default_route.dart';\n\nclass RouteReport extends StatefulWidget {\n  const RouteReport({super.key, required this.builder});\n  final WidgetBuilder builder;\n\n  @override\n  RouteReportState createState() => RouteReportState();\n}\n\nclass RouteReportState extends State<RouteReport> with RouteReportMixin {\n  @override\n  void initState() {\n    RouterReportManager.instance.reportCurrentRoute(this);\n    super.initState();\n  }\n\n  @override\n  void dispose() {\n    RouterReportManager.instance.reportRouteDispose(this);\n    super.dispose();\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return widget.builder(context);\n  }\n}\n"
  },
  {
    "path": "lib/get_navigation/src/routes/router_outlet.dart",
    "content": "import 'package:flutter/material.dart';\n\nimport '../../../get.dart';\n\nclass RouterOutlet<TDelegate extends RouterDelegate<T>, T extends Object>\n    extends StatefulWidget {\n  final TDelegate routerDelegate;\n  final Widget Function(BuildContext context) builder;\n\n  RouterOutlet.builder({\n    super.key,\n    TDelegate? delegate,\n    required this.builder,\n  }) : routerDelegate = delegate ?? Get.delegate<TDelegate, T>()!;\n\n  RouterOutlet({\n    Key? key,\n    TDelegate? delegate,\n    required Iterable<GetPage> Function(T currentNavStack) pickPages,\n    required Widget Function(\n      BuildContext context,\n      TDelegate,\n      Iterable<GetPage>? page,\n    ) pageBuilder,\n  }) : this.builder(\n            builder: (context) {\n              final currentConfig = context.delegate.currentConfiguration as T?;\n              final rDelegate = context.delegate as TDelegate;\n              var picked =\n                  currentConfig == null ? null : pickPages(currentConfig);\n              if (picked?.isEmpty ?? true) {\n                picked = null;\n              }\n              return pageBuilder(context, rDelegate, picked);\n            },\n            delegate: delegate,\n            key: key);\n  @override\n  RouterOutletState<TDelegate, T> createState() =>\n      RouterOutletState<TDelegate, T>();\n}\n\nclass RouterOutletState<TDelegate extends RouterDelegate<T>, T extends Object>\n    extends State<RouterOutlet<TDelegate, T>> {\n  RouterDelegate? delegate;\n  late ChildBackButtonDispatcher _backButtonDispatcher;\n\n  void _listener() {\n    setState(() {});\n  }\n\n  VoidCallback? disposer;\n\n  @override\n  void didChangeDependencies() {\n    super.didChangeDependencies();\n    disposer?.call();\n    final router = Router.of(context);\n    delegate ??= router.routerDelegate;\n    delegate?.addListener(_listener);\n    disposer = () => delegate?.removeListener(_listener);\n\n    _backButtonDispatcher =\n        router.backButtonDispatcher!.createChildBackButtonDispatcher();\n  }\n\n  @override\n  void dispose() {\n    super.dispose();\n    disposer?.call();\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    _backButtonDispatcher.takePriority();\n    return widget.builder(context);\n  }\n}\n\nclass GetRouterOutlet extends RouterOutlet<GetDelegate, RouteDecoder> {\n  GetRouterOutlet({\n    Key? key,\n    String? anchorRoute,\n    required String initialRoute,\n    Iterable<GetPage> Function(Iterable<GetPage> afterAnchor)? filterPages,\n    GetDelegate? delegate,\n    String? restorationScopeId,\n  }) : this.pickPages(\n          restorationScopeId: restorationScopeId,\n          pickPages: (config) {\n            Iterable<GetPage<dynamic>> ret;\n            if (anchorRoute == null) {\n              // jump the ancestor path\n              final length = Uri.parse(initialRoute).pathSegments.length;\n\n              return config.currentTreeBranch\n                  .skip(length)\n                  .take(length)\n                  .toList();\n            }\n            ret = config.currentTreeBranch.pickAfterRoute(anchorRoute);\n            if (filterPages != null) {\n              ret = filterPages(ret);\n            }\n            return ret;\n          },\n          key: key,\n          emptyPage: (delegate) =>\n              delegate.matchRoute(initialRoute).route ?? delegate.notFoundRoute,\n          navigatorKey: Get.nestedKey(anchorRoute)?.navigatorKey,\n          delegate: delegate,\n        );\n  GetRouterOutlet.pickPages({\n    super.key,\n    Widget Function(GetDelegate delegate)? emptyWidget,\n    GetPage Function(GetDelegate delegate)? emptyPage,\n    required super.pickPages,\n    bool Function(Route<dynamic>, dynamic)? onPopPage,\n    String? restorationScopeId,\n    GlobalKey<NavigatorState>? navigatorKey,\n    GetDelegate? delegate,\n  }) : super(\n          pageBuilder: (context, rDelegate, pages) {\n            final pageRes = <GetPage?>[\n              ...?pages,\n              if (pages == null || pages.isEmpty) emptyPage?.call(rDelegate),\n            ].whereType<GetPage>();\n\n            if (pageRes.isNotEmpty) {\n              return InheritedNavigator(\n                navigatorKey: navigatorKey ??\n                    Get.rootController.rootDelegate.navigatorKey,\n                child: GetNavigator(\n                  restorationScopeId: restorationScopeId,\n                  onPopPage: onPopPage ??\n                      (route, result) {\n                        final didPop = route.didPop(result);\n                        if (!didPop) {\n                          return false;\n                        }\n                        return true;\n                      },\n                  pages: pageRes.toList(),\n                  key: navigatorKey,\n                ),\n              );\n            }\n            return (emptyWidget?.call(rDelegate) ?? const SizedBox.shrink());\n          },\n          delegate: delegate ?? Get.rootController.rootDelegate,\n        );\n\n  GetRouterOutlet.builder({\n    super.key,\n    required super.builder,\n    String? route,\n    GetDelegate? routerDelegate,\n  }) : super.builder(\n          delegate: routerDelegate ??\n              (route != null\n                  ? Get.nestedKey(route)\n                  : Get.rootController.rootDelegate),\n        );\n}\n\nclass InheritedNavigator extends InheritedWidget {\n  const InheritedNavigator({\n    super.key,\n    required super.child,\n    required this.navigatorKey,\n  });\n  final GlobalKey<NavigatorState> navigatorKey;\n\n  static InheritedNavigator? of(BuildContext context) {\n    return context.dependOnInheritedWidgetOfExactType<InheritedNavigator>();\n  }\n\n  @override\n  bool updateShouldNotify(InheritedNavigator oldWidget) {\n    return true;\n  }\n}\n\nextension NavKeyExt on BuildContext {\n  GlobalKey<NavigatorState>? get parentNavigatorKey {\n    return InheritedNavigator.of(this)?.navigatorKey;\n  }\n}\n\nextension PagesListExt on List<GetPage> {\n  /// Returns the route and all following routes after the given route.\n  Iterable<GetPage> pickFromRoute(String route) {\n    return skipWhile((value) => value.name != route);\n  }\n\n  /// Returns the routes after the given route.\n  Iterable<GetPage> pickAfterRoute(String route) {\n    // If the provided route is root, we take the first route after root.\n    if (route == '/') {\n      return pickFromRoute(route).skip(1).take(1);\n    }\n    // Otherwise, we skip the route and take all routes after it.\n    return pickFromRoute(route).skip(1);\n  }\n}\n\ntypedef NavigatorItemBuilderBuilder = Widget Function(\n    BuildContext context, List<String> routes, int index);\n\nclass IndexedRouteBuilder<T> extends StatelessWidget {\n  const IndexedRouteBuilder({\n    super.key,\n    required this.builder,\n    required this.routes,\n  });\n  final List<String> routes;\n  final NavigatorItemBuilderBuilder builder;\n\n// Method to get the current index based on the route\n  int _getCurrentIndex(String currentLocation) {\n    for (int i = 0; i < routes.length; i++) {\n      if (currentLocation.startsWith(routes[i])) {\n        return i;\n      }\n    }\n    return 0; // default index\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    final location = context.location;\n    final index = _getCurrentIndex(location);\n\n    return builder(context, routes, index);\n  }\n}\n\nmixin RouterListenerMixin<T extends StatefulWidget> on State<T> {\n  RouterDelegate? delegate;\n\n  void _listener() {\n    setState(() {});\n  }\n\n  VoidCallback? disposer;\n\n  @override\n  void didChangeDependencies() {\n    super.didChangeDependencies();\n    disposer?.call();\n    final router = Router.of(context);\n    delegate ??= router.routerDelegate as GetDelegate;\n\n    delegate?.addListener(_listener);\n    disposer = () => delegate?.removeListener(_listener);\n  }\n\n  @override\n  void dispose() {\n    super.dispose();\n    disposer?.call();\n  }\n}\n\nclass RouterListenerInherited extends InheritedWidget {\n  const RouterListenerInherited({\n    super.key,\n    required super.child,\n  });\n\n  static RouterListenerInherited? of(BuildContext context) {\n    return context\n        .dependOnInheritedWidgetOfExactType<RouterListenerInherited>();\n  }\n\n  @override\n  bool updateShouldNotify(covariant InheritedWidget oldWidget) {\n    return true;\n  }\n}\n\nclass RouterListener extends StatefulWidget {\n  const RouterListener({\n    super.key,\n    required this.builder,\n  });\n  final WidgetBuilder builder;\n\n  @override\n  State<RouterListener> createState() => RouteListenerState();\n}\n\nclass RouteListenerState extends State<RouterListener>\n    with RouterListenerMixin {\n  @override\n  Widget build(BuildContext context) {\n    return RouterListenerInherited(child: Builder(builder: widget.builder));\n  }\n}\n\nclass BackButtonCallback extends StatefulWidget {\n  const BackButtonCallback({super.key, required this.builder});\n  final WidgetBuilder builder;\n\n  @override\n  State<BackButtonCallback> createState() => RouterListenerState();\n}\n\nclass RouterListenerState extends State<BackButtonCallback>\n    with RouterListenerMixin {\n  late ChildBackButtonDispatcher backButtonDispatcher;\n\n  @override\n  void didChangeDependencies() {\n    super.didChangeDependencies();\n    final router = Router.of(context);\n    backButtonDispatcher =\n        router.backButtonDispatcher!.createChildBackButtonDispatcher();\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    backButtonDispatcher.takePriority();\n    return widget.builder(context);\n  }\n}\n"
  },
  {
    "path": "lib/get_navigation/src/routes/test_kit.dart",
    "content": "class GetTestMode {\n  static bool active = false;\n  static Object? _arguments;\n\n  static void setTestArguments(Object? arguments) {\n    _arguments = arguments;\n  }\n\n  static Object? get arguments => _arguments;\n\n  static Map<String, String?> _parameters = {};\n\n  static void setTestParameters(Map<String, String?> parameters) {\n    _parameters = parameters;\n  }\n\n  static Map<String, String?> get parameters => _parameters;\n}\n"
  },
  {
    "path": "lib/get_navigation/src/routes/transitions_type.dart",
    "content": "import 'package:flutter/widgets.dart';\n\nimport 'default_route.dart';\n\nenum Transition {\n  fade,\n  fadeIn,\n  rightToLeft,\n  leftToRight,\n  upToDown,\n  downToUp,\n  rightToLeftWithFade,\n  leftToRightWithFade,\n  zoom,\n  topLevel,\n  noTransition,\n  cupertino,\n  cupertinoDialog,\n  size,\n  circularReveal,\n  native,\n}\n\ntypedef GetPageBuilder = Widget Function();\ntypedef GetRouteAwarePageBuilder<T> = Widget Function([GetPageRoute<T>? route]);\n"
  },
  {
    "path": "lib/get_navigation/src/routes/url_strategy/impl/io_url.dart",
    "content": "void removeHash() {}\n"
  },
  {
    "path": "lib/get_navigation/src/routes/url_strategy/impl/stub_url.dart",
    "content": "void removeHash() {\n  throw UnimplementedError();\n}\n"
  },
  {
    "path": "lib/get_navigation/src/routes/url_strategy/impl/web_url.dart",
    "content": "import 'package:flutter_web_plugins/flutter_web_plugins.dart';\n\nvoid removeHash() {\n  setUrlStrategy(PathUrlStrategy());\n}\n"
  },
  {
    "path": "lib/get_navigation/src/routes/url_strategy/url_strategy.dart",
    "content": "import 'impl/stub_url.dart'\n    if (dart.library.js_interop) 'impl/web_url.dart'\n    if (dart.library.io) 'impl/io_url.dart';\n\nvoid setUrlStrategy() {\n  removeHash();\n}\n\nvoid removeLastHistory(String? url) {\n  removeLastHistory(url);\n}\n"
  },
  {
    "path": "lib/get_navigation/src/snackbar/snackbar.dart",
    "content": "import 'dart:async';\nimport 'dart:ui';\n\nimport 'package:flutter/material.dart';\n\nimport '../../../get_core/get_core.dart';\nimport '../../get_navigation.dart';\n\ntypedef OnTap = void Function(GetSnackBar snack);\ntypedef OnHover = void Function(\n    GetSnackBar snack, SnackHoverState snackHoverState);\n\ntypedef SnackbarStatusCallback = void Function(SnackbarStatus? status);\n\nclass GetSnackBar extends StatefulWidget {\n  /// A callback for you to listen to the different Snack status\n  final SnackbarStatusCallback? snackbarStatus;\n\n  /// The title displayed to the user\n  final String? title;\n\n  /// Defines how the snack bar area, including margin, will behave during hit testing.\n  ///\n  /// If this property is null and [margin] is not null, then [HitTestBehavior.deferToChild] is used by default.\n  ///\n  /// Please refer to [HitTestBehavior] for a detailed explanation of every behavior.\n  final HitTestBehavior? hitTestBehavior;\n\n  /// The direction in which the SnackBar can be dismissed.\n  ///\n  /// Default is [DismissDirection.down] when\n  /// [snackPosition] == [SnackPosition.BOTTOM] and [DismissDirection.up]\n  /// when [snackPosition] == [SnackPosition.TOP]\n  final DismissDirection? dismissDirection;\n\n  /// The message displayed to the user.\n  final String? message;\n\n  /// Replaces [title]. Although this accepts a [Widget], it is meant\n  /// to receive [Text] or [RichText]\n  final Widget? titleText;\n\n  /// Replaces [message]. Although this accepts a [Widget], it is meant\n  /// to receive [Text] or  [RichText]\n  final Widget? messageText;\n\n  /// Will be ignored if [backgroundGradient] is not null\n  final Color backgroundColor;\n\n  /// If not null, shows a left vertical colored bar on notification.\n  /// It is not possible to use it with a [Form] and I do not recommend\n  /// using it with [LinearProgressIndicator]\n  final Color? leftBarIndicatorColor;\n\n  /// [boxShadows] The shadows generated by Snack. Leave it null\n  /// if you don't want a shadow.\n  /// You can use more than one if you feel the need.\n  /// Check (this example)[https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/material/shadows.dart]\n  final List<BoxShadow>? boxShadows;\n\n  /// Give to GetSnackbar a gradient background.\n  /// It Makes [backgroundColor] be ignored.\n  final Gradient? backgroundGradient;\n\n  /// You can use any widget here, but I recommend [Icon] or [Image] as\n  /// indication of what kind\n  /// of message you are displaying. Other widgets may break the layout\n  final Widget? icon;\n\n  /// An option to animate the icon (if present). Defaults to true.\n  final bool shouldIconPulse;\n\n  /// (optional) An action that the user can take based on the snack bar.\n  ///\n  /// For example, the snack bar might let the user undo the operation that\n  /// prompted the snackbar.\n  final Widget? mainButton;\n\n  /// A callback that registers the user's click anywhere.\n  /// An alternative to [mainButton]\n  final OnTap? onTap;\n\n  /// A callback that registers the user's hover anywhere over the Snackbar.\n  final OnHover? onHover;\n\n  /// How long until Snack will hide itself (be dismissed).\n  /// To make it indefinite, leave it null.\n  final Duration? duration;\n\n  /// True if you want to show a [LinearProgressIndicator].\n  final bool showProgressIndicator;\n\n  /// An optional [AnimationController] when you want to control the\n  /// progress of your [LinearProgressIndicator].\n  final AnimationController? progressIndicatorController;\n\n  /// A [LinearProgressIndicator] configuration parameter.\n  final Color? progressIndicatorBackgroundColor;\n\n  /// A [LinearProgressIndicator] configuration parameter.\n  final Animation<Color>? progressIndicatorValueColor;\n\n  /// Determines if the user can swipe or click the overlay\n  /// (if [overlayBlur] > 0) to dismiss.\n  /// It is recommended that you set [duration] != null if this is false.\n  /// If the user swipes to dismiss or clicks the overlay, no value\n  /// will be returned.\n  final bool isDismissible;\n\n  /// Used to limit Snack width (usually on large screens)\n  final double? maxWidth;\n\n  /// Adds a custom margin to Snack\n  final EdgeInsets margin;\n\n  /// Adds a custom padding to Snack\n  /// The default follows material design guide line\n  final EdgeInsets padding;\n\n  /// Adds a radius to all corners of Snack. Best combined with [margin].\n  /// I do not recommend using it with [showProgressIndicator]\n  /// or [leftBarIndicatorColor].\n  final double borderRadius;\n\n  /// Adds a border to every side of Snack\n  /// I do not recommend using it with [showProgressIndicator]\n  /// or [leftBarIndicatorColor].\n  final Color? borderColor;\n\n  /// Changes the width of the border if [borderColor] is specified\n  final double? borderWidth;\n\n  /// Snack can be based on [SnackPosition.TOP] or on [SnackPosition.BOTTOM]\n  /// of your screen.\n  /// [SnackPosition.BOTTOM] is the default.\n  final SnackPosition snackPosition;\n\n  /// Snack can be floating or be grounded to the edge of the screen.\n  /// If grounded, I do not recommend using [margin] or [borderRadius].\n  /// [SnackStyle.FLOATING] is the default\n  /// If grounded, I do not recommend using a [backgroundColor] with\n  /// transparency or [barBlur]\n  final SnackStyle snackStyle;\n\n  /// The [Curve] animation used when show() is called.\n  /// [Curves.easeOut] is default\n  final Curve forwardAnimationCurve;\n\n  /// The [Curve] animation used when dismiss() is called.\n  /// [Curves.fastOutSlowIn] is default\n  final Curve reverseAnimationCurve;\n\n  /// Use it to speed up or slow down the animation duration\n  final Duration animationDuration;\n\n  /// Default is 0.0. If different than 0.0, blurs only Snack's background.\n  /// To take effect, make sure your [backgroundColor] has some opacity.\n  /// The greater the value, the greater the blur.\n  final double barBlur;\n\n  /// Default is 0.0. If different than 0.0, creates a blurred\n  /// overlay that prevents the user from interacting with the screen.\n  /// The greater the value, the greater the blur.\n  final double overlayBlur;\n\n  /// Default is [Colors.transparent]. Only takes effect if [overlayBlur] > 0.0.\n  /// Make sure you use a color with transparency here e.g.\n  /// Colors.grey[600].withValues(alpha:0.2).\n  final Color? overlayColor;\n\n  /// A [TextFormField] in case you want a simple user input.\n  /// Every other widget is ignored if this is not null.\n  final Form? userInputForm;\n\n  const GetSnackBar({\n    super.key,\n    this.title,\n    this.message,\n    this.titleText,\n    this.messageText,\n    this.icon,\n    this.shouldIconPulse = true,\n    this.maxWidth,\n    this.margin = const EdgeInsets.all(0.0),\n    this.padding = const EdgeInsets.all(16),\n    this.borderRadius = 0.0,\n    this.borderColor,\n    this.borderWidth = 1.0,\n    this.backgroundColor = const Color(0xFF303030),\n    this.leftBarIndicatorColor,\n    this.boxShadows,\n    this.backgroundGradient,\n    this.mainButton,\n    this.onTap,\n    this.onHover,\n    this.duration,\n    this.isDismissible = true,\n    this.dismissDirection,\n    this.showProgressIndicator = false,\n    this.progressIndicatorController,\n    this.progressIndicatorBackgroundColor,\n    this.progressIndicatorValueColor,\n    this.snackPosition = SnackPosition.bottom,\n    this.snackStyle = SnackStyle.floating,\n    this.forwardAnimationCurve = Curves.easeOutCirc,\n    this.reverseAnimationCurve = Curves.easeOutCirc,\n    this.animationDuration = const Duration(seconds: 1),\n    this.barBlur = 0.0,\n    this.overlayBlur = 0.0,\n    this.overlayColor = Colors.transparent,\n    this.userInputForm,\n    this.snackbarStatus,\n    this.hitTestBehavior,\n  });\n\n  @override\n  State createState() => GetSnackBarState();\n\n  /// Show the snack. It's call [SnackbarStatus.OPENING] state\n  /// followed by [SnackbarStatus.OPEN]\n  SnackbarController show() {\n    return Get.showSnackbar(this);\n  }\n}\n\nclass GetSnackBarState extends State<GetSnackBar>\n    with TickerProviderStateMixin {\n  AnimationController? _fadeController;\n  late Animation<double> _fadeAnimation;\n\n  final Widget _emptyWidget = const SizedBox(width: 0.0, height: 0.0);\n  final double _initialOpacity = 1.0;\n  final double _finalOpacity = 0.4;\n\n  final Duration _pulseAnimationDuration = const Duration(seconds: 1);\n\n  late bool _isTitlePresent;\n  late double _messageTopMargin;\n\n  FocusScopeNode? _focusNode;\n  late FocusAttachment _focusAttachment;\n\n  final Completer<Size> _boxHeightCompleter = Completer<Size>();\n\n  late CurvedAnimation _progressAnimation;\n\n  final _backgroundBoxKey = GlobalKey();\n\n  double get buttonPadding {\n    if (widget.padding.right - 12 < 0) {\n      return 4;\n    } else {\n      return widget.padding.right - 12;\n    }\n  }\n\n  RowStyle get _rowStyle {\n    if (widget.mainButton != null && widget.icon == null) {\n      return RowStyle.action;\n    } else if (widget.mainButton == null && widget.icon != null) {\n      return RowStyle.icon;\n    } else if (widget.mainButton != null && widget.icon != null) {\n      return RowStyle.all;\n    } else {\n      return RowStyle.none;\n    }\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return Align(\n      heightFactor: 1.0,\n      child: Material(\n        color: widget.snackStyle == SnackStyle.floating\n            ? Colors.transparent\n            : widget.backgroundColor,\n        child: SafeArea(\n          minimum: widget.snackPosition == SnackPosition.bottom\n              ? EdgeInsets.only(\n                  bottom: MediaQuery.of(context).viewInsets.bottom)\n              : EdgeInsets.only(top: MediaQuery.of(context).padding.top),\n          bottom: widget.snackPosition == SnackPosition.bottom,\n          top: widget.snackPosition == SnackPosition.top,\n          left: false,\n          right: false,\n          child: Stack(\n            children: [\n              FutureBuilder<Size>(\n                future: _boxHeightCompleter.future,\n                builder: (context, snapshot) {\n                  if (snapshot.hasData) {\n                    if (widget.barBlur == 0) {\n                      return _emptyWidget;\n                    }\n                    return ClipRRect(\n                      borderRadius: BorderRadius.circular(widget.borderRadius),\n                      child: BackdropFilter(\n                        filter: ImageFilter.blur(\n                            sigmaX: widget.barBlur, sigmaY: widget.barBlur),\n                        child: Container(\n                          height: snapshot.data!.height,\n                          width: snapshot.data!.width,\n                          decoration: BoxDecoration(\n                            color: Colors.transparent,\n                            borderRadius:\n                                BorderRadius.circular(widget.borderRadius),\n                          ),\n                        ),\n                      ),\n                    );\n                  } else {\n                    return _emptyWidget;\n                  }\n                },\n              ),\n              if (widget.userInputForm != null)\n                _containerWithForm()\n              else\n                _containerWithoutForm()\n            ],\n          ),\n        ),\n      ),\n    );\n  }\n\n  @override\n  void dispose() {\n    _fadeController?.dispose();\n    widget.progressIndicatorController?.removeListener(_updateProgress);\n    widget.progressIndicatorController?.dispose();\n\n    _focusAttachment.detach();\n    _focusNode!.dispose();\n    super.dispose();\n  }\n\n  @override\n  void initState() {\n    super.initState();\n\n    assert(\n        widget.userInputForm != null ||\n            ((widget.message != null && widget.message!.isNotEmpty) ||\n                widget.messageText != null),\n        '''\nYou need to either use message[String], or messageText[Widget] or define a userInputForm[Form] in GetSnackbar''');\n\n    _isTitlePresent = (widget.title != null || widget.titleText != null);\n    _messageTopMargin = _isTitlePresent ? 6.0 : widget.padding.top;\n\n    _configureLeftBarFuture();\n    _configureProgressIndicatorAnimation();\n\n    if (widget.icon != null && widget.shouldIconPulse) {\n      _configurePulseAnimation();\n      _fadeController?.forward();\n    }\n\n    _focusNode = FocusScopeNode();\n    _focusAttachment = _focusNode!.attach(context);\n  }\n\n  Widget _buildLeftBarIndicator() {\n    if (widget.leftBarIndicatorColor != null) {\n      return FutureBuilder<Size>(\n        future: _boxHeightCompleter.future,\n        builder: (buildContext, snapshot) {\n          if (snapshot.hasData) {\n            return Container(\n              color: widget.leftBarIndicatorColor,\n              width: 5.0,\n              height: snapshot.data!.height,\n            );\n          } else {\n            return _emptyWidget;\n          }\n        },\n      );\n    } else {\n      return _emptyWidget;\n    }\n  }\n\n  void _configureLeftBarFuture() {\n    Engine.instance.addPostFrameCallback(\n      (_) {\n        final keyContext = _backgroundBoxKey.currentContext;\n        if (keyContext != null) {\n          final box = keyContext.findRenderObject() as RenderBox;\n          _boxHeightCompleter.complete(box.size);\n        }\n      },\n    );\n  }\n\n  void _configureProgressIndicatorAnimation() {\n    if (widget.showProgressIndicator &&\n        widget.progressIndicatorController != null) {\n      widget.progressIndicatorController!.addListener(_updateProgress);\n\n      _progressAnimation = CurvedAnimation(\n          curve: Curves.linear, parent: widget.progressIndicatorController!);\n    }\n  }\n\n  void _configurePulseAnimation() {\n    _fadeController =\n        AnimationController(vsync: this, duration: _pulseAnimationDuration);\n    _fadeAnimation = Tween(begin: _initialOpacity, end: _finalOpacity).animate(\n      CurvedAnimation(\n        parent: _fadeController!,\n        curve: Curves.linear,\n      ),\n    );\n\n    _fadeController!.addStatusListener((status) {\n      if (status == AnimationStatus.completed) {\n        _fadeController!.reverse();\n      }\n      if (status == AnimationStatus.dismissed) {\n        _fadeController!.forward();\n      }\n    });\n\n    _fadeController!.forward();\n  }\n\n  Widget _containerWithForm() {\n    return Container(\n      key: _backgroundBoxKey,\n      constraints: widget.maxWidth != null\n          ? BoxConstraints(maxWidth: widget.maxWidth!)\n          : null,\n      decoration: BoxDecoration(\n        color: widget.backgroundColor,\n        gradient: widget.backgroundGradient,\n        boxShadow: widget.boxShadows,\n        borderRadius: BorderRadius.circular(widget.borderRadius),\n        border: widget.borderColor != null\n            ? Border.all(\n                color: widget.borderColor!,\n                width: widget.borderWidth!,\n              )\n            : null,\n      ),\n      child: Padding(\n        padding: const EdgeInsets.only(\n            left: 8.0, right: 8.0, bottom: 8.0, top: 16.0),\n        child: FocusScope(\n          node: _focusNode,\n          autofocus: true,\n          child: widget.userInputForm!,\n        ),\n      ),\n    );\n  }\n\n  Widget _containerWithoutForm() {\n    final iconPadding = widget.padding.left > 16.0 ? widget.padding.left : 0.0;\n    final left = _rowStyle == RowStyle.icon || _rowStyle == RowStyle.all\n        ? 4.0\n        : widget.padding.left;\n    final right = _rowStyle == RowStyle.action || _rowStyle == RowStyle.all\n        ? 8.0\n        : widget.padding.right;\n    return Container(\n      key: _backgroundBoxKey,\n      constraints: widget.maxWidth != null\n          ? BoxConstraints(maxWidth: widget.maxWidth!)\n          : null,\n      decoration: BoxDecoration(\n        color: widget.backgroundColor,\n        gradient: widget.backgroundGradient,\n        boxShadow: widget.boxShadows,\n        borderRadius: BorderRadius.circular(widget.borderRadius),\n        border: widget.borderColor != null\n            ? Border.all(color: widget.borderColor!, width: widget.borderWidth!)\n            : null,\n      ),\n      child: Column(\n        mainAxisSize: MainAxisSize.min,\n        children: [\n          widget.showProgressIndicator\n              ? LinearProgressIndicator(\n                  value: widget.progressIndicatorController != null\n                      ? _progressAnimation.value\n                      : null,\n                  backgroundColor: widget.progressIndicatorBackgroundColor,\n                  valueColor: widget.progressIndicatorValueColor,\n                )\n              : _emptyWidget,\n          Row(\n            mainAxisSize: MainAxisSize.max,\n            children: [\n              _buildLeftBarIndicator(),\n              if (_rowStyle == RowStyle.icon || _rowStyle == RowStyle.all)\n                ConstrainedBox(\n                  constraints:\n                      BoxConstraints.tightFor(width: 42.0 + iconPadding),\n                  child: _getIcon(),\n                ),\n              Expanded(\n                flex: 1,\n                child: Column(\n                  crossAxisAlignment: CrossAxisAlignment.stretch,\n                  mainAxisSize: MainAxisSize.min,\n                  children: <Widget>[\n                    if (_isTitlePresent)\n                      Padding(\n                        padding: EdgeInsets.only(\n                          top: widget.padding.top,\n                          left: left,\n                          right: right,\n                        ),\n                        child: widget.titleText ??\n                            Text(\n                              widget.title ?? \"\",\n                              style: const TextStyle(\n                                fontSize: 16.0,\n                                color: Colors.white,\n                                fontWeight: FontWeight.bold,\n                              ),\n                            ),\n                      )\n                    else\n                      _emptyWidget,\n                    Padding(\n                      padding: EdgeInsets.only(\n                        top: _messageTopMargin,\n                        left: left,\n                        right: right,\n                        bottom: widget.padding.bottom,\n                      ),\n                      child: widget.messageText ??\n                          Text(\n                            widget.message ?? \"\",\n                            style: const TextStyle(\n                                fontSize: 14.0, color: Colors.white),\n                          ),\n                    ),\n                  ],\n                ),\n              ),\n              if (_rowStyle == RowStyle.action || _rowStyle == RowStyle.all)\n                Padding(\n                  padding: EdgeInsets.only(right: buttonPadding),\n                  child: widget.mainButton,\n                ),\n            ],\n          ),\n        ],\n      ),\n    );\n  }\n\n  Widget? _getIcon() {\n    if (widget.icon != null && widget.icon is Icon && widget.shouldIconPulse) {\n      return FadeTransition(\n        opacity: _fadeAnimation,\n        child: widget.icon,\n      );\n    } else if (widget.icon != null) {\n      return widget.icon;\n    } else {\n      return _emptyWidget;\n    }\n  }\n\n  void _updateProgress() => setState(() {});\n}\n\nenum RowStyle {\n  icon,\n  action,\n  all,\n  none,\n}\n\n/// Indicates Status of snackbar\n/// [SnackbarStatus.OPEN] Snack is fully open, [SnackbarStatus.CLOSED] Snackbar\n/// has closed,\n/// [SnackbarStatus.OPENING] Starts with the opening animation and ends\n/// with the full\n/// snackbar display, [SnackbarStatus.CLOSING] Starts with the closing animation\n/// and ends\n/// with the full snackbar dispose\nenum SnackbarStatus { open, closed, opening, closing }\n\n/// Indicates if snack is going to start at the [TOP] or at the [BOTTOM]\nenum SnackPosition { top, bottom }\n\n/// Indicates if snack will be attached to the edge of the screen or not\nenum SnackStyle { floating, grounded }\n\n/// Indicates if the mouse entered or exited\nenum SnackHoverState { entered, exited }\n"
  },
  {
    "path": "lib/get_navigation/src/snackbar/snackbar_controller.dart",
    "content": "import 'dart:async';\nimport 'dart:math';\nimport 'dart:ui';\n\nimport 'package:flutter/material.dart';\n\nimport '../../../get.dart';\nimport '../root/get_root.dart';\n\nclass SnackbarController {\n  final key = GlobalKey<GetSnackBarState>();\n\n  static bool get isSnackbarBeingShown =>\n      GetRootState.controller.config.snackBarQueue.isJobInProgress;\n\n  late Animation<double> _filterBlurAnimation;\n  late Animation<Color?> _filterColorAnimation;\n\n  final GetSnackBar snackbar;\n  final _transitionCompleter = Completer();\n\n  late SnackbarStatusCallback? _snackbarStatus;\n  late final Alignment? _initialAlignment;\n  late final Alignment? _endAlignment;\n\n  bool _wasDismissedBySwipe = false;\n\n  bool _onTappedDismiss = false;\n\n  Timer? _timer;\n\n  /// The animation that drives the route's transition and the previous route's\n  /// forward transition.\n  late final Animation<Alignment> _animation;\n\n  /// The animation controller that the route uses to drive the transitions.\n  ///\n  /// The animation itself is exposed by the [animation] property.\n  late final AnimationController _controller;\n\n  SnackbarStatus? _currentStatus;\n\n  final _overlayEntries = <OverlayEntry>[];\n\n  OverlayState? _overlayState;\n\n  SnackbarController(this.snackbar);\n\n  Future<void> get future => _transitionCompleter.future;\n\n  /// Close the snackbar with animation\n  Future<void> close({bool withAnimations = true}) async {\n    if (!withAnimations) {\n      _removeOverlay();\n      return;\n    }\n    _removeEntry();\n    await future;\n  }\n\n  /// Adds GetSnackbar to a view queue.\n  /// Only one GetSnackbar will be displayed at a time, and this method returns\n  /// a future to when the snackbar disappears.\n  Future<void> show() {\n    return GetRootState.controller.config.snackBarQueue.addJob(this);\n  }\n\n  void _cancelTimer() {\n    if (_timer != null && _timer!.isActive) {\n      _timer!.cancel();\n    }\n  }\n\n  // ignore: avoid_returning_this\n  void _configureAlignment(SnackPosition snackPosition) {\n    switch (snackbar.snackPosition) {\n      case SnackPosition.top:\n        {\n          _initialAlignment = const Alignment(-1.0, -2.0);\n          _endAlignment = const Alignment(-1.0, -1.0);\n          break;\n        }\n      case SnackPosition.bottom:\n        {\n          _initialAlignment = const Alignment(-1.0, 2.0);\n          _endAlignment = const Alignment(-1.0, 1.0);\n          break;\n        }\n    }\n  }\n\n  bool _isTesting = false;\n\n  void _configureOverlay() {\n    _isTesting = Get.overlayContext == null;\n    _overlayState = _isTesting ? OverlayState() : Get.key.currentState?.overlay;\n    _overlayEntries.clear();\n    _overlayEntries.addAll(_createOverlayEntries(_getBodyWidget()));\n    if (!_isTesting) {\n      _overlayState!.insertAll(_overlayEntries);\n    }\n\n    _configureSnackBarDisplay();\n  }\n\n  void _configureSnackBarDisplay() {\n    assert(!_transitionCompleter.isCompleted,\n        'Cannot configure a snackbar after disposing it.');\n    _controller = _createAnimationController();\n    _configureAlignment(snackbar.snackPosition);\n    _snackbarStatus = snackbar.snackbarStatus;\n    _filterBlurAnimation = _createBlurFilterAnimation();\n    _filterColorAnimation = _createColorOverlayColor();\n    _animation = _createAnimation();\n    _animation.addStatusListener(_handleStatusChanged);\n    _configureTimer();\n    _controller.forward();\n  }\n\n  void _configureTimer() {\n    if (snackbar.duration != null) {\n      if (_timer != null && _timer!.isActive) {\n        _timer!.cancel();\n      }\n      _timer = Timer(snackbar.duration!, _removeEntry);\n    } else {\n      if (_timer != null) {\n        _timer!.cancel();\n      }\n    }\n  }\n\n  /// Called to create the animation that exposes the current progress of\n  /// the transition controlled by the animation controller created by\n  /// `createAnimationController()`.\n  Animation<Alignment> _createAnimation() {\n    assert(!_transitionCompleter.isCompleted,\n        'Cannot create a animation from a disposed snackbar');\n    return AlignmentTween(begin: _initialAlignment, end: _endAlignment).animate(\n      CurvedAnimation(\n        parent: _controller,\n        curve: snackbar.forwardAnimationCurve,\n        reverseCurve: snackbar.reverseAnimationCurve,\n      ),\n    );\n  }\n\n  /// Called to create the animation controller that will drive the transitions\n  /// to this route from the previous one, and back to the previous route\n  /// from this one.\n  AnimationController _createAnimationController() {\n    assert(!_transitionCompleter.isCompleted,\n        'Cannot create a animationController from a disposed snackbar');\n    assert(snackbar.animationDuration >= Duration.zero);\n    return AnimationController(\n      duration: snackbar.animationDuration,\n      debugLabel: '$runtimeType',\n      vsync: _overlayState!,\n    );\n  }\n\n  Animation<double> _createBlurFilterAnimation() {\n    return Tween(begin: 0.0, end: snackbar.overlayBlur).animate(\n      CurvedAnimation(\n        parent: _controller,\n        curve: const Interval(\n          0.0,\n          0.35,\n          curve: Curves.easeInOutCirc,\n        ),\n      ),\n    );\n  }\n\n  Animation<Color?> _createColorOverlayColor() {\n    return ColorTween(\n            begin: const Color(0x00000000), end: snackbar.overlayColor)\n        .animate(\n      CurvedAnimation(\n        parent: _controller,\n        curve: const Interval(\n          0.0,\n          0.35,\n          curve: Curves.easeInOutCirc,\n        ),\n      ),\n    );\n  }\n\n  Iterable<OverlayEntry> _createOverlayEntries(Widget child) {\n    return <OverlayEntry>[\n      if (snackbar.overlayBlur > 0.0) ...[\n        OverlayEntry(\n          builder: (context) => GestureDetector(\n            onTap: () {\n              if (snackbar.isDismissible && !_onTappedDismiss) {\n                _onTappedDismiss = true;\n                close();\n              }\n            },\n            child: AnimatedBuilder(\n              animation: _filterBlurAnimation,\n              builder: (context, child) {\n                return BackdropFilter(\n                  filter: ImageFilter.blur(\n                    sigmaX: max(0.001, _filterBlurAnimation.value),\n                    sigmaY: max(0.001, _filterBlurAnimation.value),\n                  ),\n                  child: Container(\n                    constraints: const BoxConstraints.expand(),\n                    color: _filterColorAnimation.value,\n                  ),\n                );\n              },\n            ),\n          ),\n          maintainState: false,\n          opaque: false,\n        ),\n      ],\n      OverlayEntry(\n        builder: (context) => Semantics(\n          focused: false,\n          container: true,\n          explicitChildNodes: true,\n          child: AlignTransition(\n            alignment: _animation,\n            child: snackbar.isDismissible\n                ? _getDismissibleSnack(child)\n                : _getSnackbarContainer(child),\n          ),\n        ),\n        maintainState: false,\n        opaque: false,\n      ),\n    ];\n  }\n\n  Widget _getBodyWidget() {\n    return Builder(builder: (_) {\n      return MouseRegion(\n        onEnter: (_) =>\n            snackbar.onHover?.call(snackbar, SnackHoverState.entered),\n        onExit: (_) => snackbar.onHover?.call(snackbar, SnackHoverState.exited),\n        child: GestureDetector(\n          behavior: snackbar.hitTestBehavior ?? HitTestBehavior.deferToChild,\n          onTap: snackbar.onTap != null\n              ? () => snackbar.onTap?.call(snackbar)\n              : null,\n          child: snackbar,\n        ),\n      );\n    });\n  }\n\n  DismissDirection _getDefaultDismissDirection() {\n    if (snackbar.snackPosition == SnackPosition.top) {\n      return DismissDirection.up;\n    }\n    return DismissDirection.down;\n  }\n\n  Widget _getDismissibleSnack(Widget child) {\n    return Dismissible(\n      behavior: snackbar.hitTestBehavior ?? HitTestBehavior.opaque,\n      direction: snackbar.dismissDirection ?? _getDefaultDismissDirection(),\n      resizeDuration: null,\n      confirmDismiss: (_) {\n        if (_currentStatus == SnackbarStatus.opening ||\n            _currentStatus == SnackbarStatus.closing) {\n          return Future.value(false);\n        }\n        return Future.value(true);\n      },\n      key: const Key('dismissible'),\n      onDismissed: (_) {\n        _wasDismissedBySwipe = true;\n        _removeEntry();\n      },\n      child: _getSnackbarContainer(child),\n    );\n  }\n\n  Widget _getSnackbarContainer(Widget child) {\n    return Container(\n      margin: snackbar.margin,\n      child: child,\n    );\n  }\n\n  void _handleStatusChanged(AnimationStatus status) {\n    switch (status) {\n      case AnimationStatus.completed:\n        _currentStatus = SnackbarStatus.open;\n        _snackbarStatus?.call(_currentStatus);\n        if (_overlayEntries.isNotEmpty) _overlayEntries.first.opaque = false;\n\n        break;\n      case AnimationStatus.forward:\n        _currentStatus = SnackbarStatus.opening;\n        _snackbarStatus?.call(_currentStatus);\n        break;\n      case AnimationStatus.reverse:\n        _currentStatus = SnackbarStatus.closing;\n        _snackbarStatus?.call(_currentStatus);\n        if (_overlayEntries.isNotEmpty) _overlayEntries.first.opaque = false;\n        break;\n      case AnimationStatus.dismissed:\n        assert(!_overlayEntries.first.opaque);\n        _currentStatus = SnackbarStatus.closed;\n        _snackbarStatus?.call(_currentStatus);\n        _removeOverlay();\n        break;\n    }\n  }\n\n  void _removeEntry() {\n    assert(\n      !_transitionCompleter.isCompleted,\n      'Cannot remove entry from a disposed snackbar',\n    );\n\n    _cancelTimer();\n\n    if (_wasDismissedBySwipe) {\n      Timer(const Duration(milliseconds: 200), _controller.reset);\n      _wasDismissedBySwipe = false;\n    } else {\n      _controller.reverse();\n    }\n  }\n\n  void _removeOverlay() {\n    if (!_isTesting) {\n      for (var element in _overlayEntries) {\n        element.remove();\n      }\n    }\n\n    assert(!_transitionCompleter.isCompleted,\n        'Cannot remove overlay from a disposed snackbar');\n    _controller.dispose();\n    _overlayEntries.clear();\n    _transitionCompleter.complete();\n  }\n\n  Future<void> _show() {\n    _configureOverlay();\n    return future;\n  }\n\n  static Future<void> cancelAllSnackbars() async {\n    await GetRootState.controller.config.snackBarQueue.cancelAllJobs();\n  }\n\n  static Future<void> closeCurrentSnackbar() async {\n    await GetRootState.controller.config.snackBarQueue.closeCurrentJob();\n  }\n}\n\nclass SnackBarQueue {\n  final _queue = GetQueue();\n  final _snackbarList = <SnackbarController>[];\n\n  SnackbarController? get _currentSnackbar {\n    if (_snackbarList.isEmpty) return null;\n    return _snackbarList.first;\n  }\n\n  bool get isJobInProgress => _snackbarList.isNotEmpty;\n\n  Future<void> addJob(SnackbarController job) async {\n    _snackbarList.add(job);\n    final data = await _queue.add(job._show);\n    _snackbarList.remove(job);\n    return data;\n  }\n\n  Future<void> cancelAllJobs() async {\n    await _currentSnackbar?.close();\n    _queue.cancelAllJobs();\n    _snackbarList.clear();\n  }\n\n  void disposeControllers() {\n    if (_currentSnackbar != null) {\n      _currentSnackbar?._removeOverlay();\n      _currentSnackbar?._controller.dispose();\n      _snackbarList.remove(_currentSnackbar);\n    }\n\n    _queue.cancelAllJobs();\n\n    for (var element in _snackbarList) {\n      element._controller.dispose();\n    }\n    _snackbarList.clear();\n  }\n\n  Future<void> closeCurrentJob() async {\n    if (_currentSnackbar == null) return;\n    await _currentSnackbar!.close();\n  }\n}\n"
  },
  {
    "path": "lib/get_rx/get_rx.dart",
    "content": "library;\n\nexport 'src/rx_stream/rx_stream.dart';\nexport 'src/rx_types/rx_types.dart';\nexport 'src/rx_workers/rx_workers.dart';\n"
  },
  {
    "path": "lib/get_rx/src/rx_stream/mini_stream.dart",
    "content": "part of 'rx_stream.dart';\n\nclass Node<T> {\n  T? data;\n  Node<T>? next;\n  Node<T>? prev;\n  Node({this.data, this.next, this.prev});\n}\n\nclass MiniSubscription<T> {\n  const MiniSubscription(\n      this.data, this.onError, this.onDone, this.cancelOnError, this.listener);\n  final OnData<T> data;\n  final Function? onError;\n  final Callback? onDone;\n  final bool cancelOnError;\n\n  Future<void> cancel() async => listener.removeListener(this);\n\n  final FastList<T> listener;\n}\n\nclass MiniStream<T> {\n  FastList<T> listenable = FastList<T>();\n\n  late T _value;\n\n  T get value => _value;\n\n  set value(T val) {\n    add(val);\n  }\n\n  void add(T event) {\n    _value = event;\n    listenable._notifyData(event);\n  }\n\n  void addError(Object error, [StackTrace? stackTrace]) {\n    listenable._notifyError(error, stackTrace);\n  }\n\n  int get length => listenable.length;\n\n  bool get hasListeners => listenable.isNotEmpty;\n\n  bool get isClosed => _isClosed;\n\n  MiniSubscription<T> listen(void Function(T event) onData,\n      {Function? onError,\n      void Function()? onDone,\n      bool cancelOnError = false}) {\n    final subs = MiniSubscription<T>(\n      onData,\n      onError,\n      onDone,\n      cancelOnError,\n      listenable,\n    );\n    listenable.addListener(subs);\n    return subs;\n  }\n\n  bool _isClosed = false;\n\n  void close() {\n    if (_isClosed) {\n      throw 'You can not close a closed Stream';\n    }\n    listenable._notifyDone();\n    listenable.clear();\n    _isClosed = true;\n  }\n}\n\nclass FastList<T> {\n  Node<MiniSubscription<T>>? _head;\n  Node<MiniSubscription<T>>? _tail;\n  int _length = 0;\n\n  void _notifyData(T data) {\n    var currentNode = _head;\n    while (currentNode != null) {\n      currentNode.data?.data(data);\n      currentNode = currentNode.next;\n    }\n  }\n\n  void _notifyDone() {\n    var currentNode = _head;\n    while (currentNode != null) {\n      currentNode.data?.onDone?.call();\n      currentNode = currentNode.next;\n    }\n  }\n\n  void _notifyError(Object error, [StackTrace? stackTrace]) {\n    var currentNode = _head;\n    while (currentNode != null) {\n      currentNode.data?.onError?.call(error, stackTrace);\n      currentNode = currentNode.next;\n    }\n  }\n\n  bool get isEmpty => _length == 0;\n\n  bool get isNotEmpty => _length > 0;\n\n  int get length => _length;\n\n  MiniSubscription<T>? elementAt(int position) {\n    if (isEmpty || position < 0 || position >= _length) return null;\n\n    var node = _head;\n    var current = 0;\n\n    while (current != position) {\n      node = node!.next;\n      current++;\n    }\n    return node!.data;\n  }\n\n  void addListener(MiniSubscription<T> data) {\n    var newNode = Node(data: data);\n\n    if (isEmpty) {\n      _head = _tail = newNode;\n    } else {\n      _tail!.next = newNode;\n      newNode.prev = _tail;\n      _tail = newNode;\n    }\n    _length++;\n  }\n\n  bool contains(T element) {\n    var currentNode = _head;\n    while (currentNode != null) {\n      if (currentNode.data == element) return true;\n      currentNode = currentNode.next;\n    }\n    return false;\n  }\n\n  void removeListener(MiniSubscription<T> element) {\n    var currentNode = _head;\n    while (currentNode != null) {\n      if (currentNode.data == element) {\n        _removeNode(currentNode);\n        break;\n      }\n      currentNode = currentNode.next;\n    }\n  }\n\n  void clear() {\n    _head = _tail = null;\n    _length = 0;\n  }\n\n  void _removeNode(Node<MiniSubscription<T>> node) {\n    if (node.prev == null) {\n      _head = node.next;\n    } else {\n      node.prev!.next = node.next;\n    }\n\n    if (node.next == null) {\n      _tail = node.prev;\n    } else {\n      node.next!.prev = node.prev;\n    }\n\n    _length--;\n  }\n}\n"
  },
  {
    "path": "lib/get_rx/src/rx_stream/rx_stream.dart",
    "content": "library;\n\nimport 'dart:async';\n\nimport '../rx_typedefs/rx_typedefs.dart';\n\n//part 'get_stream.dart';\npart 'mini_stream.dart';\n"
  },
  {
    "path": "lib/get_rx/src/rx_typedefs/rx_typedefs.dart",
    "content": "typedef Condition = bool Function();\ntypedef OnData<T> = void Function(T data);\ntypedef Callback = void Function();\n"
  },
  {
    "path": "lib/get_rx/src/rx_types/rx_core/rx_impl.dart",
    "content": "part of '../rx_types.dart';\n\n/// global object that registers against `GetX` and `Obx`, and allows the\n/// reactivity\n/// of those `Widgets` and Rx values.\n\nmixin RxObjectMixin<T> on GetListenable<T> {\n  //late T _value;\n\n  /// Makes a direct update of [value] adding it to the Stream\n  /// useful when you make use of Rx for custom Types to refresh your UI.\n  ///\n  /// Sample:\n  /// ```\n  ///  class Person {\n  ///     String name, last;\n  ///     int age;\n  ///     Person({this.name, this.last, this.age});\n  ///     @override\n  ///     String toString() => '$name $last, $age years old';\n  ///  }\n  ///\n  /// final person = Person(name: 'John', last: 'Doe', age: 18).obs;\n  /// person.value.name = 'Roi';\n  /// person.refresh();\n  /// print( person );\n  /// ```\n  // void refresh() {\n  //   subject.add(value);\n  // }\n\n  /// updates the value to `null` and adds it to the Stream.\n  /// Even with null-safety coming, is still an important feature to support, as\n  /// `call()` doesn't accept `null` values. For instance,\n  /// `InputDecoration.errorText` has to be null to not show the \"error state\".\n  ///\n  /// Sample:\n  /// ```\n  /// final inputError = ''.obs..nil();\n  /// print('${inputError.runtimeType}: $inputError'); // outputs > RxString: null\n  /// ```\n  // void nil() {\n  //   subject.add(_value = null);\n  // }\n\n  /// Makes this Rx looks like a function so you can update a new\n  /// value using `rx(someOtherValue)`. Practical to assign the Rx directly\n  /// to some Widget that has a signature ::onChange( value )\n  ///\n  /// Example:\n  /// ```\n  /// final myText = 'GetX rocks!'.obs;\n  ///\n  /// // in your Constructor, just to check it works :P\n  /// ever( myText, print ) ;\n  ///\n  /// // in your build(BuildContext) {\n  /// TextField(\n  ///   onChanged: myText,\n  /// ),\n  ///```\n  @override\n  T call([T? v]) {\n    if (v != null) {\n      value = v;\n    }\n    return value;\n  }\n\n  bool firstRebuild = true;\n  bool sentToStream = false;\n\n  /// Same as `toString()` but using a getter.\n  String get string => value.toString();\n\n  @override\n  String toString() => value.toString();\n\n  /// Returns the json representation of `value`.\n  dynamic toJson() => value;\n\n  /// This equality override works for _RxImpl instances and the internal\n  /// values.\n  @override\n  // ignore: avoid_equals_and_hash_code_on_mutable_classes\n  bool operator ==(Object o) {\n    // Todo, find a common implementation for the hashCode of different Types.\n    if (o is T) return value == o;\n    if (o is RxObjectMixin<T>) return value == o.value;\n    return false;\n  }\n\n  @override\n  // ignore: avoid_equals_and_hash_code_on_mutable_classes\n  int get hashCode => value.hashCode;\n\n  /// Updates the [value] and adds it to the stream, updating the observer\n  /// Widget, only if it's different from the previous value.\n  @override\n  set value(T val) {\n    if (isDisposed) return;\n    sentToStream = false;\n    if (value == val && !firstRebuild) return;\n    firstRebuild = false;\n    sentToStream = true;\n    super.value = val;\n  }\n\n  /// Returns a [StreamSubscription] similar to [listen], but with the\n  /// added benefit that it primes the stream with the current [value], rather\n  /// than waiting for the next [value]. This should not be called in [onInit]\n  /// or anywhere else during the build process.\n  StreamSubscription<T> listenAndPump(void Function(T event) onData,\n      {Function? onError, void Function()? onDone, bool? cancelOnError}) {\n    final subscription = listen(\n      onData,\n      onError: onError,\n      onDone: onDone,\n      cancelOnError: cancelOnError,\n    );\n\n    subject.add(value);\n\n    return subscription;\n  }\n\n  /// Binds an existing `Stream<T>` to this `Rx<T>` to keep the values in sync.\n  /// You can bind multiple sources to update the value.\n  /// Closing the subscription will happen automatically when the observer\n  /// Widget (`GetX` or `Obx`) gets unmounted from the Widget tree.\n  void bindStream(Stream<T> stream) {\n    // final listSubscriptions =\n    //     _subscriptions[subject] ??= <StreamSubscription>[];\n\n    final sub = stream.listen((va) => value = va);\n    reportAdd(sub.cancel);\n  }\n}\n\n/// Base Rx class that manages all the stream logic for any Type.\nabstract class _RxImpl<T> extends GetListenable<T> with RxObjectMixin<T> {\n  _RxImpl(super.initial);\n\n  void addError(Object error, [StackTrace? stackTrace]) {\n    subject.addError(error, stackTrace);\n  }\n\n  Stream<R> map<R>(R Function(T? data) mapper) => stream.map(mapper);\n\n  /// Uses a callback to update [value] internally, similar to [refresh],\n  /// but provides the current value as the argument.\n  /// Makes sense for custom Rx types (like Models).\n  ///\n  /// Sample:\n  /// ```\n  ///  class Person {\n  ///     String name, last;\n  ///     int age;\n  ///     Person({this.name, this.last, this.age});\n  ///     @override\n  ///     String toString() => '$name $last, $age years old';\n  ///  }\n  ///\n  /// final person = Person(name: 'John', last: 'Doe', age: 18).obs;\n  /// person.update((person) {\n  ///   person.name = 'Roi';\n  /// });\n  /// print( person );\n  /// ```\n  void update(T Function(T? val) fn) {\n    value = fn(value);\n    // subject.add(value);\n  }\n\n  /// Following certain practices on Rx data, we might want to react to certain\n  /// listeners when a value has been provided, even if the value is the same.\n  /// At the moment, we ignore part of the process if we `.call(value)` with\n  /// the same value since it holds the value and there's no real\n  /// need triggering the entire process for the same value inside, but\n  /// there are other situations where we might be interested in\n  /// triggering this.\n  ///\n  /// For example, supposed we have a `int seconds = 2` and we want to animate\n  /// from invisible to visible a widget in two seconds:\n  /// `RxEvent<int>.call(seconds);`\n  /// then after a click happens, you want to call a `RxEvent<int>.call(seconds)`.\n  /// By doing `call(seconds)`, if the value being held is the same,\n  /// the listeners won't trigger, hence we need this new `trigger` function.\n  /// This will refresh the listener of an AnimatedWidget and will keep\n  /// the value if the Rx is kept in memory.\n  /// Sample:\n  /// ```\n  /// Rx<Int> secondsRx = RxInt();\n  /// secondsRx.listen((value) => print(\"$value seconds set\"));\n  ///\n  /// secondsRx.call(2);      // This won't trigger any listener, since the value is the same\n  /// secondsRx.trigger(2);   // This will trigger the listener independently from the value.\n  /// ```\n  ///\n  void trigger(T v) {\n    var firstRebuild = this.firstRebuild;\n    value = v;\n    // If it's not the first rebuild, the listeners have been called already\n    // So we won't call them again.\n    if (!firstRebuild && !sentToStream) {\n      subject.add(v);\n    }\n  }\n}\n\nclass RxBool extends Rx<bool> {\n  RxBool(super.initial);\n  @override\n  String toString() {\n    return value ? \"true\" : \"false\";\n  }\n}\n\nclass RxnBool extends Rx<bool?> {\n  RxnBool([super.initial]);\n  @override\n  String toString() {\n    return \"$value\";\n  }\n}\n\nextension RxBoolExt on Rx<bool> {\n  bool get isTrue => value;\n\n  bool get isFalse => !isTrue;\n\n  bool operator &(bool other) => other && value;\n\n  bool operator |(bool other) => other || value;\n\n  bool operator ^(bool other) => !other == value;\n\n  /// Toggles the bool [value] between false and true.\n  /// A shortcut for `flag.value = !flag.value;`\n  void toggle() {\n    call(!value);\n    // return this;\n  }\n}\n\nextension RxnBoolExt on Rx<bool?> {\n  bool? get isTrue => value;\n\n  bool? get isFalse {\n    if (value != null) return !isTrue!;\n    return null;\n  }\n\n  bool? operator &(bool other) {\n    if (value != null) {\n      return other && value!;\n    }\n    return null;\n  }\n\n  bool? operator |(bool other) {\n    if (value != null) {\n      return other || value!;\n    }\n    return null;\n  }\n\n  bool? operator ^(bool other) => !other == value;\n\n  /// Toggles the bool [value] between false and true.\n  /// A shortcut for `flag.value = !flag.value;`\n  void toggle() {\n    if (value != null) {\n      call(!value!);\n      // return this;\n    }\n  }\n}\n\n/// Foundation class used for custom `Types` outside the common native Dart\n/// types.\n/// For example, any custom \"Model\" class, like User().obs will use `Rx` as\n/// wrapper.\nclass Rx<T> extends _RxImpl<T> {\n  Rx(super.initial);\n\n  @override\n  dynamic toJson() {\n    try {\n      return (value as dynamic)?.toJson();\n    } on Exception catch (_) {\n      throw '$T has not method [toJson]';\n    }\n  }\n}\n\nclass Rxn<T> extends Rx<T?> {\n  Rxn([super.initial]);\n\n  @override\n  dynamic toJson() {\n    try {\n      return (value as dynamic)?.toJson();\n    } on Exception catch (_) {\n      throw '$T has not method [toJson]';\n    }\n  }\n}\n\nextension StringExtension on String {\n  /// Returns a `RxString` with [this] `String` as initial value.\n  RxString get obs => RxString(this);\n}\n\nextension IntExtension on int {\n  /// Returns a `RxInt` with [this] `int` as initial value.\n  RxInt get obs => RxInt(this);\n}\n\nextension DoubleExtension on double {\n  /// Returns a `RxDouble` with [this] `double` as initial value.\n  RxDouble get obs => RxDouble(this);\n}\n\nextension BoolExtension on bool {\n  /// Returns a `RxBool` with [this] `bool` as initial value.\n  RxBool get obs => RxBool(this);\n}\n\nextension RxT<T extends Object> on T {\n  /// Returns a `Rx` instance with [this] `T` as initial value.\n  Rx<T> get obs => Rx<T>(this);\n}\n\n/// This method will replace the old `.obs` method.\n/// It's a breaking change, but it is essential to avoid conflicts with\n/// the new dart 3 features. T will be inferred by contextual type inference\n/// rather than the extension type.\nextension RxTnew on Object {\n  /// Returns a `Rx` instance with [this] `T` as initial value.\n  Rx<T> obs<T>() => Rx<T>(this as T);\n}\n"
  },
  {
    "path": "lib/get_rx/src/rx_types/rx_core/rx_interface.dart",
    "content": "part of '../rx_types.dart';\n\n/// This class is the foundation for all reactive (Rx) classes that makes Get\n/// so powerful.\n/// This interface is the contract that `_RxImpl<T>` uses in all it's\n/// subclass.\nabstract class RxInterface<T> implements ValueListenable<T> {\n  /// Close the Rx Variable\n  void close();\n\n  /// Calls `callback` with current value, when the value changes.\n  StreamSubscription<T> listen(void Function(T event) onData,\n      {Function? onError, void Function()? onDone, bool? cancelOnError});\n}\n\nclass ObxError {\n  const ObxError();\n  @override\n  String toString() {\n    return \"\"\"\n      [Get] the improper use of a GetX has been detected. \n      You should only use GetX or Obx for the specific widget that will be updated.\n      If you are seeing this error, you probably did not insert any observable variables into GetX/Obx \n      or insert them outside the scope that GetX considers suitable for an update \n      (example: GetX => HeavyWidget => variableObservable).\n      If you need to update a parent widget and a child widget, wrap each one in an Obx/GetX.\n      \"\"\";\n  }\n}\n"
  },
  {
    "path": "lib/get_rx/src/rx_types/rx_core/rx_num.dart",
    "content": "part of '../rx_types.dart';\n\nextension RxNumExt<T extends num> on Rx<T> {\n  /// Multiplication operator.\n  num operator *(num other) => value * other;\n\n  /// Euclidean modulo operator.\n  ///\n  /// Returns the remainder of the Euclidean division. The Euclidean division of\n  /// two integers `a` and `b` yields two integers `q` and `r` such that\n  /// `a == b * q + r` and `0 <= r < b.abs()`.\n  ///\n  /// The Euclidean division is only defined for integers, but can be easily\n  /// extended to work with doubles. In that case `r` may have a non-integer\n  /// value, but it still verifies `0 <= r < |b|`.\n  ///\n  /// The sign of the returned value `r` is always positive.\n  ///\n  /// See [remainder] for the remainder of the truncating division.\n  num operator %(num other) => value % other;\n\n  /// Division operator.\n  double operator /(num other) => value / other;\n\n  /// Truncating division operator.\n  ///\n  /// If either operand is a [double] then the result of the truncating division\n  /// `a ~/ b` is equivalent to `(a / b).truncate().toInt()`.\n  ///\n  /// If both operands are [int]s then `a ~/ b` performs the truncating\n  /// integer division.\n  int operator ~/(num other) => value ~/ other;\n\n  /// Negate operator.\n  num operator -() => -value;\n\n  /// Returns the remainder of the truncating division of `this` by [other].\n  ///\n  /// The result `r` of this operation satisfies:\n  /// `this == (this ~/ other) * other + r`.\n  /// As a consequence the remainder `r` has the same sign as the divider\n  /// `this`.\n  num remainder(num other) => value.remainder(other);\n\n  /// Relational less than operator.\n  bool operator <(num other) => value < other;\n\n  /// Relational less than or equal operator.\n  bool operator <=(num other) => value <= other;\n\n  /// Relational greater than operator.\n  bool operator >(num other) => value > other;\n\n  /// Relational greater than or equal operator.\n  bool operator >=(num other) => value >= other;\n\n  /// True if the number is the double Not-a-Number value; otherwise, false.\n  bool get isNaN => value.isNaN;\n\n  /// True if the number is negative; otherwise, false.\n  ///\n  /// Negative numbers are those less than zero, and the double `-0.0`.\n  bool get isNegative => value.isNegative;\n\n  /// True if the number is positive infinity or negative infinity; otherwise,\n  /// false.\n  bool get isInfinite => value.isInfinite;\n\n  /// True if the number is finite; otherwise, false.\n  ///\n  /// The only non-finite numbers are NaN, positive infinity, and\n  /// negative infinity.\n  bool get isFinite => value.isFinite;\n\n  /// Returns the absolute value of this [num].\n  num abs() => value.abs();\n\n  /// Returns minus one, zero or plus one depending on the sign and\n  /// numerical value of the number.\n  ///\n  /// Returns minus one if the number is less than zero,\n  /// plus one if the number is greater than zero,\n  /// and zero if the number is equal to zero.\n  ///\n  /// Returns NaN if the number is the double NaN value.\n  ///\n  /// Returns a number of the same type as this number.\n  /// For doubles, `-0.0.sign == -0.0`.\n  /// The result satisfies:\n  ///\n  ///     n == n.sign * n.abs()\n  ///\n  /// for all numbers `n` (except NaN, because NaN isn't `==` to itself).\n  num get sign => value.sign;\n\n  /// Returns the integer closest to `this`.\n  ///\n  /// Rounds away from zero when there is no closest integer:\n  ///  `(3.5).round() == 4` and `(-3.5).round() == -4`.\n  ///\n  /// If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError].\n  int round() => value.round();\n\n  /// Returns the greatest integer no greater than `this`.\n  ///\n  /// If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError].\n  int floor() => value.floor();\n\n  /// Returns the least integer no smaller than `this`.\n  ///\n  /// If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError].\n  int ceil() => value.ceil();\n\n  /// Returns the integer obtained by discarding any fractional\n  /// digits from `this`.\n  ///\n  /// If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError].\n  int truncate() => value.truncate();\n\n  /// Returns the double integer value closest to `this`.\n  ///\n  /// Rounds away from zero when there is no closest integer:\n  ///  `(3.5).roundToDouble() == 4` and `(-3.5).roundToDouble() == -4`.\n  ///\n  /// If this is already an integer valued double, including `-0.0`, or it is a\n  /// non-finite double value, the value is returned unmodified.\n  ///\n  /// For the purpose of rounding, `-0.0` is considered to be below `0.0`,\n  /// and `-0.0` is therefore considered closer to negative numbers than `0.0`.\n  /// This means that for a value, `d` in the range `-0.5 < d < 0.0`,\n  /// the result is `-0.0`.\n  ///\n  /// The result is always a double.\n  /// If this is a numerically large integer, the result may be an infinite\n  /// double.\n  double roundToDouble() => value.roundToDouble();\n\n  /// Returns the greatest double integer value no greater than `this`.\n  ///\n  /// If this is already an integer valued double, including `-0.0`, or it is a\n  /// non-finite double value, the value is returned unmodified.\n  ///\n  /// For the purpose of rounding, `-0.0` is considered to be below `0.0`.\n  /// A number `d` in the range `0.0 < d < 1.0` will return `0.0`.\n  ///\n  /// The result is always a double.\n  /// If this is a numerically large integer, the result may be an infinite\n  /// double.\n  double floorToDouble() => value.floorToDouble();\n\n  /// Returns the least double integer value no smaller than `this`.\n  ///\n  /// If this is already an integer valued double, including `-0.0`, or it is a\n  /// non-finite double value, the value is returned unmodified.\n  ///\n  /// For the purpose of rounding, `-0.0` is considered to be below `0.0`.\n  /// A number `d` in the range `-1.0 < d < 0.0` will return `-0.0`.\n  ///\n  /// The result is always a double.\n  /// If this is a numerically large integer, the result may be an infinite\n  /// double.\n  double ceilToDouble() => value.ceilToDouble();\n\n  /// Returns the double integer value obtained by discarding any fractional\n  /// digits from the double value of `this`.\n  ///\n  /// If this is already an integer valued double, including `-0.0`, or it is a\n  /// non-finite double value, the value is returned unmodified.\n  ///\n  /// For the purpose of rounding, `-0.0` is considered to be below `0.0`.\n  /// A number `d` in the range `-1.0 < d < 0.0` will return `-0.0`, and\n  /// in the range `0.0 < d < 1.0` it will return 0.0.\n  ///\n  /// The result is always a double.\n  /// If this is a numerically large integer, the result may be an infinite\n  /// double.\n  double truncateToDouble() => value.truncateToDouble();\n\n  /// Returns this [num] clamped to be in the range [lowerLimit]-[upperLimit].\n  ///\n  /// The comparison is done using [compareTo] and therefore takes `-0.0` into\n  /// account. This also implies that [double.nan] is treated as the maximal\n  /// double value.\n  ///\n  /// The arguments [lowerLimit] and [upperLimit] must form a valid range where\n  /// `lowerLimit.compareTo(upperLimit) <= 0`.\n  num clamp(num lowerLimit, num upperLimit) =>\n      value.clamp(lowerLimit, upperLimit);\n\n  /// Truncates this [num] to an integer and returns the result as an [int]. */\n  int toInt() => value.toInt();\n\n  /// Return this [num] as a [double].\n  ///\n  /// If the number is not representable as a [double], an\n  /// approximation is returned. For numerically large integers, the\n  /// approximation may be infinite.\n  double toDouble() => value.toDouble();\n\n  /// Returns a decimal-point string-representation of `this`.\n  ///\n  /// Converts `this` to a [double] before computing the string representation.\n  ///\n  /// If the absolute value of `this` is greater or equal to `10^21` then this\n  /// methods returns an exponential representation computed by\n  /// `this.toStringAsExponential()`. Otherwise the result\n  /// is the closest string representation with exactly [fractionDigits] digits\n  /// after the decimal point. If [fractionDigits] equals 0 then the decimal\n  /// point is omitted.\n  ///\n  /// The parameter [fractionDigits] must be an integer satisfying:\n  /// `0 <= fractionDigits <= 20`.\n  ///\n  /// Examples:\n  ///\n  ///     1.toStringAsFixed(3);  // 1.000\n  ///     (4321.12345678).toStringAsFixed(3);  // 4321.123\n  ///     (4321.12345678).toStringAsFixed(5);  // 4321.12346\n  ///     123456789012345.toStringAsFixed(3);  // 123456789012345.000\n  ///     10000000000000000.toStringAsFixed(4); // 10000000000000000.0000\n  ///     5.25.toStringAsFixed(0); // 5\n  String toStringAsFixed(int fractionDigits) =>\n      value.toStringAsFixed(fractionDigits);\n\n  /// Returns an exponential string-representation of `this`.\n  ///\n  /// Converts `this` to a [double] before computing the string representation.\n  ///\n  /// If [fractionDigits] is given then it must be an integer satisfying:\n  /// `0 <= fractionDigits <= 20`. In this case the string contains exactly\n  /// [fractionDigits] after the decimal point. Otherwise, without the\n  /// parameter, the returned string uses the shortest number of digits that\n  /// accurately represent [this].\n  ///\n  /// If [fractionDigits] equals 0 then the decimal point is omitted.\n  /// Examples:\n  ///\n  ///     1.toStringAsExponential();       // 1e+0\n  ///     1.toStringAsExponential(3);      // 1.000e+0\n  ///     123456.toStringAsExponential();  // 1.23456e+5\n  ///     123456.toStringAsExponential(3); // 1.235e+5\n  ///     123.toStringAsExponential(0);    // 1e+2\n  String toStringAsExponential([int? fractionDigits]) =>\n      value.toStringAsExponential(fractionDigits);\n\n  /// Converts `this` to a double and returns a string representation with\n  /// exactly [precision] significant digits.\n  ///\n  /// The parameter [precision] must be an integer satisfying:\n  /// `1 <= precision <= 21`.\n  ///\n  /// Examples:\n  ///\n  ///     1.toStringAsPrecision(2);       // 1.0\n  ///     1e15.toStringAsPrecision(3);    // 1.00e+15\n  ///     1234567.toStringAsPrecision(3); // 1.23e+6\n  ///     1234567.toStringAsPrecision(9); // 1234567.00\n  ///     12345678901234567890.toStringAsPrecision(20); // 12345678901234567168\n  ///     12345678901234567890.toStringAsPrecision(14); // 1.2345678901235e+19\n  ///     0.00000012345.toStringAsPrecision(15); // 1.23450000000000e-7\n  ///     0.0000012345.toStringAsPrecision(15);  // 0.00000123450000000000\n  String toStringAsPrecision(int precision) =>\n      value.toStringAsPrecision(precision);\n}\n\nextension RxnNumExt<T extends num> on Rx<T?> {\n  /// Multiplication operator.\n  num? operator *(num other) {\n    if (value != null) {\n      return value! * other;\n    }\n    return null;\n  }\n\n  /// Euclidean modulo operator.\n  ///\n  /// Returns the remainder of the Euclidean division. The Euclidean division of\n  /// two integers `a` and `b` yields two integers `q` and `r` such that\n  /// `a == b * q + r` and `0 <= r < b.abs()`.\n  ///\n  /// The Euclidean division is only defined for integers, but can be easily\n  /// extended to work with doubles. In that case `r` may have a non-integer\n  /// value, but it still verifies `0 <= r < |b|`.\n  ///\n  /// The sign of the returned value `r` is always positive.\n  ///\n  /// See [remainder] for the remainder of the truncating division.\n  num? operator %(num other) {\n    if (value != null) {\n      return value! % other;\n    }\n    return null;\n  }\n\n  /// Division operator.\n  double? operator /(num other) {\n    if (value != null) {\n      return value! / other;\n    }\n    return null;\n  }\n\n  /// Truncating division operator.\n  ///\n  /// If either operand is a [double] then the result of the truncating division\n  /// `a ~/ b` is equivalent to `(a / b).truncate().toInt()`.\n  ///\n  /// If both operands are [int]s then `a ~/ b` performs the truncating\n  /// integer division.\n  int? operator ~/(num other) {\n    if (value != null) {\n      return value! ~/ other;\n    }\n    return null;\n  }\n\n  /// Negate operator.\n  num? operator -() {\n    if (value != null) {\n      return -value!;\n    }\n    return null;\n  }\n\n  /// Returns the remainder of the truncating division of `this` by [other].\n  ///\n  /// The result `r` of this operation satisfies:\n  /// `this == (this ~/ other) * other + r`.\n  /// As a consequence the remainder `r` has the same sign as the divider\n  /// `this`.\n  num? remainder(num other) => value?.remainder(other);\n\n  /// Relational less than operator.\n  bool? operator <(num other) {\n    if (value != null) {\n      return value! < other;\n    }\n    return null;\n  }\n\n  /// Relational less than or equal operator.\n  bool? operator <=(num other) {\n    if (value != null) {\n      return value! <= other;\n    }\n    return null;\n  }\n\n  /// Relational greater than operator.\n  bool? operator >(num other) {\n    if (value != null) {\n      return value! > other;\n    }\n    return null;\n  }\n\n  /// Relational greater than or equal operator.\n  bool? operator >=(num other) {\n    if (value != null) {\n      return value! >= other;\n    }\n    return null;\n  }\n\n  /// True if the number is the double Not-a-Number value; otherwise, false.\n  bool? get isNaN => value?.isNaN;\n\n  /// True if the number is negative; otherwise, false.\n  ///\n  /// Negative numbers are those less than zero, and the double `-0.0`.\n  bool? get isNegative => value?.isNegative;\n\n  /// True if the number is positive infinity or negative infinity; otherwise,\n  /// false.\n  bool? get isInfinite => value?.isInfinite;\n\n  /// True if the number is finite; otherwise, false.\n  ///\n  /// The only non-finite numbers are NaN, positive infinity, and\n  /// negative infinity.\n  bool? get isFinite => value?.isFinite;\n\n  /// Returns the absolute value of this [num].\n  num? abs() => value?.abs();\n\n  /// Returns minus one, zero or plus one depending on the sign and\n  /// numerical value of the number.\n  ///\n  /// Returns minus one if the number is less than zero,\n  /// plus one if the number is greater than zero,\n  /// and zero if the number is equal to zero.\n  ///\n  /// Returns NaN if the number is the double NaN value.\n  ///\n  /// Returns a number of the same type as this number.\n  /// For doubles, `-0.0.sign == -0.0`.\n  /// The result satisfies:\n  ///\n  ///     n == n.sign * n.abs()\n  ///\n  /// for all numbers `n` (except NaN, because NaN isn't `==` to itself).\n  num? get sign => value?.sign;\n\n  /// Returns the integer closest to `this`.\n  ///\n  /// Rounds away from zero when there is no closest integer:\n  ///  `(3.5).round() == 4` and `(-3.5).round() == -4`.\n  ///\n  /// If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError].\n  int? round() => value?.round();\n\n  /// Returns the greatest integer no greater than `this`.\n  ///\n  /// If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError].\n  int? floor() => value?.floor();\n\n  /// Returns the least integer no smaller than `this`.\n  ///\n  /// If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError].\n  int? ceil() => value?.ceil();\n\n  /// Returns the integer obtained by discarding any fractional\n  /// digits from `this`.\n  ///\n  /// If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError].\n  int? truncate() => value?.truncate();\n\n  /// Returns the double integer value closest to `this`.\n  ///\n  /// Rounds away from zero when there is no closest integer:\n  ///  `(3.5).roundToDouble() == 4` and `(-3.5).roundToDouble() == -4`.\n  ///\n  /// If this is already an integer valued double, including `-0.0`, or it is a\n  /// non-finite double value, the value is returned unmodified.\n  ///\n  /// For the purpose of rounding, `-0.0` is considered to be below `0.0`,\n  /// and `-0.0` is therefore considered closer to negative numbers than `0.0`.\n  /// This means that for a value, `d` in the range `-0.5 < d < 0.0`,\n  /// the result is `-0.0`.\n  ///\n  /// The result is always a double.\n  /// If this is a numerically large integer, the result may be an infinite\n  /// double.\n  double? roundToDouble() => value?.roundToDouble();\n\n  /// Returns the greatest double integer value no greater than `this`.\n  ///\n  /// If this is already an integer valued double, including `-0.0`, or it is a\n  /// non-finite double value, the value is returned unmodified.\n  ///\n  /// For the purpose of rounding, `-0.0` is considered to be below `0.0`.\n  /// A number `d` in the range `0.0 < d < 1.0` will return `0.0`.\n  ///\n  /// The result is always a double.\n  /// If this is a numerically large integer, the result may be an infinite\n  /// double.\n  double? floorToDouble() => value?.floorToDouble();\n\n  /// Returns the least double integer value no smaller than `this`.\n  ///\n  /// If this is already an integer valued double, including `-0.0`, or it is a\n  /// non-finite double value, the value is returned unmodified.\n  ///\n  /// For the purpose of rounding, `-0.0` is considered to be below `0.0`.\n  /// A number `d` in the range `-1.0 < d < 0.0` will return `-0.0`.\n  ///\n  /// The result is always a double.\n  /// If this is a numerically large integer, the result may be an infinite\n  /// double.\n  double? ceilToDouble() => value?.ceilToDouble();\n\n  /// Returns the double integer value obtained by discarding any fractional\n  /// digits from the double value of `this`.\n  ///\n  /// If this is already an integer valued double, including `-0.0`, or it is a\n  /// non-finite double value, the value is returned unmodified.\n  ///\n  /// For the purpose of rounding, `-0.0` is considered to be below `0.0`.\n  /// A number `d` in the range `-1.0 < d < 0.0` will return `-0.0`, and\n  /// in the range `0.0 < d < 1.0` it will return 0.0.\n  ///\n  /// The result is always a double.\n  /// If this is a numerically large integer, the result may be an infinite\n  /// double.\n  double? truncateToDouble() => value?.truncateToDouble();\n\n  /// Returns this [num] clamped to be in the range [lowerLimit]-[upperLimit].\n  ///\n  /// The comparison is done using [compareTo] and therefore takes `-0.0` into\n  /// account. This also implies that [double.nan] is treated as the maximal\n  /// double value.\n  ///\n  /// The arguments [lowerLimit] and [upperLimit] must form a valid range where\n  /// `lowerLimit.compareTo(upperLimit) <= 0`.\n  num? clamp(num lowerLimit, num upperLimit) =>\n      value?.clamp(lowerLimit, upperLimit);\n\n  /// Truncates this [num] to an integer and returns the result as an [int]. */\n  int? toInt() => value?.toInt();\n\n  /// Return this [num] as a [double].\n  ///\n  /// If the number is not representable as a [double], an\n  /// approximation is returned. For numerically large integers, the\n  /// approximation may be infinite.\n  double? toDouble() => value?.toDouble();\n\n  /// Returns a decimal-point string-representation of `this`.\n  ///\n  /// Converts `this` to a [double] before computing the string representation.\n  ///\n  /// If the absolute value of `this` is greater or equal to `10^21` then this\n  /// methods returns an exponential representation computed by\n  /// `this.toStringAsExponential()`. Otherwise the result\n  /// is the closest string representation with exactly [fractionDigits] digits\n  /// after the decimal point. If [fractionDigits] equals 0 then the decimal\n  /// point is omitted.\n  ///\n  /// The parameter [fractionDigits] must be an integer satisfying:\n  /// `0 <= fractionDigits <= 20`.\n  ///\n  /// Examples:\n  ///\n  ///     1.toStringAsFixed(3);  // 1.000\n  ///     (4321.12345678).toStringAsFixed(3);  // 4321.123\n  ///     (4321.12345678).toStringAsFixed(5);  // 4321.12346\n  ///     123456789012345.toStringAsFixed(3);  // 123456789012345.000\n  ///     10000000000000000.toStringAsFixed(4); // 10000000000000000.0000\n  ///     5.25.toStringAsFixed(0); // 5\n  String? toStringAsFixed(int fractionDigits) =>\n      value?.toStringAsFixed(fractionDigits);\n\n  /// Returns an exponential string-representation of `this`.\n  ///\n  /// Converts `this` to a [double] before computing the string representation.\n  ///\n  /// If [fractionDigits] is given then it must be an integer satisfying:\n  /// `0 <= fractionDigits <= 20`. In this case the string contains exactly\n  /// [fractionDigits] after the decimal point. Otherwise, without the\n  /// parameter, the returned string uses the shortest number of digits that\n  /// accurately represent [this].\n  ///\n  /// If [fractionDigits] equals 0 then the decimal point is omitted.\n  /// Examples:\n  ///\n  ///     1.toStringAsExponential();       // 1e+0\n  ///     1.toStringAsExponential(3);      // 1.000e+0\n  ///     123456.toStringAsExponential();  // 1.23456e+5\n  ///     123456.toStringAsExponential(3); // 1.235e+5\n  ///     123.toStringAsExponential(0);    // 1e+2\n  String? toStringAsExponential([int? fractionDigits]) =>\n      value?.toStringAsExponential(fractionDigits);\n\n  /// Converts `this` to a double and returns a string representation with\n  /// exactly [precision] significant digits.\n  ///\n  /// The parameter [precision] must be an integer satisfying:\n  /// `1 <= precision <= 21`.\n  ///\n  /// Examples:\n  ///\n  ///     1.toStringAsPrecision(2);       // 1.0\n  ///     1e15.toStringAsPrecision(3);    // 1.00e+15\n  ///     1234567.toStringAsPrecision(3); // 1.23e+6\n  ///     1234567.toStringAsPrecision(9); // 1234567.00\n  ///     12345678901234567890.toStringAsPrecision(20); // 12345678901234567168\n  ///     12345678901234567890.toStringAsPrecision(14); // 1.2345678901235e+19\n  ///     0.00000012345.toStringAsPrecision(15); // 1.23450000000000e-7\n  ///     0.0000012345.toStringAsPrecision(15);  // 0.00000123450000000000\n  String? toStringAsPrecision(int precision) =>\n      value?.toStringAsPrecision(precision);\n}\n\nclass RxNum extends Rx<num> {\n  RxNum(super.initial);\n\n  num operator +(num other) {\n    value += other;\n    return value;\n  }\n\n  /// Subtraction operator.\n  num operator -(num other) {\n    value -= other;\n    return value;\n  }\n}\n\nclass RxnNum extends Rx<num?> {\n  RxnNum([super.initial]);\n\n  num? operator +(num other) {\n    if (value != null) {\n      value = value! + other;\n      return value;\n    }\n    return null;\n  }\n\n  /// Subtraction operator.\n  num? operator -(num other) {\n    if (value != null) {\n      value = value! - other;\n      return value;\n    }\n    return null;\n  }\n}\n\nextension RxDoubleExt on Rx<double> {\n  /// Addition operator.\n  Rx<double> operator +(num other) {\n    value = value + other;\n    return this;\n  }\n\n  /// Subtraction operator.\n  Rx<double> operator -(num other) {\n    value = value - other;\n    return this;\n  }\n\n  /// Multiplication operator.\n  double operator *(num other) => value * other;\n\n  double operator %(num other) => value % other;\n\n  /// Division operator.\n  double operator /(num other) => value / other;\n\n  /// Truncating division operator.\n  ///\n  /// The result of the truncating division `a ~/ b` is equivalent to\n  /// `(a / b).truncate()`.\n  int operator ~/(num other) => value ~/ other;\n\n  /// Negate operator. */\n  double operator -() => -value;\n\n  /// Returns the absolute value of this [double].\n  double abs() => value.abs();\n\n  /// Returns the sign of the double's numerical value.\n  ///\n  /// Returns -1.0 if the value is less than zero,\n  /// +1.0 if the value is greater than zero,\n  /// and the value itself if it is -0.0, 0.0 or NaN.\n  double get sign => value.sign;\n\n  /// Returns the integer closest to `this`.\n  ///\n  /// Rounds away from zero when there is no closest integer:\n  ///  `(3.5).round() == 4` and `(-3.5).round() == -4`.\n  ///\n  /// If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError].\n  int round() => value.round();\n\n  /// Returns the greatest integer no greater than `this`.\n  ///\n  /// If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError].\n  int floor() => value.floor();\n\n  /// Returns the least integer no smaller than `this`.\n  ///\n  /// If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError].\n  int ceil() => value.ceil();\n\n  /// Returns the integer obtained by discarding any fractional\n  /// digits from `this`.\n  ///\n  /// If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError].\n  int truncate() => value.truncate();\n\n  /// Returns the integer double value closest to `this`.\n  ///\n  /// Rounds away from zero when there is no closest integer:\n  ///  `(3.5).roundToDouble() == 4` and `(-3.5).roundToDouble() == -4`.\n  ///\n  /// If this is already an integer valued double, including `-0.0`, or it is\n  /// not a finite value, the value is returned unmodified.\n  ///\n  /// For the purpose of rounding, `-0.0` is considered to be below `0.0`,\n  /// and `-0.0` is therefore considered closer to negative numbers than `0.0`.\n  /// This means that for a value, `d` in the range `-0.5 < d < 0.0`,\n  /// the result is `-0.0`.\n  double roundToDouble() => value.roundToDouble();\n\n  /// Returns the greatest integer double value no greater than `this`.\n  ///\n  /// If this is already an integer valued double, including `-0.0`, or it is\n  /// not a finite value, the value is returned unmodified.\n  ///\n  /// For the purpose of rounding, `-0.0` is considered to be below `0.0`.\n  /// A number `d` in the range `0.0 < d < 1.0` will return `0.0`.\n  double floorToDouble() => value.floorToDouble();\n\n  /// Returns the least integer double value no smaller than `this`.\n  ///\n  /// If this is already an integer valued double, including `-0.0`, or it is\n  /// not a finite value, the value is returned unmodified.\n  ///\n  /// For the purpose of rounding, `-0.0` is considered to be below `0.0`.\n  /// A number `d` in the range `-1.0 < d < 0.0` will return `-0.0`.\n  double ceilToDouble() => value.ceilToDouble();\n\n  /// Returns the integer double value obtained by discarding any fractional\n  /// digits from `this`.\n  ///\n  /// If this is already an integer valued double, including `-0.0`, or it is\n  /// not a finite value, the value is returned unmodified.\n  ///\n  /// For the purpose of rounding, `-0.0` is considered to be below `0.0`.\n  /// A number `d` in the range `-1.0 < d < 0.0` will return `-0.0`, and\n  /// in the range `0.0 < d < 1.0` it will return 0.0.\n  double truncateToDouble() => value.truncateToDouble();\n}\n\nextension RxnDoubleExt on Rx<double?> {\n  /// Addition operator.\n  Rx<double?>? operator +(num other) {\n    if (value != null) {\n      value = value! + other;\n      return this;\n    }\n    return null;\n  }\n\n  /// Subtraction operator.\n  Rx<double?>? operator -(num other) {\n    if (value != null) {\n      value = value! + other;\n      return this;\n    }\n    return null;\n  }\n\n  /// Multiplication operator.\n  double? operator *(num other) {\n    if (value != null) {\n      return value! * other;\n    }\n    return null;\n  }\n\n  double? operator %(num other) {\n    if (value != null) {\n      return value! % other;\n    }\n    return null;\n  }\n\n  /// Division operator.\n  double? operator /(num other) {\n    if (value != null) {\n      return value! / other;\n    }\n    return null;\n  }\n\n  /// Truncating division operator.\n  ///\n  /// The result of the truncating division `a ~/ b` is equivalent to\n  /// `(a / b).truncate()`.\n  int? operator ~/(num other) {\n    if (value != null) {\n      return value! ~/ other;\n    }\n    return null;\n  }\n\n  /// Negate operator. */\n  double? operator -() {\n    if (value != null) {\n      return -value!;\n    }\n    return null;\n  }\n\n  /// Returns the absolute value of this [double].\n  double? abs() {\n    return value?.abs();\n  }\n\n  /// Returns the sign of the double's numerical value.\n  ///\n  /// Returns -1.0 if the value is less than zero,\n  /// +1.0 if the value is greater than zero,\n  /// and the value itself if it is -0.0, 0.0 or NaN.\n  double? get sign => value?.sign;\n\n  /// Returns the integer closest to `this`.\n  ///\n  /// Rounds away from zero when there is no closest integer:\n  ///  `(3.5).round() == 4` and `(-3.5).round() == -4`.\n  ///\n  /// If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError].\n  int? round() => value?.round();\n\n  /// Returns the greatest integer no greater than `this`.\n  ///\n  /// If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError].\n  int? floor() => value?.floor();\n\n  /// Returns the least integer no smaller than `this`.\n  ///\n  /// If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError].\n  int? ceil() => value?.ceil();\n\n  /// Returns the integer obtained by discarding any fractional\n  /// digits from `this`.\n  ///\n  /// If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError].\n  int? truncate() => value?.truncate();\n\n  /// Returns the integer double value closest to `this`.\n  ///\n  /// Rounds away from zero when there is no closest integer:\n  ///  `(3.5).roundToDouble() == 4` and `(-3.5).roundToDouble() == -4`.\n  ///\n  /// If this is already an integer valued double, including `-0.0`, or it is\n  /// not a finite value, the value is returned unmodified.\n  ///\n  /// For the purpose of rounding, `-0.0` is considered to be below `0.0`,\n  /// and `-0.0` is therefore considered closer to negative numbers than `0.0`.\n  /// This means that for a value, `d` in the range `-0.5 < d < 0.0`,\n  /// the result is `-0.0`.\n  double? roundToDouble() => value?.roundToDouble();\n\n  /// Returns the greatest integer double value no greater than `this`.\n  ///\n  /// If this is already an integer valued double, including `-0.0`, or it is\n  /// not a finite value, the value is returned unmodified.\n  ///\n  /// For the purpose of rounding, `-0.0` is considered to be below `0.0`.\n  /// A number `d` in the range `0.0 < d < 1.0` will return `0.0`.\n  double? floorToDouble() => value?.floorToDouble();\n\n  /// Returns the least integer double value no smaller than `this`.\n  ///\n  /// If this is already an integer valued double, including `-0.0`, or it is\n  /// not a finite value, the value is returned unmodified.\n  ///\n  /// For the purpose of rounding, `-0.0` is considered to be below `0.0`.\n  /// A number `d` in the range `-1.0 < d < 0.0` will return `-0.0`.\n  double? ceilToDouble() => value?.ceilToDouble();\n\n  /// Returns the integer double value obtained by discarding any fractional\n  /// digits from `this`.\n  ///\n  /// If this is already an integer valued double, including `-0.0`, or it is\n  /// not a finite value, the value is returned unmodified.\n  ///\n  /// For the purpose of rounding, `-0.0` is considered to be below `0.0`.\n  /// A number `d` in the range `-1.0 < d < 0.0` will return `-0.0`, and\n  /// in the range `0.0 < d < 1.0` it will return 0.0.\n  double? truncateToDouble() => value?.truncateToDouble();\n}\n\nclass RxDouble extends Rx<double> {\n  RxDouble(super.initial);\n}\n\nclass RxnDouble extends Rx<double?> {\n  RxnDouble([super.initial]);\n}\n\nclass RxInt extends Rx<int> {\n  RxInt(super.initial);\n\n  /// Addition operator.\n  RxInt operator +(int other) {\n    value = value + other;\n    return this;\n  }\n\n  /// Subtraction operator.\n  RxInt operator -(int other) {\n    value = value - other;\n    return this;\n  }\n}\n\nclass RxnInt extends Rx<int?> {\n  RxnInt([super.initial]);\n\n  /// Addition operator.\n  RxnInt operator +(int other) {\n    if (value != null) {\n      value = value! + other;\n    }\n    return this;\n  }\n\n  /// Subtraction operator.\n  RxnInt operator -(int other) {\n    if (value != null) {\n      value = value! - other;\n    }\n    return this;\n  }\n}\n\nextension RxIntExt on Rx<int> {\n  /// Bit-wise and operator.\n  ///\n  /// Treating both `this` and [other] as sufficiently large two's component\n  /// integers, the result is a number with only the bits set that are set in\n  /// both `this` and [other]\n  ///\n  /// If both operands are negative, the result is negative, otherwise\n  /// the result is non-negative.\n  int operator &(int other) => value & other;\n\n  /// Bit-wise or operator.\n  ///\n  /// Treating both `this` and [other] as sufficiently large two's component\n  /// integers, the result is a number with the bits set that are set in either\n  /// of `this` and [other]\n  ///\n  /// If both operands are non-negative, the result is non-negative,\n  /// otherwise the result is negative.\n  int operator |(int other) => value | other;\n\n  /// Bit-wise exclusive-or operator.\n  ///\n  /// Treating both `this` and [other] as sufficiently large two's component\n  /// integers, the result is a number with the bits set that are set in one,\n  /// but not both, of `this` and [other]\n  ///\n  /// If the operands have the same sign, the result is non-negative,\n  /// otherwise the result is negative.\n  int operator ^(int other) => value ^ other;\n\n  /// The bit-wise negate operator.\n  ///\n  /// Treating `this` as a sufficiently large two's component integer,\n  /// the result is a number with the opposite bits set.\n  ///\n  /// This maps any integer `x` to `-x - 1`.\n  int operator ~() => ~value;\n\n  /// Shift the bits of this integer to the left by [shiftAmount].\n  ///\n  /// Shifting to the left makes the number larger, effectively multiplying\n  /// the number by `pow(2, shiftIndex)`.\n  ///\n  /// There is no limit on the size of the result. It may be relevant to\n  /// limit intermediate values by using the \"and\" operator with a suitable\n  /// mask.\n  ///\n  /// It is an error if [shiftAmount] is negative.\n  int operator <<(int shiftAmount) => value << shiftAmount;\n\n  /// Shift the bits of this integer to the right by [shiftAmount].\n  ///\n  /// Shifting to the right makes the number smaller and drops the least\n  /// significant bits, effectively doing an integer division by\n  ///`pow(2, shiftIndex)`.\n  ///\n  /// It is an error if [shiftAmount] is negative.\n  int operator >>(int shiftAmount) => value >> shiftAmount;\n\n  /// Returns this integer to the power of [exponent] modulo [modulus].\n  ///\n  /// The [exponent] must be non-negative and [modulus] must be\n  /// positive.\n  int modPow(int exponent, int modulus) => value.modPow(exponent, modulus);\n\n  /// Returns the modular multiplicative inverse of this integer\n  /// modulo [modulus].\n  ///\n  /// The [modulus] must be positive.\n  ///\n  /// It is an error if no modular inverse exists.\n  int modInverse(int modulus) => value.modInverse(modulus);\n\n  /// Returns the greatest common divisor of this integer and [other].\n  ///\n  /// If either number is non-zero, the result is the numerically greatest\n  /// integer dividing both `this` and `other`.\n  ///\n  /// The greatest common divisor is independent of the order,\n  /// so `x.gcd(y)` is  always the same as `y.gcd(x)`.\n  ///\n  /// For any integer `x`, `x.gcd(x)` is `x.abs()`.\n  ///\n  /// If both `this` and `other` is zero, the result is also zero.\n  int gcd(int other) => value.gcd(other);\n\n  /// Returns true if and only if this integer is even.\n  bool get isEven => value.isEven;\n\n  /// Returns true if and only if this integer is odd.\n  bool get isOdd => value.isOdd;\n\n  /// Returns the minimum number of bits required to store this integer.\n  ///\n  /// The number of bits excludes the sign bit, which gives the natural length\n  /// for non-negative (unsigned) values.  Negative values are complemented to\n  /// return the bit position of the first bit that differs from the sign bit.\n  ///\n  /// To find the number of bits needed to store the value as a signed value,\n  /// add one, i.e. use `x.bitLength + 1`.\n  /// ```\n  /// x.bitLength == (-x-1).bitLength\n  ///\n  /// 3.bitLength == 2;     // 00000011\n  /// 2.bitLength == 2;     // 00000010\n  /// 1.bitLength == 1;     // 00000001\n  /// 0.bitLength == 0;     // 00000000\n  /// (-1).bitLength == 0;  // 11111111\n  /// (-2).bitLength == 1;  // 11111110\n  /// (-3).bitLength == 2;  // 11111101\n  /// (-4).bitLength == 2;  // 11111100\n  /// ```\n  int get bitLength => value.bitLength;\n\n  /// Returns the least significant [width] bits of this integer as a\n  /// non-negative number (i.e. unsigned representation).  The returned value\n  /// has zeros in all bit positions higher than [width].\n  /// ```\n  /// (-1).toUnsigned(5) == 31   // 11111111  ->  00011111\n  /// ```\n  /// This operation can be used to simulate arithmetic from low level\n  /// languages.\n  /// For example, to increment an 8 bit quantity:\n  /// ```\n  /// q = (q + 1).toUnsigned(8);\n  /// ```\n  /// `q` will count from `0` up to `255` and then wrap around to `0`.\n  ///\n  /// If the input fits in [width] bits without truncation, the result is the\n  /// same as the input.  The minimum width needed to avoid truncation of `x` is\n  /// given by `x.bitLength`, i.e.\n  /// ```\n  /// x == x.toUnsigned(x.bitLength);\n  /// ```\n  int toUnsigned(int width) => value.toUnsigned(width);\n\n  /// Returns the least significant [width] bits of this integer, extending the\n  /// highest retained bit to the sign.  This is the same as truncating the\n  /// value to fit in [width] bits using an signed 2-s complement\n  /// representation.\n  /// The returned value has the same bit value in all positions higher than\n  /// [width].\n  ///\n  /// ```\n  ///                                V--sign bit-V\n  /// 16.toSigned(5) == -16   //  00010000 -> 11110000\n  /// 239.toSigned(5) == 15   //  11101111 -> 00001111\n  ///                                ^           ^\n  /// ```\n  /// This operation can be used to simulate arithmetic from low level\n  /// languages.\n  /// For example, to increment an 8 bit signed quantity:\n  /// ```\n  /// q = (q + 1).toSigned(8);\n  /// ```\n  /// `q` will count from `0` up to `127`, wrap to `-128` and count back up to\n  /// `127`.\n  ///\n  /// If the input value fits in [width] bits without truncation, the result is\n  /// the same as the input.  The minimum width needed to avoid truncation\n  /// of `x` is `x.bitLength + 1`, i.e.\n  /// ```\n  /// x == x.toSigned(x.bitLength + 1);\n  /// ```\n  int toSigned(int width) => value.toSigned(width);\n\n  /// Return the negative value of this integer.\n  ///\n  /// The result of negating an integer always has the opposite sign, except\n  /// for zero, which is its own negation.\n  int operator -() => -value;\n\n  /// Returns the absolute value of this integer.\n  ///\n  /// For any integer `x`, the result is the same as `x < 0 ? -x : x`.\n  int abs() => value.abs();\n\n  /// Returns the sign of this integer.\n  ///\n  /// Returns 0 for zero, -1 for values less than zero and\n  /// +1 for values greater than zero.\n  int get sign => value.sign;\n\n  /// Returns `this`.\n  int round() => value.round();\n\n  /// Returns `this`.\n  int floor() => value.floor();\n\n  /// Returns `this`.\n  int ceil() => value.ceil();\n\n  /// Returns `this`.\n  int truncate() => value.truncate();\n\n  /// Returns `this.toDouble()`.\n  double roundToDouble() => value.roundToDouble();\n\n  /// Returns `this.toDouble()`.\n  double floorToDouble() => value.floorToDouble();\n\n  /// Returns `this.toDouble()`.\n  double ceilToDouble() => value.ceilToDouble();\n\n  /// Returns `this.toDouble()`.\n  double truncateToDouble() => value.truncateToDouble();\n}\n\nextension RxnIntExt on Rx<int?> {\n  /// Bit-wise and operator.\n  ///\n  /// Treating both `this` and [other] as sufficiently large two's component\n  /// integers, the result is a number with only the bits set that are set in\n  /// both `this` and [other]\n  ///\n  /// If both operands are negative, the result is negative, otherwise\n  /// the result is non-negative.\n  int? operator &(int other) {\n    if (value != null) {\n      return value! & other;\n    }\n    return null;\n  }\n\n  /// Bit-wise or operator.\n  ///\n  /// Treating both `this` and [other] as sufficiently large two's component\n  /// integers, the result is a number with the bits set that are set in either\n  /// of `this` and [other]\n  ///\n  /// If both operands are non-negative, the result is non-negative,\n  /// otherwise the result is negative.\n  int? operator |(int other) {\n    if (value != null) {\n      return value! | other;\n    }\n    return null;\n  }\n\n  /// Bit-wise exclusive-or operator.\n  ///\n  /// Treating both `this` and [other] as sufficiently large two's component\n  /// integers, the result is a number with the bits set that are set in one,\n  /// but not both, of `this` and [other]\n  ///\n  /// If the operands have the same sign, the result is non-negative,\n  /// otherwise the result is negative.\n  int? operator ^(int other) {\n    if (value != null) {\n      return value! ^ other;\n    }\n    return null;\n  }\n\n  /// The bit-wise negate operator.\n  ///\n  /// Treating `this` as a sufficiently large two's component integer,\n  /// the result is a number with the opposite bits set.\n  ///\n  /// This maps any integer `x` to `-x - 1`.\n  int? operator ~() {\n    if (value != null) {\n      return ~value!;\n    }\n    return null;\n  }\n\n  /// Shift the bits of this integer to the left by [shiftAmount].\n  ///\n  /// Shifting to the left makes the number larger, effectively multiplying\n  /// the number by `pow(2, shiftIndex)`.\n  ///\n  /// There is no limit on the size of the result. It may be relevant to\n  /// limit intermediate values by using the \"and\" operator with a suitable\n  /// mask.\n  ///\n  /// It is an error if [shiftAmount] is negative.\n  int? operator <<(int shiftAmount) {\n    if (value != null) {\n      return value! << shiftAmount;\n    }\n    return null;\n  }\n\n  /// Shift the bits of this integer to the right by [shiftAmount].\n  ///\n  /// Shifting to the right makes the number smaller and drops the least\n  /// significant bits, effectively doing an integer division by\n  ///`pow(2, shiftIndex)`.\n  ///\n  /// It is an error if [shiftAmount] is negative.\n  int? operator >>(int shiftAmount) {\n    if (value != null) {\n      return value! >> shiftAmount;\n    }\n    return null;\n  }\n\n  /// Returns this integer to the power of [exponent] modulo [modulus].\n  ///\n  /// The [exponent] must be non-negative and [modulus] must be\n  /// positive.\n  int? modPow(int exponent, int modulus) => value?.modPow(exponent, modulus);\n\n  /// Returns the modular multiplicative inverse of this integer\n  /// modulo [modulus].\n  ///\n  /// The [modulus] must be positive.\n  ///\n  /// It is an error if no modular inverse exists.\n  int? modInverse(int modulus) => value?.modInverse(modulus);\n\n  /// Returns the greatest common divisor of this integer and [other].\n  ///\n  /// If either number is non-zero, the result is the numerically greatest\n  /// integer dividing both `this` and `other`.\n  ///\n  /// The greatest common divisor is independent of the order,\n  /// so `x.gcd(y)` is  always the same as `y.gcd(x)`.\n  ///\n  /// For any integer `x`, `x.gcd(x)` is `x.abs()`.\n  ///\n  /// If both `this` and `other` is zero, the result is also zero.\n  int? gcd(int other) => value?.gcd(other);\n\n  /// Returns true if and only if this integer is even.\n  bool? get isEven => value?.isEven;\n\n  /// Returns true if and only if this integer is odd.\n  bool? get isOdd => value?.isOdd;\n\n  /// Returns the minimum number of bits required to store this integer.\n  ///\n  /// The number of bits excludes the sign bit, which gives the natural length\n  /// for non-negative (unsigned) values.  Negative values are complemented to\n  /// return the bit position of the first bit that differs from the sign bit.\n  ///\n  /// To find the number of bits needed to store the value as a signed value,\n  /// add one, i.e. use `x.bitLength + 1`.\n  /// ```\n  /// x.bitLength == (-x-1).bitLength\n  ///\n  /// 3.bitLength == 2;     // 00000011\n  /// 2.bitLength == 2;     // 00000010\n  /// 1.bitLength == 1;     // 00000001\n  /// 0.bitLength == 0;     // 00000000\n  /// (-1).bitLength == 0;  // 11111111\n  /// (-2).bitLength == 1;  // 11111110\n  /// (-3).bitLength == 2;  // 11111101\n  /// (-4).bitLength == 2;  // 11111100\n  /// ```\n  int? get bitLength => value?.bitLength;\n\n  /// Returns the least significant [width] bits of this integer as a\n  /// non-negative number (i.e. unsigned representation).  The returned value\n  /// has zeros in all bit positions higher than [width].\n  /// ```\n  /// (-1).toUnsigned(5) == 31   // 11111111  ->  00011111\n  /// ```\n  /// This operation can be used to simulate arithmetic from low level\n  /// languages.\n  /// For example, to increment an 8 bit quantity:\n  /// ```\n  /// q = (q + 1).toUnsigned(8);\n  /// ```\n  /// `q` will count from `0` up to `255` and then wrap around to `0`.\n  ///\n  /// If the input fits in [width] bits without truncation, the result is the\n  /// same as the input.  The minimum width needed to avoid truncation of `x` is\n  /// given by `x.bitLength`, i.e.\n  /// ```\n  /// x == x.toUnsigned(x.bitLength);\n  /// ```\n  int? toUnsigned(int width) => value?.toUnsigned(width);\n\n  /// Returns the least significant [width] bits of this integer, extending the\n  /// highest retained bit to the sign.  This is the same as truncating the\n  /// value to fit in [width] bits using an signed 2-s complement\n  /// representation.\n  /// The returned value has the same bit value in all positions higher than\n  /// [width].\n  ///\n  /// ```\n  ///                                V--sign bit-V\n  /// 16.toSigned(5) == -16   //  00010000 -> 11110000\n  /// 239.toSigned(5) == 15   //  11101111 -> 00001111\n  ///                                ^           ^\n  /// ```\n  /// This operation can be used to simulate arithmetic from low level\n  /// languages.\n  /// For example, to increment an 8 bit signed quantity:\n  /// ```\n  /// q = (q + 1).toSigned(8);\n  /// ```\n  /// `q` will count from `0` up to `127`, wrap to `-128` and count back up to\n  /// `127`.\n  ///\n  /// If the input value fits in [width] bits without truncation, the result is\n  /// the same as the input.  The minimum width needed to avoid truncation\n  /// of `x` is `x.bitLength + 1`, i.e.\n  /// ```\n  /// x == x.toSigned(x.bitLength + 1);\n  /// ```\n  int? toSigned(int width) => value?.toSigned(width);\n\n  /// Return the negative value of this integer.\n  ///\n  /// The result of negating an integer always has the opposite sign, except\n  /// for zero, which is its own negation.\n  int? operator -() {\n    if (value != null) {\n      return -value!;\n    }\n    return null;\n  }\n\n  /// Returns the absolute value of this integer.\n  ///\n  /// For any integer `x`, the result is the same as `x < 0 ? -x : x`.\n  int? abs() => value?.abs();\n\n  /// Returns the sign of this integer.\n  ///\n  /// Returns 0 for zero, -1 for values less than zero and\n  /// +1 for values greater than zero.\n  int? get sign => value?.sign;\n\n  /// Returns `this`.\n  int? round() => value?.round();\n\n  /// Returns `this`.\n  int? floor() => value?.floor();\n\n  /// Returns `this`.\n  int? ceil() => value?.ceil();\n\n  /// Returns `this`.\n  int? truncate() => value?.truncate();\n\n  /// Returns `this.toDouble()`.\n  double? roundToDouble() => value?.roundToDouble();\n\n  /// Returns `this.toDouble()`.\n  double? floorToDouble() => value?.floorToDouble();\n\n  /// Returns `this.toDouble()`.\n  double? ceilToDouble() => value?.ceilToDouble();\n\n  /// Returns `this.toDouble()`.\n  double? truncateToDouble() => value?.truncateToDouble();\n}\n"
  },
  {
    "path": "lib/get_rx/src/rx_types/rx_core/rx_string.dart",
    "content": "part of '../rx_types.dart';\n\nextension RxStringExt on Rx<String> {\n  String operator +(String val) => value + val;\n\n  int compareTo(String other) {\n    return value.compareTo(other);\n  }\n\n  /// Returns true if this string ends with [other]. For example:\n  ///\n  ///     'Dart'.endsWith('t'); // true\n  bool endsWith(String other) {\n    return value.endsWith(other);\n  }\n\n  /// Returns true if this string starts with a match of [pattern].\n  bool startsWith(Pattern pattern, [int index = 0]) {\n    return value.startsWith(pattern, index);\n  }\n\n  /// Returns the position of the first match of [pattern] in this string\n  int indexOf(Pattern pattern, [int start = 0]) {\n    return value.indexOf(pattern, start);\n  }\n\n  /// Returns the starting position of the last match [pattern] in this string,\n  /// searching backward starting at [start], inclusive:\n  int lastIndexOf(Pattern pattern, [int? start]) {\n    return value.lastIndexOf(pattern, start);\n  }\n\n  /// Returns true if this string is empty.\n  bool get isEmpty => value.isEmpty;\n\n  /// Returns true if this string is not empty.\n  bool get isNotEmpty => !isEmpty;\n\n  /// Returns the substring of this string that extends from [startIndex],\n  /// inclusive, to [endIndex], exclusive\n  String substring(int startIndex, [int? endIndex]) {\n    return value.substring(startIndex, endIndex);\n  }\n\n  /// Returns the string without any leading and trailing whitespace.\n  String trim() {\n    return value.trim();\n  }\n\n  /// Returns the string without any leading whitespace.\n  ///\n  /// As [trim], but only removes leading whitespace.\n  String trimLeft() {\n    return value.trimLeft();\n  }\n\n  /// Returns the string without any trailing whitespace.\n  ///\n  /// As [trim], but only removes trailing whitespace.\n  String trimRight() {\n    return value.trimRight();\n  }\n\n  /// Pads this string on the left if it is shorter than [width].\n  ///\n  /// Return a new string that prepends [padding] onto this string\n  /// one time for each position the length is less than [width].\n  String padLeft(int width, [String padding = ' ']) {\n    return value.padLeft(width, padding);\n  }\n\n  /// Pads this string on the right if it is shorter than [width].\n\n  /// Return a new string that appends [padding] after this string\n  /// one time for each position the length is less than [width].\n  String padRight(int width, [String padding = ' ']) {\n    return value.padRight(width, padding);\n  }\n\n  /// Returns true if this string contains a match of [other]:\n  bool contains(Pattern other, [int startIndex = 0]) {\n    return value.contains(other, startIndex);\n  }\n\n  /// Replaces all substrings that match [from] with [replace].\n  String replaceAll(Pattern from, String replace) {\n    return value.replaceAll(from, replace);\n  }\n\n  /// Splits the string at matches of [pattern] and returns a list\n  /// of substrings.\n  List<String> split(Pattern pattern) {\n    return value.split(pattern);\n  }\n\n  /// Returns an unmodifiable list of the UTF-16 code units of this string.\n  List<int> get codeUnits => value.codeUnits;\n\n  /// Returns an [Iterable] of Unicode code-points of this string.\n  ///\n  /// If the string contains surrogate pairs, they are combined and returned\n  /// as one integer by this iterator. Unmatched surrogate halves are treated\n  /// like valid 16-bit code-units.\n  Runes get runes => value.runes;\n\n  /// Converts all characters in this string to lower case.\n  /// If the string is already in all lower case, this method returns `this`.\n  String toLowerCase() {\n    return value.toLowerCase();\n  }\n\n  /// Converts all characters in this string to upper case.\n  /// If the string is already in all upper case, this method returns `this`.\n  String toUpperCase() {\n    return value.toUpperCase();\n  }\n\n  Iterable<Match> allMatches(String string, [int start = 0]) {\n    return value.allMatches(string, start);\n  }\n\n  Match? matchAsPrefix(String string, [int start = 0]) {\n    return value.matchAsPrefix(string, start);\n  }\n}\n\nextension RxnStringExt on Rx<String?> {\n  String operator +(String val) => (value ?? '') + val;\n\n  int? compareTo(String other) {\n    return value?.compareTo(other);\n  }\n\n  /// Returns true if this string ends with [other]. For example:\n  ///\n  ///     'Dart'.endsWith('t'); // true\n  bool? endsWith(String other) {\n    return value?.endsWith(other);\n  }\n\n  /// Returns true if this string starts with a match of [pattern].\n  bool? startsWith(Pattern pattern, [int index = 0]) {\n    return value?.startsWith(pattern, index);\n  }\n\n  /// Returns the position of the first match of [pattern] in this string\n  int? indexOf(Pattern pattern, [int start = 0]) {\n    return value?.indexOf(pattern, start);\n  }\n\n  /// Returns the starting position of the last match [pattern] in this string,\n  /// searching backward starting at [start], inclusive:\n  int? lastIndexOf(Pattern pattern, [int? start]) {\n    return value?.lastIndexOf(pattern, start);\n  }\n\n  /// Returns true if this string is empty.\n  bool? get isEmpty => value?.isEmpty;\n\n  /// Returns true if this string is not empty.\n  bool? get isNotEmpty => value?.isNotEmpty;\n\n  /// Returns the substring of this string that extends from [startIndex],\n  /// inclusive, to [endIndex], exclusive\n  String? substring(int startIndex, [int? endIndex]) {\n    return value?.substring(startIndex, endIndex);\n  }\n\n  /// Returns the string without any leading and trailing whitespace.\n  String? trim() {\n    return value?.trim();\n  }\n\n  /// Returns the string without any leading whitespace.\n  ///\n  /// As [trim], but only removes leading whitespace.\n  String? trimLeft() {\n    return value?.trimLeft();\n  }\n\n  /// Returns the string without any trailing whitespace.\n  ///\n  /// As [trim], but only removes trailing whitespace.\n  String? trimRight() {\n    return value?.trimRight();\n  }\n\n  /// Pads this string on the left if it is shorter than [width].\n  ///\n  /// Return a new string that prepends [padding] onto this string\n  /// one time for each position the length is less than [width].\n  String? padLeft(int width, [String padding = ' ']) {\n    return value?.padLeft(width, padding);\n  }\n\n  /// Pads this string on the right if it is shorter than [width].\n\n  /// Return a new string that appends [padding] after this string\n  /// one time for each position the length is less than [width].\n  String? padRight(int width, [String padding = ' ']) {\n    return value?.padRight(width, padding);\n  }\n\n  /// Returns true if this string contains a match of [other]:\n  bool? contains(Pattern other, [int startIndex = 0]) {\n    return value?.contains(other, startIndex);\n  }\n\n  /// Replaces all substrings that match [from] with [replace].\n  String? replaceAll(Pattern from, String replace) {\n    return value?.replaceAll(from, replace);\n  }\n\n  /// Splits the string at matches of [pattern] and returns a list\n  /// of substrings.\n  List<String>? split(Pattern pattern) {\n    return value?.split(pattern);\n  }\n\n  /// Returns an unmodifiable list of the UTF-16 code units of this string.\n  List<int>? get codeUnits => value?.codeUnits;\n\n  /// Returns an [Iterable] of Unicode code-points of this string.\n  ///\n  /// If the string contains surrogate pairs, they are combined and returned\n  /// as one integer by this iterator. Unmatched surrogate halves are treated\n  /// like valid 16-bit code-units.\n  Runes? get runes => value?.runes;\n\n  /// Converts all characters in this string to lower case.\n  /// If the string is already in all lower case, this method returns `this`.\n  String? toLowerCase() {\n    return value?.toLowerCase();\n  }\n\n  /// Converts all characters in this string to upper case.\n  /// If the string is already in all upper case, this method returns `this`.\n  String? toUpperCase() {\n    return value?.toUpperCase();\n  }\n\n  Iterable<Match>? allMatches(String string, [int start = 0]) {\n    return value?.allMatches(string, start);\n  }\n\n  Match? matchAsPrefix(String string, [int start = 0]) {\n    return value?.matchAsPrefix(string, start);\n  }\n}\n\n/// Rx class for `String` Type.\nclass RxString extends Rx<String> implements Comparable<String>, Pattern {\n  RxString(super.initial);\n\n  @override\n  Iterable<Match> allMatches(String string, [int start = 0]) {\n    return value.allMatches(string, start);\n  }\n\n  @override\n  Match? matchAsPrefix(String string, [int start = 0]) {\n    return value.matchAsPrefix(string, start);\n  }\n\n  @override\n  int compareTo(String other) {\n    return value.compareTo(other);\n  }\n}\n\n/// Rx class for `String` Type.\nclass RxnString extends Rx<String?> implements Comparable<String>, Pattern {\n  RxnString([super.initial]);\n\n  @override\n  Iterable<Match> allMatches(String string, [int start = 0]) {\n    return value!.allMatches(string, start);\n  }\n\n  @override\n  Match? matchAsPrefix(String string, [int start = 0]) {\n    return value!.matchAsPrefix(string, start);\n  }\n\n  @override\n  int compareTo(String other) {\n    return value!.compareTo(other);\n  }\n}\n"
  },
  {
    "path": "lib/get_rx/src/rx_types/rx_iterables/rx_list.dart",
    "content": "part of '../rx_types.dart';\n\n/// Create a list similar to `List<T>`\nclass RxList<E> extends GetListenable<List<E>>\n    with ListMixin<E>, RxObjectMixin<List<E>> {\n  RxList([super.initial = const []]);\n\n  factory RxList.filled(int length, E fill, {bool growable = false}) {\n    return RxList(List.filled(length, fill, growable: growable));\n  }\n\n  factory RxList.empty({bool growable = false}) {\n    return RxList(List.empty(growable: growable));\n  }\n\n  /// Creates a list containing all [elements].\n  factory RxList.from(Iterable elements, {bool growable = true}) {\n    return RxList(List.from(elements, growable: growable));\n  }\n\n  /// Creates a list from [elements].\n  factory RxList.of(Iterable<E> elements, {bool growable = true}) {\n    return RxList(List.of(elements, growable: growable));\n  }\n\n  /// Generates a list of values.\n  factory RxList.generate(int length, E Function(int index) generator,\n      {bool growable = true}) {\n    return RxList(List.generate(length, generator, growable: growable));\n  }\n\n  /// Creates an unmodifiable list containing all [elements].\n  factory RxList.unmodifiable(Iterable elements) {\n    return RxList(List.unmodifiable(elements));\n  }\n\n  @override\n  Iterator<E> get iterator => value.iterator;\n\n  @override\n  void operator []=(int index, E val) {\n    value[index] = val;\n    refresh();\n  }\n\n  /// Special override to push() element(s) in a reactive way\n  /// inside the List,\n  @override\n  RxList<E> operator +(Iterable<E> val) {\n    addAll(val);\n    // refresh();\n    return this;\n  }\n\n  @override\n  E operator [](int index) {\n    return value[index];\n  }\n\n  @override\n  void add(E element) {\n    value.add(element);\n    refresh();\n  }\n\n  @override\n  void addAll(Iterable<E> iterable) {\n    value.addAll(iterable);\n    refresh();\n  }\n\n  @override\n  bool remove(Object? element) {\n    final removed = value.remove(element);\n    refresh();\n    return removed;\n  }\n\n  @override\n  void removeWhere(bool Function(E element) test) {\n    value.removeWhere(test);\n    refresh();\n  }\n\n  @override\n  void retainWhere(bool Function(E element) test) {\n    value.retainWhere(test);\n    refresh();\n  }\n\n  @override\n  int get length => value.length;\n\n  // @override\n  // @protected\n  // List<E> get value {\n  //   RxInterface.proxy?.addListener(subject);\n  //   return subject.value;\n  // }\n\n  @override\n  set length(int newLength) {\n    value.length = newLength;\n    refresh();\n  }\n\n  @override\n  void insertAll(int index, Iterable<E> iterable) {\n    value.insertAll(index, iterable);\n    refresh();\n  }\n\n  @override\n  Iterable<E> get reversed => value.reversed;\n\n  // @override\n  // set value(List<E> val) {\n  //   value = val;\n  //   refresh();\n  // }\n\n  @override\n  Iterable<E> where(bool Function(E) test) {\n    return value.where(test);\n  }\n\n  @override\n  Iterable<T> whereType<T>() {\n    return value.whereType<T>();\n  }\n\n  @override\n  void sort([int Function(E a, E b)? compare]) {\n    value.sort(compare);\n    refresh();\n  }\n}\n\nextension ListExtension<E> on List<E> {\n  RxList<E> get obs => RxList<E>(this);\n\n  /// Add [item] to [List<E>] only if [item] is not null.\n  void addNonNull(E item) {\n    if (item != null) add(item);\n  }\n\n  /// Add [item] to [List<E>] only if [condition] is true.\n  void addIf(dynamic condition, E item) {\n    if (condition is Condition) condition = condition();\n    if (condition is bool && condition) add(item);\n  }\n\n  /// Adds [Iterable<E>] to [List<E>] only if [condition] is true.\n  void addAllIf(dynamic condition, Iterable<E> items) {\n    if (condition is Condition) condition = condition();\n    if (condition is bool && condition) addAll(items);\n  }\n\n  /// Replaces all existing items of this list with [item]\n  void assign(E item) {\n    // if (this is RxList) {\n    //   (this as RxList)._value;\n    // }\n\n    if (this is RxList) {\n      (this as RxList).value.clear();\n    }\n    add(item);\n  }\n\n  /// Replaces all existing items of this list with [items]\n  void assignAll(Iterable<E> items) {\n    if (this is RxList) {\n      (this as RxList).value.clear();\n    }\n    //clear();\n    addAll(items);\n  }\n}\n"
  },
  {
    "path": "lib/get_rx/src/rx_types/rx_iterables/rx_map.dart",
    "content": "part of '../rx_types.dart';\n\nclass RxMap<K, V> extends GetListenable<Map<K, V>>\n    with MapMixin<K, V>, RxObjectMixin<Map<K, V>> {\n  RxMap([super.initial = const {}]);\n\n  factory RxMap.from(Map<K, V> other) {\n    return RxMap(Map.from(other));\n  }\n\n  /// Creates a [LinkedHashMap] with the same keys and values as [other].\n  factory RxMap.of(Map<K, V> other) {\n    return RxMap(Map.of(other));\n  }\n\n  ///Creates an unmodifiable hash based map containing the entries of [other].\n  factory RxMap.unmodifiable(Map<dynamic, dynamic> other) {\n    return RxMap(Map.unmodifiable(other));\n  }\n\n  /// Creates an identity map with the default implementation, [LinkedHashMap].\n  factory RxMap.identity() {\n    return RxMap(Map.identity());\n  }\n\n  @override\n  V? operator [](Object? key) {\n    return value[key as K];\n  }\n\n  @override\n  void operator []=(K key, V value) {\n    this.value[key] = value;\n    refresh();\n  }\n\n  @override\n  void clear() {\n    value.clear();\n    refresh();\n  }\n\n  @override\n  Iterable<K> get keys => value.keys;\n\n  @override\n  V? remove(Object? key) {\n    final val = value.remove(key);\n    refresh();\n    return val;\n  }\n\n  // @override\n  // @protected\n  // Map<K, V> get value {\n  //   return subject.value;\n  //   // RxInterface.proxy?.addListener(subject);\n  //   // return _value;\n  // }\n}\n\nextension MapExtension<K, V> on Map<K, V> {\n  RxMap<K, V> get obs {\n    return RxMap<K, V>(this);\n  }\n\n  void addIf(dynamic condition, K key, V value) {\n    if (condition is Condition) condition = condition();\n    if (condition is bool && condition) {\n      this[key] = value;\n    }\n  }\n\n  void addAllIf(dynamic condition, Map<K, V> values) {\n    if (condition is Condition) condition = condition();\n    if (condition is bool && condition) addAll(values);\n  }\n\n  void assign(K key, V val) {\n    if (this is RxMap) {\n      final map = (this as RxMap);\n      // map._value;\n      map.value.clear();\n      this[key] = val;\n    } else {\n      clear();\n      this[key] = val;\n    }\n  }\n\n  void assignAll(Map<K, V> val) {\n    if (val is RxMap && this is RxMap) {\n      if ((val as RxMap).value == (this as RxMap).value) return;\n    }\n    if (this is RxMap) {\n      final map = (this as RxMap);\n      if (map.value == val) return;\n      map.value = val;\n      // ignore: invalid_use_of_protected_member\n      map.refresh();\n    } else {\n      if (this == val) return;\n      clear();\n      addAll(val);\n    }\n  }\n}\n"
  },
  {
    "path": "lib/get_rx/src/rx_types/rx_iterables/rx_set.dart",
    "content": "part of '../rx_types.dart';\n\nclass RxSet<E> extends GetListenable<Set<E>>\n    with SetMixin<E>, RxObjectMixin<Set<E>> {\n  RxSet([super.initial = const {}]);\n\n  /// Special override to push() element(s) in a reactive way\n  /// inside the List,\n  RxSet<E> operator +(Set<E> val) {\n    addAll(val);\n    //refresh();\n    return this;\n  }\n\n  void update(void Function(Iterable<E>? value) fn) {\n    fn(value);\n    refresh();\n  }\n\n  // @override\n  // @protected\n  // Set<E> get value {\n  //   return subject.value;\n  //   // RxInterface.proxy?.addListener(subject);\n  //   // return _value;\n  // }\n\n  // @override\n  // @protected\n  // set value(Set<E> val) {\n  //   if (value == val) return;\n  //   value = val;\n  //   refresh();\n  // }\n\n  @override\n  bool add(E value) {\n    final hasAdded = this.value.add(value);\n    if (hasAdded) {\n      refresh();\n    }\n    return hasAdded;\n  }\n\n  @override\n  bool contains(Object? element) {\n    return value.contains(element);\n  }\n\n  @override\n  Iterator<E> get iterator => value.iterator;\n\n  @override\n  int get length => value.length;\n\n  @override\n  E? lookup(Object? element) {\n    return value.lookup(element);\n  }\n\n  @override\n  bool remove(Object? value) {\n    var hasRemoved = this.value.remove(value);\n    if (hasRemoved) {\n      refresh();\n    }\n    return hasRemoved;\n  }\n\n  @override\n  Set<E> toSet() {\n    return value.toSet();\n  }\n\n  @override\n  void addAll(Iterable<E> elements) {\n    value.addAll(elements);\n    refresh();\n  }\n\n  @override\n  void clear() {\n    value.clear();\n    refresh();\n  }\n\n  @override\n  void removeAll(Iterable<Object?> elements) {\n    value.removeAll(elements);\n    refresh();\n  }\n\n  @override\n  void retainAll(Iterable<Object?> elements) {\n    value.retainAll(elements);\n    refresh();\n  }\n\n  @override\n  void retainWhere(bool Function(E) test) {\n    value.retainWhere(test);\n    refresh();\n  }\n}\n\nextension SetExtension<E> on Set<E> {\n  RxSet<E> get obs {\n    return RxSet<E>(<E>{})..addAll(this);\n  }\n\n  // /// Add [item] to [List<E>] only if [item] is not null.\n  // void addNonNull(E item) {\n  //   if (item != null) add(item);\n  // }\n\n  // /// Add [Iterable<E>] to [List<E>] only if [Iterable<E>] is not null.\n  // void addAllNonNull(Iterable<E> item) {\n  //   if (item != null) addAll(item);\n  // }\n\n  /// Add [item] to [List<E>] only if [condition] is true.\n  void addIf(dynamic condition, E item) {\n    if (condition is Condition) condition = condition();\n    if (condition is bool && condition) add(item);\n  }\n\n  /// Adds [Iterable<E>] to [List<E>] only if [condition] is true.\n  void addAllIf(dynamic condition, Iterable<E> items) {\n    if (condition is Condition) condition = condition();\n    if (condition is bool && condition) addAll(items);\n  }\n\n  /// Replaces all existing items of this list with [item]\n  void assign(E item) {\n    // if (this is RxSet) {\n    //   (this as RxSet)._value;\n    // }\n\n    clear();\n    add(item);\n  }\n\n  /// Replaces all existing items of this list with [items]\n  void assignAll(Iterable<E> items) {\n    // if (this is RxSet) {\n    //   (this as RxSet)._value;\n    // }\n    clear();\n    addAll(items);\n  }\n}\n"
  },
  {
    "path": "lib/get_rx/src/rx_types/rx_types.dart",
    "content": "library;\n\nimport 'dart:async';\nimport 'dart:collection';\n\nimport 'package:flutter/foundation.dart';\n\nimport '../../../get_state_manager/src/rx_flutter/rx_notifier.dart';\nimport '../rx_typedefs/rx_typedefs.dart';\n\npart 'rx_core/rx_impl.dart';\npart 'rx_core/rx_interface.dart';\npart 'rx_core/rx_num.dart';\npart 'rx_core/rx_string.dart';\npart 'rx_iterables/rx_list.dart';\npart 'rx_iterables/rx_map.dart';\npart 'rx_iterables/rx_set.dart';\n"
  },
  {
    "path": "lib/get_rx/src/rx_workers/rx_workers.dart",
    "content": "import 'dart:async';\n\nimport '../../../get_core/get_core.dart';\nimport '../../../get_state_manager/src/rx_flutter/rx_notifier.dart';\nimport '../rx_types/rx_types.dart';\nimport 'utils/debouncer.dart';\n\nbool _conditional(dynamic condition) {\n  if (condition == null) return true;\n  if (condition is bool) return condition;\n  if (condition is bool Function()) return condition();\n  return true;\n}\n\ntypedef WorkerCallback<T> = Function(T callback);\n\nclass Workers {\n  Workers(this.workers);\n  final List<Worker> workers;\n\n  void dispose() {\n    for (final worker in workers) {\n      if (!worker._disposed) {\n        worker.dispose();\n      }\n    }\n  }\n}\n\n///\n/// Called every time [listener] changes. As long as the [condition]\n/// returns true.\n///\n/// Sample:\n/// Every time increment() is called, ever() will process the [condition]\n/// (can be a [bool] expression or a `bool Function()`), and only call\n/// the callback when [condition] is true.\n/// In our case, only when count is bigger to 5. In order to \"dispose\"\n/// this Worker\n/// that will run forever, we made a `worker` variable. So, when the count value\n/// reaches 10, the worker gets disposed, and releases any memory resources.\n///\n/// ```\n/// // imagine some counter widget...\n///\n/// class _CountController extends GetxController {\n///   final count = 0.obs;\n///   Worker worker;\n///\n///   void onInit() {\n///     worker = ever(count, (value) {\n///       print('counter changed to: $value');\n///       if (value == 10) worker.dispose();\n///     }, condition: () => count > 5);\n///   }\n///\n///   void increment() => count + 1;\n/// }\n/// ```\nWorker ever<T>(\n  GetListenable<T> listener,\n  WorkerCallback<T> callback, {\n  dynamic condition = true,\n  Function? onError,\n  void Function()? onDone,\n  bool? cancelOnError,\n}) {\n  StreamSubscription sub = listener.listen(\n    (event) {\n      if (_conditional(condition)) callback(event);\n    },\n    onError: onError,\n    onDone: onDone,\n    cancelOnError: cancelOnError,\n  );\n  return Worker(sub.cancel, '[ever]');\n}\n\n/// Similar to [ever], but takes a list of [listeners], the condition\n/// for the [callback] is common to all [listeners],\n/// and the [callback] is executed to each one of them. The [Worker] is\n/// common to all, so `worker.dispose()` will cancel all streams.\nWorker everAll(\n  List<RxInterface> listeners,\n  WorkerCallback callback, {\n  dynamic condition = true,\n  Function? onError,\n  void Function()? onDone,\n  bool? cancelOnError,\n}) {\n  final evers = <StreamSubscription>[];\n  for (var i in listeners) {\n    final sub = i.listen(\n      (event) {\n        if (_conditional(condition)) callback(event);\n      },\n      onError: onError,\n      onDone: onDone,\n      cancelOnError: cancelOnError,\n    );\n    evers.add(sub);\n  }\n\n  Future<void> cancel() async {\n    for (var i in evers) {\n      i.cancel();\n    }\n  }\n\n  return Worker(cancel, '[everAll]');\n}\n\n/// `once()` will execute only 1 time when [condition] is met and cancel\n/// the subscription to the [listener] stream right after that.\n/// [condition] defines when [callback] is called, and\n/// can be a [bool] or a `bool Function()`.\n///\n/// Sample:\n/// ```\n///  class _CountController extends GetxController {\n///   final count = 0.obs;\n///   Worker worker;\n///\n///   @override\n///   Future<void> onInit() async {\n///     worker = once(count, (value) {\n///       print(\"counter reached $value before 3 seconds.\");\n///     }, condition: () => count() > 2);\n///     3.delay(worker.dispose);\n///   }\n///   void increment() => count + 1;\n/// }\n///```\nWorker once<T>(\n  GetListenable<T> listener,\n  WorkerCallback<T> callback, {\n  dynamic condition = true,\n  Function? onError,\n  void Function()? onDone,\n  bool? cancelOnError,\n}) {\n  late Worker ref;\n  StreamSubscription? sub;\n  sub = listener.listen(\n    (event) {\n      if (!_conditional(condition)) return;\n      ref._disposed = true;\n      ref._log('called');\n      sub?.cancel();\n      callback(event);\n    },\n    onError: onError,\n    onDone: onDone,\n    cancelOnError: cancelOnError,\n  );\n  ref = Worker(sub.cancel, '[once]');\n  return ref;\n}\n\n/// Ignore all changes in [listener] during [time] (1 sec by default) or until\n/// [condition] is met (can be a [bool] expression or a `bool Function()`),\n/// It brings the 1st \"value\" since the period of time, so\n/// if you click a counter button 3 times in 1 sec, it will show you \"1\"\n/// (after 1 sec of the first press)\n/// click counter 3 times in 1 sec, it will show you \"4\" (after 1 sec)\n/// click counter 2 times in 1 sec, it will show you \"7\" (after 1 sec).\n///\n/// Sample:\n/// // wait 1 sec each time an event starts, only if counter is lower than 20.\n/// worker = interval(\n///    count,\n///    (value) => print(value),\n///    time: 1.seconds,\n///    condition: () => count < 20,\n/// );\n/// ```\nWorker interval<T>(\n  GetListenable<T> listener,\n  WorkerCallback<T> callback, {\n  Duration time = const Duration(seconds: 1),\n  dynamic condition = true,\n  Function? onError,\n  void Function()? onDone,\n  bool? cancelOnError,\n}) {\n  var debounceActive = false;\n  StreamSubscription sub = listener.listen(\n    (event) async {\n      if (debounceActive || !_conditional(condition)) return;\n      debounceActive = true;\n      await Future.delayed(time);\n      debounceActive = false;\n      callback(event);\n    },\n    onError: onError,\n    onDone: onDone,\n    cancelOnError: cancelOnError,\n  );\n  return Worker(sub.cancel, '[interval]');\n}\n\n/// [debounce] is similar to [interval], but sends the last value.\n/// Useful for Anti DDos, every time the user stops typing for 1 second,\n/// for instance.\n/// When [listener] emits the last \"value\", when [time] hits,\n/// it calls [callback] with the last \"value\" emitted.\n///\n/// Sample:\n///\n/// ```\n/// worker = debounce(\n///      count,\n///      (value) {\n///        print(value);\n///        if( value > 20 ) worker.dispose();\n///      },\n///      time: 1.seconds,\n///    );\n///  }\n///  ```\nWorker debounce<T>(\n  GetListenable<T> listener,\n  WorkerCallback<T> callback, {\n  Duration? time,\n  Function? onError,\n  void Function()? onDone,\n  bool? cancelOnError,\n}) {\n  final newDebouncer =\n      Debouncer(delay: time ?? const Duration(milliseconds: 800));\n  StreamSubscription sub = listener.listen(\n    (event) {\n      newDebouncer(() {\n        callback(event);\n      });\n    },\n    onError: onError,\n    onDone: onDone,\n    cancelOnError: cancelOnError,\n  );\n  return Worker(sub.cancel, '[debounce]');\n}\n\nclass Worker {\n  Worker(this.worker, this.type);\n\n  /// subscription.cancel() callback\n  final Future<void> Function() worker;\n\n  /// type of worker (debounce, interval, ever)..\n  final String type;\n  bool _disposed = false;\n\n  bool get disposed => _disposed;\n\n  //final bool _verbose = true;\n  void _log(String msg) {\n    //  if (!_verbose) return;\n    Get.log('$runtimeType $type $msg');\n  }\n\n  void dispose() {\n    if (_disposed) {\n      _log('already disposed');\n      return;\n    }\n    _disposed = true;\n    worker();\n    _log('disposed');\n  }\n\n  void call() => dispose();\n}\n"
  },
  {
    "path": "lib/get_rx/src/rx_workers/utils/debouncer.dart",
    "content": "import 'dart:async';\n\n/// This \"function\" class is the implementation of `debouncer()` Worker.\n/// It calls the function passed after specified [delay] parameter.\n/// Example:\n/// ```\n/// final delayed = Debouncer( delay: Duration( seconds: 1 )) ;\n/// print( 'the next function will be called after 1 sec' );\n/// delayed( () => print( 'called after 1 sec' ));\n/// ```\nclass Debouncer {\n  final Duration delay;\n  Timer? _timer;\n\n  Debouncer({required this.delay});\n\n  void call(void Function() action) {\n    _timer?.cancel();\n    _timer = Timer(delay, action);\n  }\n\n  /// Notifies if the delayed call is active.\n  bool get isRunning => _timer?.isActive ?? false;\n\n  /// Cancel the current delayed call.\n  void cancel() => _timer?.cancel();\n}\n"
  },
  {
    "path": "lib/get_state_manager/get_state_manager.dart",
    "content": "library;\n\nexport 'src/rx_flutter/rx_getx_widget.dart';\nexport 'src/rx_flutter/rx_notifier.dart';\nexport 'src/rx_flutter/rx_obx_widget.dart';\nexport 'src/rx_flutter/rx_ticket_provider_mixin.dart';\nexport 'src/simple/get_controllers.dart';\nexport 'src/simple/get_responsive.dart';\nexport 'src/simple/get_state.dart';\nexport 'src/simple/get_view.dart';\nexport 'src/simple/simple_builder.dart';\n"
  },
  {
    "path": "lib/get_state_manager/src/rx_flutter/rx_getx_widget.dart",
    "content": "import 'package:flutter/foundation.dart';\nimport 'package:flutter/widgets.dart';\n\nimport '../../../get_core/get_core.dart';\nimport '../../../get_instance/src/extension_instance.dart';\nimport '../../../get_instance/src/lifecycle.dart';\nimport '../simple/list_notifier.dart';\n\ntypedef GetXControllerBuilder<T extends GetLifeCycleMixin> = Widget Function(\n    T controller);\n\nclass GetX<T extends GetLifeCycleMixin> extends StatefulWidget {\n  final GetXControllerBuilder<T> builder;\n  final bool global;\n  final bool autoRemove;\n  final bool assignId;\n  final void Function(GetXState<T> state)? initState,\n      dispose,\n      didChangeDependencies;\n  final void Function(GetX oldWidget, GetXState<T> state)? didUpdateWidget;\n  final T? init;\n  final String? tag;\n\n  const GetX({\n    super.key,\n    this.tag,\n    required this.builder,\n    this.global = true,\n    this.autoRemove = true,\n    this.initState,\n    this.assignId = false,\n    //  this.stream,\n    this.dispose,\n    this.didChangeDependencies,\n    this.didUpdateWidget,\n    this.init,\n    // this.streamController\n  });\n\n  @override\n  StatefulElement createElement() => StatefulElement(this);\n\n  @override\n  void debugFillProperties(DiagnosticPropertiesBuilder properties) {\n    super.debugFillProperties(properties);\n    properties\n      ..add(\n        DiagnosticsProperty<T>('controller', init),\n      )\n      ..add(DiagnosticsProperty<String>('tag', tag))\n      ..add(\n          ObjectFlagProperty<GetXControllerBuilder<T>>.has('builder', builder));\n  }\n\n  @override\n  GetXState<T> createState() => GetXState<T>();\n}\n\nclass GetXState<T extends GetLifeCycleMixin> extends State<GetX<T>> {\n  T? controller;\n  bool? _isCreator = false;\n\n  @override\n  void initState() {\n    // var isPrepared = Get.isPrepared<T>(tag: widget.tag);\n    final isRegistered = Get.isRegistered<T>(tag: widget.tag);\n\n    if (widget.global) {\n      if (isRegistered) {\n        _isCreator = Get.isPrepared<T>(tag: widget.tag);\n        controller = Get.find<T>(tag: widget.tag);\n      } else {\n        controller = widget.init;\n        _isCreator = true;\n        Get.put<T>(controller!, tag: widget.tag);\n      }\n    } else {\n      controller = widget.init;\n      _isCreator = true;\n      controller?.onStart();\n    }\n    widget.initState?.call(this);\n    if (widget.global && Get.smartManagement == SmartManagement.onlyBuilder) {\n      controller?.onStart();\n    }\n\n    super.initState();\n  }\n\n  @override\n  void didChangeDependencies() {\n    super.didChangeDependencies();\n    if (widget.didChangeDependencies != null) {\n      widget.didChangeDependencies!(this);\n    }\n  }\n\n  @override\n  void didUpdateWidget(GetX oldWidget) {\n    super.didUpdateWidget(oldWidget as GetX<T>);\n    widget.didUpdateWidget?.call(oldWidget, this);\n  }\n\n  @override\n  void dispose() {\n    if (widget.dispose != null) widget.dispose!(this);\n    if (_isCreator! || widget.assignId) {\n      if (widget.autoRemove && Get.isRegistered<T>(tag: widget.tag)) {\n        Get.delete<T>(tag: widget.tag);\n      }\n    }\n\n    for (final disposer in disposers) {\n      disposer();\n    }\n\n    disposers.clear();\n\n    controller = null;\n    _isCreator = null;\n    super.dispose();\n  }\n\n  void _update() {\n    if (mounted) {\n      setState(() {});\n    }\n  }\n\n  final disposers = <Disposer>[];\n\n  @override\n  Widget build(BuildContext context) => Notifier.instance.append(\n      NotifyData(disposers: disposers, updater: _update),\n      () => widget.builder(controller!));\n\n  @override\n  void debugFillProperties(DiagnosticPropertiesBuilder properties) {\n    super.debugFillProperties(properties);\n    properties.add(DiagnosticsProperty<T>('controller', controller));\n  }\n}\n"
  },
  {
    "path": "lib/get_state_manager/src/rx_flutter/rx_notifier.dart",
    "content": "import 'dart:async';\n\nimport 'package:flutter/foundation.dart';\nimport 'package:flutter/material.dart';\nimport 'package:get/utils.dart';\n\nimport '../../../get_rx/src/rx_types/rx_types.dart';\nimport '../../../instance_manager.dart';\nimport '../../get_state_manager.dart';\nimport '../simple/list_notifier.dart';\n\nextension _Empty on Object {\n  bool _isEmpty() {\n    final val = this;\n    // if (val == null) return true;\n    var result = false;\n    if (val is Iterable) {\n      result = val.isEmpty;\n    } else if (val is String) {\n      result = val.trim().isEmpty;\n    } else if (val is Map) {\n      result = val.isEmpty;\n    }\n    return result;\n  }\n}\n\nmixin StateMixin<T> on ListNotifier {\n  T? _value;\n  GetStatus<T>? _status;\n\n  void _fillInitialStatus() {\n    _status = (_value == null || _value!._isEmpty())\n        ? GetStatus<T>.loading()\n        : GetStatus<T>.success(_value as T);\n  }\n\n  GetStatus<T> get status {\n    reportRead();\n    return _status ??= _status = GetStatus.loading();\n  }\n\n  T get state => value;\n\n  set status(GetStatus<T> newStatus) {\n    if (newStatus == status) return;\n    _status = newStatus;\n    if (newStatus is SuccessStatus<T>) {\n      _value = newStatus.data;\n    }\n    refresh();\n  }\n\n  @protected\n  T get value {\n    reportRead();\n    return _value as T;\n  }\n\n  @protected\n  set value(T newValue) {\n    if (_value == newValue) return;\n    _value = newValue;\n    refresh();\n  }\n\n  @protected\n  void change(GetStatus<T> status) {\n    if (status != this.status) {\n      this.status = status;\n    }\n  }\n\n  void setSuccess(T data) {\n    change(GetStatus<T>.success(data));\n  }\n\n  void setError(Object error) {\n    change(GetStatus<T>.error(error));\n  }\n\n  void setLoading() {\n    change(GetStatus<T>.loading());\n  }\n\n  void setEmpty() {\n    change(GetStatus<T>.empty());\n  }\n\n  void futurize(Future<T> Function() body,\n      {T? initialData, String? errorMessage, bool useEmpty = true}) {\n    final compute = body;\n    _value ??= initialData;\n    status = GetStatus<T>.loading();\n    compute().then((newValue) {\n      if ((newValue == null || newValue._isEmpty()) && useEmpty) {\n        status = GetStatus<T>.empty();\n      } else {\n        status = GetStatus<T>.success(newValue);\n      }\n\n      refresh();\n    }, onError: (err) {\n      status = GetStatus.error(\n          err is Exception ? err : Exception(errorMessage ?? err.toString()));\n      refresh();\n    });\n  }\n}\n\ntypedef FuturizeCallback<T> = Future<T> Function(VoidCallback fn);\n\ntypedef VoidCallback = void Function();\n\nclass GetListenable<T> extends ListNotifierSingle implements RxInterface<T> {\n  GetListenable(T val) : _value = val;\n\n  StreamController<T>? _controller;\n\n  StreamController<T> get subject {\n    if (_controller == null) {\n      _controller =\n          StreamController<T>.broadcast(onCancel: addListener(_streamListener));\n      _controller?.add(_value);\n\n      ///TODO: report to controller dispose\n    }\n    return _controller!;\n  }\n\n  void _streamListener() {\n    _controller?.add(_value);\n  }\n\n  @override\n  @mustCallSuper\n  void close() {\n    removeListener(_streamListener);\n    _controller?.close();\n    dispose();\n  }\n\n  Stream<T> get stream {\n    return subject.stream;\n  }\n\n  T _value;\n\n  @override\n  T get value {\n    reportRead();\n    return _value;\n  }\n\n  void _notify() {\n    refresh();\n  }\n\n  set value(T newValue) {\n    if (_value == newValue) return;\n    _value = newValue;\n    _notify();\n  }\n\n  T? call([T? v]) {\n    if (v != null) {\n      value = v;\n    }\n    return value;\n  }\n\n  @override\n  StreamSubscription<T> listen(\n    void Function(T)? onData, {\n    Function? onError,\n    void Function()? onDone,\n    bool? cancelOnError,\n  }) =>\n      stream.listen(\n        onData,\n        onError: onError,\n        onDone: onDone,\n        cancelOnError: cancelOnError ?? false,\n      );\n\n  @override\n  String toString() => value.toString();\n}\n\nclass Value<T> extends ListNotifier\n    with StateMixin<T>\n    implements ValueListenable<T?> {\n  Value(T val) {\n    _value = val;\n    _fillInitialStatus();\n  }\n\n  @override\n  T get value {\n    reportRead();\n    return _value as T;\n  }\n\n  @override\n  set value(T newValue) {\n    if (_value == newValue) return;\n    _value = newValue;\n    refresh();\n  }\n\n  T? call([T? v]) {\n    if (v != null) {\n      value = v;\n    }\n    return value;\n  }\n\n  void update(T Function(T? value) fn) {\n    value = fn(value);\n    // refresh();\n  }\n\n  @override\n  String toString() => value.toString();\n\n  dynamic toJson() => (value as dynamic)?.toJson();\n}\n\n/// GetNotifier has a native status and state implementation, with the\n/// Get Lifecycle\nabstract class GetNotifier<T> extends Value<T> with GetLifeCycleMixin {\n  GetNotifier(super.initial);\n}\n\nextension StateExt<T> on StateMixin<T> {\n  Widget obx(\n    NotifierBuilder<T> widget, {\n    Widget Function(String? error)? onError,\n    Widget? onLoading,\n    Widget? onEmpty,\n    WidgetBuilder? onCustom,\n  }) {\n    return Observer(builder: (context) {\n      if (status.isLoading) {\n        return onLoading ?? const Center(child: CircularProgressIndicator());\n      } else if (status.isError) {\n        return onError != null\n            ? onError(status.errorMessage)\n            : Center(child: Text('A error occurred: ${status.errorMessage}'));\n      } else if (status.isEmpty) {\n        return onEmpty ??\n            const SizedBox.shrink(); // Also can be widget(null); but is risky\n      } else if (status.isSuccess) {\n        return widget(value);\n      } else if (status.isCustom) {\n        return onCustom?.call(context) ??\n            const SizedBox.shrink(); // Also can be widget(null); but is risky\n      }\n      return widget(value);\n    });\n  }\n}\n\ntypedef NotifierBuilder<T> = Widget Function(T state);\n\nabstract class GetStatus<T> with Equality {\n  const GetStatus();\n\n  factory GetStatus.loading() => LoadingStatus<T>();\n\n  factory GetStatus.error(Object message) => ErrorStatus<T, Object>(message);\n\n  factory GetStatus.empty() => EmptyStatus<T>();\n\n  factory GetStatus.success(T data) => SuccessStatus<T>(data);\n\n  factory GetStatus.custom() => CustomStatus<T>();\n}\n\nclass CustomStatus<T> extends GetStatus<T> {\n  @override\n  List get props => [];\n}\n\nclass LoadingStatus<T> extends GetStatus<T> {\n  @override\n  List get props => [];\n}\n\nclass SuccessStatus<T> extends GetStatus<T> {\n  final T data;\n\n  const SuccessStatus(this.data);\n\n  @override\n  List get props => [data];\n}\n\nclass ErrorStatus<T, S> extends GetStatus<T> {\n  final S? error;\n\n  const ErrorStatus([this.error]);\n\n  @override\n  List get props => [error];\n}\n\nclass EmptyStatus<T> extends GetStatus<T> {\n  @override\n  List get props => [];\n}\n\nextension StatusDataExt<T> on GetStatus<T> {\n  bool get isLoading => this is LoadingStatus;\n\n  bool get isSuccess => this is SuccessStatus;\n\n  bool get isError => this is ErrorStatus;\n\n  bool get isEmpty => this is EmptyStatus;\n\n  bool get isCustom => !isLoading && !isSuccess && !isError && !isEmpty;\n\n  dynamic get error {\n    if (this is ErrorStatus) {\n      return (this as ErrorStatus).error;\n    }\n    return null;\n  }\n\n  String get errorMessage {\n    final isError = this is ErrorStatus;\n    if (isError) {\n      final err = this as ErrorStatus;\n      if (err.error != null) {\n        if (err.error is String) {\n          return err.error as String;\n        }\n        return err.error.toString();\n      }\n    }\n\n    return '';\n  }\n\n  T? get data {\n    if (this is SuccessStatus<T>) {\n      final success = this as SuccessStatus<T>;\n      return success.data;\n    }\n    return null;\n  }\n}\n"
  },
  {
    "path": "lib/get_state_manager/src/rx_flutter/rx_obx_widget.dart",
    "content": "import 'package:flutter/widgets.dart';\n\nimport '../../../get_rx/src/rx_types/rx_types.dart';\nimport '../simple/simple_builder.dart';\n\ntypedef WidgetCallback = Widget Function();\n\n/// The [ObxWidget] is the base for all GetX reactive widgets\n///\n/// See also:\n/// - [Obx]\n/// - [ObxValue]\nabstract class ObxWidget extends ObxStatelessWidget {\n  const ObxWidget({super.key});\n}\n\n/// The simplest reactive widget in GetX.\n///\n/// Just pass your Rx variable in the root scope of the callback to have it\n/// automatically registered for changes.\n///\n/// final _name = \"GetX\".obs;\n/// Obx(() => Text( _name.value )),... ;\nclass Obx extends ObxWidget {\n  final WidgetCallback builder;\n\n  const Obx(this.builder, {super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return builder();\n  }\n}\n\n/// Similar to Obx, but manages a local state.\n/// Pass the initial data in constructor.\n/// Useful for simple local states, like toggles, visibility, themes,\n/// button states, etc.\n///  Sample:\n///    ObxValue((data) => Switch(\n///      value: data.value,\n///      onChanged: (flag) => data.value = flag,\n///    ),\n///    false.obs,\n///   ),\nclass ObxValue<T extends RxInterface> extends ObxWidget {\n  final Widget Function(T) builder;\n  final T data;\n\n  const ObxValue(this.builder, this.data, {super.key});\n\n  @override\n  Widget build(BuildContext context) => builder(data);\n}\n"
  },
  {
    "path": "lib/get_state_manager/src/rx_flutter/rx_ticket_provider_mixin.dart",
    "content": "// ignore_for_file: lines_longer_than_80_chars\n\nimport 'package:flutter/foundation.dart';\nimport 'package:flutter/material.dart';\nimport 'package:flutter/scheduler.dart';\n\nimport '../../../get_instance/src/lifecycle.dart';\nimport '../../get_state_manager.dart';\n\n/// Used like `SingleTickerProviderMixin` but only with Get Controllers.\n/// Simplifies AnimationController creation inside GetxController.\n///\n/// Example:\n///```\n///class SplashController extends GetxController with\n///    GetSingleTickerProviderStateMixin {\n///  AnimationController controller;\n///\n///  @override\n///  void onInit() {\n///    final duration = const Duration(seconds: 2);\n///    controller =\n///        AnimationController.unbounded(duration: duration, vsync: this);\n///    controller.repeat();\n///    controller.addListener(() =>\n///        print(\"Animation Controller value: ${controller.value}\"));\n///  }\n///  ...\n/// ```\nmixin GetSingleTickerProviderStateMixin on GetxController\n    implements TickerProvider {\n  Ticker? _ticker;\n\n  @override\n  Ticker createTicker(TickerCallback onTick) {\n    assert(() {\n      if (_ticker == null) return true;\n      throw FlutterError.fromParts(<DiagnosticsNode>[\n        ErrorSummary(\n            '$runtimeType is a GetSingleTickerProviderStateMixin but multiple tickers were created.'),\n        ErrorDescription(\n            'A GetSingleTickerProviderStateMixin can only be used as a TickerProvider once.'),\n        ErrorHint(\n          'If a State is used for multiple AnimationController objects, or if it is passed to other '\n          'objects and those objects might use it more than one time in total, then instead of '\n          'mixing in a GetSingleTickerProviderStateMixin, use a regular GetTickerProviderStateMixin.',\n        ),\n      ]);\n    }());\n    _ticker =\n        Ticker(onTick, debugLabel: kDebugMode ? 'created by $this' : null);\n    // We assume that this is called from initState, build, or some sort of\n    // event handler, and that thus TickerMode.of(context) would return true. We\n    // can't actually check that here because if we're in initState then we're\n    // not allowed to do inheritance checks yet.\n    return _ticker!;\n  }\n\n  void didChangeDependencies(BuildContext context) {\n    if (_ticker != null) _ticker!.muted = !TickerMode.of(context);\n  }\n\n  @override\n  void onClose() {\n    assert(() {\n      if (_ticker == null || !_ticker!.isActive) return true;\n      throw FlutterError.fromParts(<DiagnosticsNode>[\n        ErrorSummary('$this was disposed with an active Ticker.'),\n        ErrorDescription(\n          '$runtimeType created a Ticker via its GetSingleTickerProviderStateMixin, but at the time '\n          'dispose() was called on the mixin, that Ticker was still active. The Ticker must '\n          'be disposed before calling super.dispose().',\n        ),\n        ErrorHint(\n          'Tickers used by AnimationControllers '\n          'should be disposed by calling dispose() on the AnimationController itself. '\n          'Otherwise, the ticker will leak.',\n        ),\n        _ticker!.describeForError('The offending ticker was'),\n      ]);\n    }());\n    super.onClose();\n  }\n}\n\n/// Used like `TickerProviderMixin` but only with Get Controllers.\n/// Simplifies multiple AnimationController creation inside GetxController.\n///\n/// Example:\n///```\n///class SplashController extends GetxController with\n///    GetTickerProviderStateMixin {\n///  AnimationController first_controller;\n///  AnimationController second_controller;\n///\n///  @override\n///  void onInit() {\n///    final duration = const Duration(seconds: 2);\n///    first_controller =\n///        AnimationController.unbounded(duration: duration, vsync: this);\n///    second_controller =\n///        AnimationController.unbounded(duration: duration, vsync: this);\n///    first_controller.repeat();\n///    first_controller.addListener(() =>\n///        print(\"Animation Controller value: ${first_controller.value}\"));\n///    second_controller.addListener(() =>\n///        print(\"Animation Controller value: ${second_controller.value}\"));\n///  }\n///  ...\n/// ```\nmixin GetTickerProviderStateMixin on GetxController implements TickerProvider {\n  Set<Ticker>? _tickers;\n\n  @override\n  Ticker createTicker(TickerCallback onTick) {\n    _tickers ??= <_WidgetTicker>{};\n    final result = _WidgetTicker(onTick, this,\n        debugLabel: kDebugMode ? 'created by ${describeIdentity(this)}' : null);\n    _tickers!.add(result);\n    return result;\n  }\n\n  void _removeTicker(_WidgetTicker ticker) {\n    assert(_tickers != null);\n    assert(_tickers!.contains(ticker));\n    _tickers!.remove(ticker);\n  }\n\n  void didChangeDependencies(BuildContext context) {\n    final muted = !TickerMode.of(context);\n    if (_tickers != null) {\n      for (final ticker in _tickers!) {\n        ticker.muted = muted;\n      }\n    }\n  }\n\n  @override\n  void onClose() {\n    assert(() {\n      if (_tickers != null) {\n        for (final ticker in _tickers!) {\n          if (ticker.isActive) {\n            throw FlutterError.fromParts(<DiagnosticsNode>[\n              ErrorSummary('$this was disposed with an active Ticker.'),\n              ErrorDescription(\n                '$runtimeType created a Ticker via its GetTickerProviderStateMixin, but at the time '\n                'dispose() was called on the mixin, that Ticker was still active. All Tickers must '\n                'be disposed before calling super.dispose().',\n              ),\n              ErrorHint(\n                'Tickers used by AnimationControllers '\n                'should be disposed by calling dispose() on the AnimationController itself. '\n                'Otherwise, the ticker will leak.',\n              ),\n              ticker.describeForError('The offending ticker was'),\n            ]);\n          }\n        }\n      }\n      return true;\n    }());\n    super.onClose();\n  }\n}\n\nclass _WidgetTicker extends Ticker {\n  _WidgetTicker(super.onTick, this._creator, {super.debugLabel});\n\n  final GetTickerProviderStateMixin _creator;\n\n  @override\n  void dispose() {\n    _creator._removeTicker(this);\n    super.dispose();\n  }\n}\n\n@Deprecated('use GetSingleTickerProviderStateMixin')\n\n/// Used like `SingleTickerProviderMixin` but only with Get Controllers.\n/// Simplifies AnimationController creation inside GetxController.\n///\n/// Example:\n///```\n///class SplashController extends GetxController with\n///    SingleGetTickerProviderMixin {\n///  AnimationController _ac;\n///\n///  @override\n///  void onInit() {\n///    final dur = const Duration(seconds: 2);\n///    _ac = AnimationController.unbounded(duration: dur, vsync: this);\n///    _ac.repeat();\n///    _ac.addListener(() => print(\"Animation Controller value: ${_ac.value}\"));\n///  }\n///  ...\n/// ```\nmixin SingleGetTickerProviderMixin on GetLifeCycleMixin\n    implements TickerProvider {\n  @override\n  Ticker createTicker(TickerCallback onTick) => Ticker(onTick);\n}\n"
  },
  {
    "path": "lib/get_state_manager/src/simple/get_controllers.dart",
    "content": "// ignore: prefer_mixin\nimport 'package:flutter/widgets.dart';\n\nimport '../../../instance_manager.dart';\nimport '../rx_flutter/rx_notifier.dart';\nimport 'list_notifier.dart';\n\n/// A base controller class that provides state management functionality.\n///\n/// Extend this class to create a controller that can be used with GetX's\n/// state management system. This class provides methods to update the UI\n/// when the controller's state changes.\n///\n/// Example:\n/// ```dart\n/// class CounterController extends GetxController {\n///   var count = 0;\n///\n///   void increment() {\n///     count++;\n///     update(); // Triggers UI update\n///   }\n/// }\n/// ```\n// ignore: prefer_mixin\nabstract class GetxController extends ListNotifier with GetLifeCycleMixin {\n  /// Notifies listeners to update the UI.\n  ///\n  /// When called without parameters, it will update all widgets that depend on\n  /// this controller. You can also specify specific widget IDs to update only\n  /// those widgets.\n  ///\n  /// Parameters:\n  /// - [ids]: Optional list of widget IDs to update. If null, updates all widgets.\n  /// - [condition]: If false, the update will be skipped.\n  ///\n  void update([List<Object>? ids, bool condition = true]) {\n    if (!condition) {\n      return;\n    }\n    if (ids == null) {\n      refresh();\n    } else {\n      for (final id in ids) {\n        refreshGroup(id);\n      }\n    }\n  }\n}\n\n/// A mixin that provides scroll-based data fetching capabilities.\n///\n/// This mixin can be used with controllers that need to load more data\n/// when the user scrolls to the top or bottom of a scrollable view.\n///\n/// Example:\n/// ```dart\n/// class MyController extends GetxController with ScrollMixin {\n///   @override\n///   Future<void> onEndScroll() async {\n///     // Load more data when scrolled to bottom\n///   }\n///\n///   @override\n///   Future<void> onTopScroll() async {\n///     // Load previous data when scrolled to top\n///   }\n/// }\n/// ```\nmixin ScrollMixin on GetLifeCycleMixin {\n  /// The scroll controller used to detect scroll position\n  final ScrollController scroll = ScrollController();\n\n  @override\n  void onInit() {\n    super.onInit();\n    scroll.addListener(_listener);\n  }\n\n  /// Flag to prevent multiple simultaneous bottom fetches\n  bool _canFetchBottom = true;\n\n  /// Flag to prevent multiple simultaneous top fetches\n  bool _canFetchTop = true;\n\n  void _listener() {\n    if (scroll.position.atEdge) {\n      _checkIfCanLoadMore();\n    }\n  }\n\n  Future<void> _checkIfCanLoadMore() async {\n    if (scroll.position.pixels == 0) {\n      if (!_canFetchTop) return;\n      _canFetchTop = false;\n      await onTopScroll();\n      _canFetchTop = true;\n    } else {\n      if (!_canFetchBottom) return;\n      _canFetchBottom = false;\n      await onEndScroll();\n      _canFetchBottom = true;\n    }\n  }\n\n  /// this method is called when the scroll is at the bottom\n  Future<void> onEndScroll();\n\n  /// this method is called when the scroll is at the top\n  Future<void> onTopScroll();\n\n  @override\n  void onClose() {\n    scroll.removeListener(_listener);\n    scroll.dispose();\n    super.onClose();\n  }\n}\n\n/// A base controller class for reactive state management using Rx variables.\n///\n/// This class is a lightweight alternative to [GetxController] when you only\n/// need reactive variables without the need for manual UI updates.\n///\n/// Example:\n/// ```dart\n/// class UserController extends RxController {\n///   final name = 'John'.obs;\n///   final age = 30.obs;\n/// }\n/// ```\nabstract class RxController with GetLifeCycleMixin {}\n\n/// A controller that manages state for asynchronous operations.\n///\n/// This controller provides a standard way to handle loading, error, and success\n/// states for async operations. It's particularly useful for API calls and\n/// other asynchronous operations.\n///\n/// Type parameters:\n/// - [T]: The type of data this controller will manage\n///\n/// Example:\n/// ```dart\n/// class UserController extends StateController<User> {\n///   Future<void> fetchUser() async {\n///     change(null, status: RxStatus.loading());\n///     try {\n///       final user = await userRepository.getUser();\n///       change(user, status: RxStatus.success());\n///     } catch (e) {\n///       change(state, status: RxStatus.error(e.toString()));\n///     }\n///   }\n/// }\n/// ```\nabstract class StateController<T> extends GetxController with StateMixin<T> {}\n\n/// A controller that combines full lifecycle management with state management.\n///\n/// This controller is ideal for complex scenarios where you need both:\n/// 1. Full app lifecycle awareness\n/// 2. State management with loading/error states\n///\n/// Type parameters:\n/// - [T]: The type of data this controller will manage\n///\n/// Example:\n/// ```dart\n/// class HomeController extends SuperController<HomeState> {\n///   @override\n///   void onResumed() {\n///     // App came to foreground\n///     fetchData();\n///   }\n///\n///   Future<void> fetchData() async {\n///     change(state, status: RxStatus.loading());\n///     try {\n///       final data = await repository.getData();\n///       change(HomeState(data: data), status: RxStatus.success());\n///     } catch (e) {\n///       change(state, status: RxStatus.error(e.toString()));\n///     }\n///   }\n/// }\n/// ```\nabstract class SuperController<T> extends FullLifeCycleController\n    with FullLifeCycleMixin, StateMixin<T> {}\n\n/// A controller that can observe the full app lifecycle.\n///\n/// This controller extends [GetxController] and implements [WidgetsBindingObserver]\n/// to provide full lifecycle awareness. It can respond to:\n/// - App lifecycle changes (resumed, paused, etc.)\n/// - Memory pressure events\n/// - Accessibility changes\n///\n/// Note: Don't forget to call `super.onClose()` in your controller's\n/// [onClose] method to properly clean up the observer.\n///\n/// Example:\n/// ```dart\n/// class MyController extends FullLifeCycleController {\n///   @override\n///   void onResumed() {\n///     // App came to foreground\n///   }\n///\n///   @override\n///   void onPaused() {\n///     // App went to background\n///   }\n///\n///   @override\n///   void onClose() {\n///     // Clean up resources\n///     super.onClose();\n///   }\n/// }\n/// ```\nabstract class FullLifeCycleController extends GetxController\n    with\n        // ignore: prefer_mixin\n        WidgetsBindingObserver {}\n\n/// A mixin that provides full lifecycle callbacks for the controller.\n///\n/// This mixin handles app lifecycle events, memory pressure, and accessibility changes.\n/// Override the provided methods to respond to these events.\n///\n/// Example:\n/// ```dart\n/// class MyController extends FullLifeCycleController with FullLifeCycleMixin {\n///   @override\n///   void onResumed() {\n///     // App came to foreground\n///   }\n///\n///   @override\n///   void onMemoryPressure() {\n///     // Clean up resources when system is low on memory\n///   }\n/// }\n/// ```\nmixin FullLifeCycleMixin on FullLifeCycleController {\n  @mustCallSuper\n  @override\n  void onInit() {\n    super.onInit();\n    Engine.instance.addObserver(this);\n  }\n\n  @mustCallSuper\n  @override\n  void onClose() {\n    Engine.instance.removeObserver(this);\n    super.onClose();\n  }\n\n  @mustCallSuper\n  @override\n  void didChangeAppLifecycleState(AppLifecycleState state) {\n    switch (state) {\n      case AppLifecycleState.resumed:\n        onResumed();\n        break;\n      case AppLifecycleState.inactive:\n        onInactive();\n        break;\n      case AppLifecycleState.paused:\n        onPaused();\n        break;\n      case AppLifecycleState.detached:\n        onDetached();\n        break;\n      case AppLifecycleState.hidden:\n        onHidden();\n        break;\n    }\n  }\n\n  @override\n  void didHaveMemoryPressure() {\n    super.didHaveMemoryPressure();\n    onMemoryPressure();\n  }\n\n  @override\n  void didChangeAccessibilityFeatures() {\n    super.didChangeAccessibilityFeatures();\n    onAccessibilityChanged();\n  }\n\n  /// Called when the system reports that the app is visible and interactive.\n  /// This is called when the app returns to the foreground.\n  void onResumed() {}\n\n  /// Called when the app is not currently visible to the user, not responding to\n  /// user input, and running in the background.\n  void onPaused() {}\n\n  /// Called when the app is in an inactive state and is not receiving user input.\n  /// For example, when a phone call is received or when the app is in a\n  /// multi-window mode.\n  void onInactive() {}\n\n  /// Called before the app is destroyed.\n  /// This is the final callback the app will receive before it is terminated.\n  void onDetached() {}\n\n  /// Called when the app is hidden (e.g., when the device is locked).\n  void onHidden() {}\n\n  /// Called when the system is running low on memory.\n  /// Override this method to release caches or other resources that aren't\n  /// critical for the app to function.\n  void onMemoryPressure() {}\n\n  /// Called when the system changes the set of currently active accessibility\n  /// features.\n  void onAccessibilityChanged() {}\n}\n"
  },
  {
    "path": "lib/get_state_manager/src/simple/get_responsive.dart",
    "content": "import 'package:flutter/widgets.dart';\n\nimport '../../../get.dart';\n\nmixin GetResponsiveMixin on Widget {\n  ResponsiveScreen get screen;\n  bool get alwaysUseBuilder;\n\n  @protected\n  Widget build(BuildContext context) {\n    screen.context = context;\n    Widget? widget;\n    if (alwaysUseBuilder) {\n      widget = builder();\n      if (widget != null) return widget;\n    }\n    if (screen.isDesktop) {\n      widget = desktop() ?? widget;\n      if (widget != null) return widget;\n    }\n    if (screen.isTablet) {\n      widget = tablet() ?? desktop();\n      if (widget != null) return widget;\n    }\n    if (screen.isPhone) {\n      widget = phone() ?? tablet() ?? desktop();\n      if (widget != null) return widget;\n    }\n    return watch() ?? phone() ?? tablet() ?? desktop() ?? builder()!;\n  }\n\n  Widget? builder() => null;\n\n  Widget? desktop() => null;\n\n  Widget? phone() => null;\n\n  Widget? tablet() => null;\n\n  Widget? watch() => null;\n}\n\n/// Extend this widget to build responsive view.\n/// this widget contains the `screen` property that have all\n/// information about the screen size and type.\n/// You have two options to build it.\n/// 1- with `builder` method you return the widget to build.\n/// 2- with methods `desktop`, `tablet`,`phone`, `watch`. the specific\n/// method will be built when the screen type matches the method\n/// when the screen is [ScreenType.Tablet] the `tablet` method\n/// will be exuded and so on.\n/// Note if you use this method please set the\n/// property `alwaysUseBuilder` to false\n/// With `settings` property you can set the width limit for the screen types.\nclass GetResponsiveView<T> extends GetView<T> with GetResponsiveMixin {\n  @override\n  final bool alwaysUseBuilder;\n\n  @override\n  final ResponsiveScreen screen;\n\n  GetResponsiveView({\n    this.alwaysUseBuilder = false,\n    ResponsiveScreenSettings settings = const ResponsiveScreenSettings(),\n    super.key,\n  }) : screen = ResponsiveScreen(settings);\n}\n\nclass GetResponsiveWidget<T extends GetLifeCycleMixin> extends GetWidget<T>\n    with GetResponsiveMixin {\n  @override\n  final bool alwaysUseBuilder;\n\n  @override\n  final ResponsiveScreen screen;\n\n  GetResponsiveWidget({\n    this.alwaysUseBuilder = false,\n    ResponsiveScreenSettings settings = const ResponsiveScreenSettings(),\n    super.key,\n  }) : screen = ResponsiveScreen(settings);\n}\n\nclass ResponsiveScreenSettings {\n  /// When the width is greater als this value\n  /// the display will be set as [ScreenType.Desktop]\n  final double desktopChangePoint;\n\n  /// When the width is greater als this value\n  /// the display will be set as [ScreenType.Tablet]\n  /// or when width greater als [watchChangePoint] and smaller als this value\n  /// the display will be [ScreenType.Phone]\n  final double tabletChangePoint;\n\n  /// When the width is smaller als this value\n  /// the display will be set as [ScreenType.Watch]\n  /// or when width greater als this value and smaller als [tabletChangePoint]\n  /// the display will be [ScreenType.Phone]\n  final double watchChangePoint;\n\n  const ResponsiveScreenSettings(\n      {this.desktopChangePoint = 1200,\n      this.tabletChangePoint = 600,\n      this.watchChangePoint = 300});\n}\n\nclass ResponsiveScreen {\n  late BuildContext context;\n  final ResponsiveScreenSettings settings;\n\n  late bool _isPlatformDesktop;\n  ResponsiveScreen(this.settings) {\n    _isPlatformDesktop = GetPlatform.isDesktop;\n  }\n\n  double get height => context.height;\n  double get width => context.width;\n\n  /// Is [screenType] [ScreenType.Desktop]\n  bool get isDesktop => (screenType == ScreenType.desktop);\n\n  /// Is [screenType] [ScreenType.Tablet]\n  bool get isTablet => (screenType == ScreenType.tablet);\n\n  /// Is [screenType] [ScreenType.Phone]\n  bool get isPhone => (screenType == ScreenType.phone);\n\n  /// Is [screenType] [ScreenType.Watch]\n  bool get isWatch => (screenType == ScreenType.watch);\n\n  double get _getDeviceWidth {\n    if (_isPlatformDesktop) {\n      return width;\n    }\n    return context.mediaQueryShortestSide;\n  }\n\n  ScreenType get screenType {\n    final deviceWidth = _getDeviceWidth;\n    if (deviceWidth >= settings.desktopChangePoint) return ScreenType.desktop;\n    if (deviceWidth >= settings.tabletChangePoint) return ScreenType.tablet;\n    if (deviceWidth < settings.watchChangePoint) return ScreenType.watch;\n    return ScreenType.phone;\n  }\n\n  /// Return widget according to screen type\n  /// if the [screenType] is [ScreenType.Desktop] and\n  /// `desktop` object is null the `tablet` object will be returned\n  /// and if `tablet` object is null the `mobile` object will be returned\n  /// and if `mobile` object is null the `watch` object will be returned\n  ///  also when it is null.\n  T? responsiveValue<T>({\n    T? mobile,\n    T? tablet,\n    T? desktop,\n    T? watch,\n  }) {\n    if (isDesktop && desktop != null) return desktop;\n    if (isTablet && tablet != null) return tablet;\n    if (isPhone && mobile != null) return mobile;\n    return watch;\n  }\n}\n\nenum ScreenType {\n  watch,\n  phone,\n  tablet,\n  desktop,\n}\n"
  },
  {
    "path": "lib/get_state_manager/src/simple/get_state.dart",
    "content": "// ignore_for_file: overridden_fields\n\nimport 'dart:async';\n\nimport 'package:flutter/material.dart';\n\nimport '../../../instance_manager.dart';\nimport '../../get_state_manager.dart';\nimport 'list_notifier.dart';\n\ntypedef InitBuilder<T> = T Function();\n\ntypedef GetControllerBuilder<T extends GetLifeCycleMixin> = Widget Function(\n    T controller);\n\nextension WatchExt on BuildContext {\n  T listen<T>() {\n    return Bind.of(this, rebuild: true);\n  }\n}\n\nextension ReadExt on BuildContext {\n  T get<T>() {\n    return Bind.of(this);\n  }\n}\n\n// extension FilterExt on BuildContext {\n//   T filter<T extends GetxController>(Object Function(T value)? filter) {\n//     return Bind.of(this, filter: filter, rebuild: true);\n//   }\n// }\n\nclass GetBuilder<T extends GetxController> extends StatelessWidget {\n  final GetControllerBuilder<T> builder;\n  final bool global;\n  final Object? id;\n  final String? tag;\n  final bool autoRemove;\n  final bool assignId;\n  final Object Function(T value)? filter;\n  final void Function(BindElement<T> state)? initState,\n      dispose,\n      didChangeDependencies;\n  final void Function(Binder<T> oldWidget, BindElement<T> state)?\n      didUpdateWidget;\n  final T? init;\n\n  const GetBuilder({\n    super.key,\n    this.init,\n    this.global = true,\n    required this.builder,\n    this.autoRemove = true,\n    this.assignId = false,\n    this.initState,\n    this.filter,\n    this.tag,\n    this.dispose,\n    this.id,\n    this.didChangeDependencies,\n    this.didUpdateWidget,\n  });\n\n  @override\n  Widget build(BuildContext context) {\n    return Binder(\n      init: init == null ? null : () => init!,\n      global: global,\n      autoRemove: autoRemove,\n      assignId: assignId,\n      initState: initState,\n      filter: filter,\n      tag: tag,\n      dispose: dispose,\n      id: id,\n      lazy: false,\n      didChangeDependencies: didChangeDependencies,\n      didUpdateWidget: didUpdateWidget,\n      child: Builder(builder: (context) {\n        final controller = Bind.of<T>(context, rebuild: true);\n        return builder(controller);\n      }),\n    );\n    // return widget.builder(controller!);\n  }\n}\n\nabstract class Bind<T> extends StatelessWidget {\n  const Bind({\n    super.key,\n    required this.child,\n    this.init,\n    this.global = true,\n    this.autoRemove = true,\n    this.assignId = false,\n    this.initState,\n    this.filter,\n    this.tag,\n    this.dispose,\n    this.id,\n    this.didChangeDependencies,\n    this.didUpdateWidget,\n  });\n\n  final InitBuilder<T>? init;\n\n  final bool global;\n  final Object? id;\n  final String? tag;\n  final bool autoRemove;\n  final bool assignId;\n  final Object Function(T value)? filter;\n  final void Function(BindElement<T> state)? initState,\n      dispose,\n      didChangeDependencies;\n  final void Function(Binder<T> oldWidget, BindElement<T> state)?\n      didUpdateWidget;\n\n  final Widget? child;\n\n  static Bind put<S>(\n    S dependency, {\n    String? tag,\n    bool permanent = false,\n  }) {\n    Get.put<S>(dependency, tag: tag, permanent: permanent);\n    return _FactoryBind<S>(\n      autoRemove: permanent,\n      assignId: true,\n      tag: tag,\n    );\n  }\n\n  static bool fenixMode = false;\n\n  static Bind lazyPut<S>(\n    InstanceBuilderCallback<S> builder, {\n    String? tag,\n    bool? fenix,\n    // VoidCallback? onInit,\n    VoidCallback? onClose,\n  }) {\n    Get.lazyPut<S>(builder, tag: tag, fenix: fenix ?? fenixMode);\n    return _FactoryBind<S>(\n      tag: tag,\n      // initState: (_) {\n      //   onInit?.call();\n      // },\n      dispose: (_) {\n        onClose?.call();\n      },\n    );\n  }\n\n  static Bind create<S>(InstanceCreateBuilderCallback<S> builder,\n      {String? tag, bool permanent = true}) {\n    return _FactoryBind<S>(\n      create: builder,\n      tag: tag,\n      global: false,\n    );\n  }\n\n  static Bind spawn<S>(InstanceBuilderCallback<S> builder,\n      {String? tag, bool permanent = true}) {\n    Get.spawn<S>(builder, tag: tag, permanent: permanent);\n    return _FactoryBind<S>(\n      tag: tag,\n      global: false,\n      autoRemove: permanent,\n    );\n  }\n\n  static S find<S>({String? tag}) => Get.find<S>(tag: tag);\n\n  static Future<bool> delete<S>({String? tag, bool force = false}) async =>\n      Get.delete<S>(tag: tag, force: force);\n\n  static Future<void> deleteAll({bool force = false}) async =>\n      Get.deleteAll(force: force);\n\n  static void reloadAll({bool force = false}) => Get.reloadAll(force: force);\n\n  static void reload<S>({String? tag, String? key, bool force = false}) =>\n      Get.reload<S>(tag: tag, key: key, force: force);\n\n  static bool isRegistered<S>({String? tag}) => Get.isRegistered<S>(tag: tag);\n\n  static bool isPrepared<S>({String? tag}) => Get.isPrepared<S>(tag: tag);\n\n  static void replace<P>(P child, {String? tag}) {\n    final info = Get.getInstanceInfo<P>(tag: tag);\n    final permanent = (info.isPermanent ?? false);\n    delete<P>(tag: tag, force: permanent);\n    Get.put(child, tag: tag, permanent: permanent);\n  }\n\n  static void lazyReplace<P>(InstanceBuilderCallback<P> builder,\n      {String? tag, bool? fenix}) {\n    final info = Get.getInstanceInfo<P>(tag: tag);\n    final permanent = (info.isPermanent ?? false);\n    delete<P>(tag: tag, force: permanent);\n    Get.lazyPut(builder, tag: tag, fenix: fenix ?? permanent);\n  }\n\n  factory Bind.builder({\n    Widget? child,\n    InitBuilder<T>? init,\n    InstanceCreateBuilderCallback<T>? create,\n    bool global = true,\n    bool autoRemove = true,\n    bool assignId = false,\n    Object Function(T value)? filter,\n    String? tag,\n    Object? id,\n    void Function(BindElement<T> state)? initState,\n    void Function(BindElement<T> state)? dispose,\n    void Function(BindElement<T> state)? didChangeDependencies,\n    void Function(Binder<T> oldWidget, BindElement<T> state)? didUpdateWidget,\n  }) =>\n      _FactoryBind<T>(\n        // key: key,\n        init: init,\n        create: create,\n        global: global,\n        autoRemove: autoRemove,\n        assignId: assignId,\n        initState: initState,\n        filter: filter,\n        tag: tag,\n        dispose: dispose,\n        id: id,\n        didChangeDependencies: didChangeDependencies,\n        didUpdateWidget: didUpdateWidget,\n        child: child,\n      );\n\n  static T of<T>(\n    BuildContext context, {\n    bool rebuild = false,\n    // Object Function(T value)? filter,\n  }) {\n    final inheritedElement =\n        context.getElementForInheritedWidgetOfExactType<Binder<T>>()\n            as BindElement<T>?;\n\n    if (inheritedElement == null) {\n      throw BindError(controller: '$T', tag: null);\n    }\n\n    if (rebuild) {\n      // var newFilter = filter?.call(inheritedElement.controller!);\n      // if (newFilter != null) {\n      //  context.dependOnInheritedElement(inheritedElement, aspect: newFilter);\n      // } else {\n      context.dependOnInheritedElement(inheritedElement);\n      // }\n    }\n\n    final controller = inheritedElement.controller;\n\n    return controller;\n  }\n\n  @factory\n  Bind<T> _copyWithChild(Widget child);\n}\n\nclass _FactoryBind<T> extends Bind<T> {\n  @override\n  final InitBuilder<T>? init;\n\n  final InstanceCreateBuilderCallback<T>? create;\n\n  @override\n  final bool global;\n  @override\n  final Object? id;\n  @override\n  final String? tag;\n  @override\n  final bool autoRemove;\n  @override\n  final bool assignId;\n  @override\n  final Object Function(T value)? filter;\n\n  @override\n  final void Function(BindElement<T> state)? initState,\n      dispose,\n      didChangeDependencies;\n  @override\n  final void Function(Binder<T> oldWidget, BindElement<T> state)?\n      didUpdateWidget;\n\n  @override\n  final Widget? child;\n\n  const _FactoryBind({\n    super.key,\n    this.child,\n    this.init,\n    this.create,\n    this.global = true,\n    this.autoRemove = true,\n    this.assignId = false,\n    this.initState,\n    this.filter,\n    this.tag,\n    this.dispose,\n    this.id,\n    this.didChangeDependencies,\n    this.didUpdateWidget,\n  }) : super(child: child);\n\n  @override\n  Bind<T> _copyWithChild(Widget child) {\n    return Bind<T>.builder(\n      init: init,\n      create: create,\n      global: global,\n      autoRemove: autoRemove,\n      assignId: assignId,\n      initState: initState,\n      filter: filter,\n      tag: tag,\n      dispose: dispose,\n      id: id,\n      didChangeDependencies: didChangeDependencies,\n      didUpdateWidget: didUpdateWidget,\n      child: child,\n    );\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return Binder<T>(\n      create: create,\n      global: global,\n      autoRemove: autoRemove,\n      assignId: assignId,\n      initState: initState,\n      filter: filter,\n      tag: tag,\n      dispose: dispose,\n      id: id,\n      didChangeDependencies: didChangeDependencies,\n      didUpdateWidget: didUpdateWidget,\n      child: child!,\n    );\n  }\n}\n\nclass Binds extends StatelessWidget {\n  final List<Bind<dynamic>> binds;\n  final Widget child;\n\n  Binds({\n    super.key,\n    required this.binds,\n    required this.child,\n  }) : assert(binds.isNotEmpty);\n\n  @override\n  Widget build(BuildContext context) =>\n      binds.reversed.fold(child, (widget, e) => e._copyWithChild(widget));\n}\n\nclass Binder<T> extends InheritedWidget {\n  /// Create an inherited widget that updates its dependents when [controller]\n  /// sends notifications.\n  ///\n  /// The [child] argument is required\n  const Binder({\n    super.key,\n    required super.child,\n    this.init,\n    this.global = true,\n    this.autoRemove = true,\n    this.assignId = false,\n    this.lazy = true,\n    this.initState,\n    this.filter,\n    this.tag,\n    this.dispose,\n    this.id,\n    this.didChangeDependencies,\n    this.didUpdateWidget,\n    this.create,\n  });\n\n  final InitBuilder<T>? init;\n  final InstanceCreateBuilderCallback? create;\n  final bool global;\n  final Object? id;\n  final String? tag;\n  final bool lazy;\n  final bool autoRemove;\n  final bool assignId;\n  final Object Function(T value)? filter;\n  final void Function(BindElement<T> state)? initState,\n      dispose,\n      didChangeDependencies;\n  final void Function(Binder<T> oldWidget, BindElement<T> state)?\n      didUpdateWidget;\n\n  @override\n  bool updateShouldNotify(Binder<T> oldWidget) {\n    return oldWidget.id != id ||\n        oldWidget.global != global ||\n        oldWidget.autoRemove != autoRemove ||\n        oldWidget.assignId != assignId;\n  }\n\n  @override\n  InheritedElement createElement() => BindElement<T>(this);\n}\n\n/// The BindElement is responsible for injecting dependencies into the widget\n/// tree so that they can be observed\nclass BindElement<T> extends InheritedElement {\n  BindElement(Binder<T> super.widget) {\n    initState();\n  }\n\n  final disposers = <Disposer>[];\n\n  InitBuilder<T>? _controllerBuilder;\n\n  T? _controller;\n\n  T get controller {\n    if (_controller == null) {\n      _controller = _controllerBuilder?.call();\n      _subscribeToController();\n      if (_controller == null) {\n        throw BindError(controller: T, tag: widget.tag);\n      }\n      return _controller!;\n    } else {\n      return _controller!;\n    }\n  }\n\n  bool? _isCreator = false;\n  bool? _needStart = false;\n  bool _wasStarted = false;\n  VoidCallback? _remove;\n  Object? _filter;\n\n  void initState() {\n    widget.initState?.call(this);\n\n    var isRegistered = Get.isRegistered<T>(tag: widget.tag);\n\n    if (widget.global) {\n      if (isRegistered) {\n        if (Get.isPrepared<T>(tag: widget.tag)) {\n          _isCreator = true;\n        } else {\n          _isCreator = false;\n        }\n\n        _controllerBuilder = () => Get.find<T>(tag: widget.tag);\n      } else {\n        _controllerBuilder =\n            () => (widget.create?.call(this) ?? widget.init?.call());\n        _isCreator = true;\n        if (widget.lazy) {\n          Get.lazyPut<T>(_controllerBuilder!, tag: widget.tag);\n        } else {\n          Get.put<T>(_controllerBuilder!(), tag: widget.tag);\n        }\n      }\n    } else {\n      if (widget.create != null) {\n        _controllerBuilder = () => widget.create!.call(this);\n        Get.spawn<T>(_controllerBuilder!, tag: widget.tag, permanent: false);\n      } else {\n        _controllerBuilder = widget.init;\n      }\n      _controllerBuilder =\n          (widget.create != null ? () => widget.create!.call(this) : null) ??\n              widget.init;\n      _isCreator = true;\n      _needStart = true;\n    }\n  }\n\n  /// Register to listen Controller's events.\n  /// It gets a reference to the remove() callback, to delete the\n  /// setState \"link\" from the Controller.\n  void _subscribeToController() {\n    if (widget.filter != null) {\n      _filter = widget.filter!(_controller as T);\n    }\n    final filter = _filter != null ? _filterUpdate : getUpdate;\n    final localController = _controller;\n\n    if (_needStart == true && localController is GetLifeCycleMixin) {\n      localController.onStart();\n      _needStart = false;\n      _wasStarted = true;\n    }\n\n    if (localController is GetxController) {\n      _remove?.call();\n      _remove = (widget.id == null)\n          ? localController.addListener(filter)\n          : localController.addListenerId(widget.id, filter);\n    } else if (localController is Listenable) {\n      _remove?.call();\n      localController.addListener(filter);\n      _remove = () => localController.removeListener(filter);\n    } else if (localController is StreamController) {\n      _remove?.call();\n      final stream = localController.stream.listen((_) => filter());\n      _remove = () => stream.cancel();\n    }\n  }\n\n  void _filterUpdate() {\n    var newFilter = widget.filter!(_controller as T);\n    if (newFilter != _filter) {\n      _filter = newFilter;\n      getUpdate();\n    }\n  }\n\n  void dispose() {\n    widget.dispose?.call(this);\n    if (_isCreator! || widget.assignId) {\n      if (widget.autoRemove && Get.isRegistered<T>(tag: widget.tag)) {\n        Get.delete<T>(tag: widget.tag);\n      }\n    }\n\n    for (final disposer in disposers) {\n      disposer();\n    }\n\n    disposers.clear();\n\n    _remove?.call();\n    _controller = null;\n    _isCreator = null;\n    _remove = null;\n    _filter = null;\n    _needStart = null;\n    _controllerBuilder = null;\n    _controller = null;\n  }\n\n  @override\n  Binder<T> get widget => super.widget as Binder<T>;\n\n  var _dirty = false;\n\n  @override\n  void update(Binder<T> newWidget) {\n    final oldNotifier = widget.id;\n    final newNotifier = newWidget.id;\n    if (oldNotifier != newNotifier && _wasStarted) {\n      _subscribeToController();\n    }\n    widget.didUpdateWidget?.call(widget, this);\n    super.update(newWidget);\n  }\n\n  @override\n  void didChangeDependencies() {\n    super.didChangeDependencies();\n    widget.didChangeDependencies?.call(this);\n  }\n\n  @override\n  Widget build() {\n    if (_dirty) {\n      notifyClients(widget);\n    }\n    // return Notifier.instance.notifyAppend(\n    //   NotifyData(\n    //       disposers: disposers, updater: getUpdate, throwException: false),\n    return super.build();\n    //);\n  }\n\n  void getUpdate() {\n    _dirty = true;\n    markNeedsBuild();\n  }\n\n  @override\n  void notifyClients(Binder<T> oldWidget) {\n    super.notifyClients(oldWidget);\n    _dirty = false;\n  }\n\n  @override\n  void unmount() {\n    dispose();\n    super.unmount();\n  }\n}\n\nclass BindError<T> extends Error {\n  /// The type of the class the user tried to retrieve\n  final T controller;\n  final String? tag;\n\n  /// Creates a [BindError]\n  BindError({required this.controller, required this.tag});\n\n  @override\n  String toString() {\n    if (controller == 'dynamic') {\n      return '''Error: please specify type [<T>] when calling context.listen<T>() or context.find<T>() method.''';\n    }\n\n    return '''Error: No Bind<$controller>  ancestor found. To fix this, please add a Bind<$controller> widget ancestor to the current context.\n      ''';\n  }\n}\n\n/// [Binding] should be extended.\n/// When using `GetMaterialApp`, all `GetPage`s and navigation\n/// methods (like Get.to()) have a `binding` property that takes an\n/// instance of Bindings to manage the\n/// dependencies() (via Get.put()) for the Route you are opening.\n// ignore: one_member_abstracts\nabstract class Binding extends BindingsInterface<List<Bind>> {}\n"
  },
  {
    "path": "lib/get_state_manager/src/simple/get_view.dart",
    "content": "import 'package:flutter/widgets.dart';\n\nimport '../../../instance_manager.dart';\nimport '../../../utils.dart';\nimport 'get_state.dart';\nimport 'get_widget_cache.dart';\n\n/// GetView is a great way of quickly access your Controller\n/// without having to call `Get.find<AwesomeController>()` yourself.\n///\n/// Sample:\n/// ```\n/// class AwesomeController extends GetxController {\n///   final String title = 'My Awesome View';\n/// }\n///\n/// class AwesomeView extends GetView<AwesomeController> {\n///   /// if you need you can pass the tag for\n///   /// Get.find<AwesomeController>(tag:\"myTag\");\n///   @override\n///   final String tag = \"myTag\";\n///\n///   AwesomeView({Key key}):super(key:key);\n///\n///   @override\n///   Widget build(BuildContext context) {\n///     return Container(\n///       padding: EdgeInsets.all(20),\n///       child: Text( controller.title ),\n///     );\n///   }\n/// }\n///``\nabstract class GetView<T> extends StatelessWidget {\n  const GetView({super.key});\n\n  final String? tag = null;\n\n  T get controller => Get.find<T>(tag: tag)!;\n\n  @override\n  Widget build(BuildContext context);\n}\n\n/// GetWidget is a great way of quickly access your individual Controller\n/// without having to call `Get.find<AwesomeController>()` yourself.\n/// Get save you controller on cache, so, you can to use Get.create() safely\n/// GetWidget is perfect to multiples instance of a same controller. Each\n/// GetWidget will have your own controller, and will be call events as `onInit`\n/// and `onClose` when the controller get in/get out on memory.\nabstract class GetWidget<S extends GetLifeCycleMixin> extends GetWidgetCache {\n  const GetWidget({super.key});\n\n  @protected\n  final String? tag = null;\n\n  S get controller => GetWidget._cache[this] as S;\n\n  // static final _cache = <GetWidget, GetLifeCycleBase>{};\n\n  static final _cache = Expando<GetLifeCycleMixin>();\n\n  @protected\n  Widget build(BuildContext context);\n\n  @override\n  WidgetCache createWidgetCache() => _GetCache<S>();\n}\n\nclass _GetCache<S extends GetLifeCycleMixin> extends WidgetCache<GetWidget<S>> {\n  S? _controller;\n  bool _isCreator = false;\n  InstanceInfo? info;\n  @override\n  void onInit() {\n    info = Get.getInstanceInfo<S>(tag: widget!.tag);\n\n    _isCreator = info!.isPrepared && info!.isCreate;\n\n    if (info!.isRegistered) {\n      _controller = Get.find<S>(tag: widget!.tag);\n    }\n\n    GetWidget._cache[widget!] = _controller;\n\n    super.onInit();\n  }\n\n  @override\n  void onClose() {\n    if (_isCreator) {\n      Get.asap(() {\n        widget!.controller.onDelete();\n        Get.log('\"${widget!.controller.runtimeType}\" onClose() called');\n        Get.log('\"${widget!.controller.runtimeType}\" deleted from memory');\n        // GetWidget._cache[widget!] = null;\n      });\n    }\n    info = null;\n    super.onClose();\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return Binder(\n      init: () => _controller,\n      child: widget!.build(context),\n    );\n  }\n}\n"
  },
  {
    "path": "lib/get_state_manager/src/simple/get_widget_cache.dart",
    "content": "import 'package:flutter/widgets.dart';\n\nabstract class GetWidgetCache extends Widget {\n  const GetWidgetCache({super.key});\n\n  @override\n  GetWidgetCacheElement createElement() => GetWidgetCacheElement(this);\n\n  @protected\n  @factory\n  WidgetCache createWidgetCache();\n}\n\nclass GetWidgetCacheElement extends ComponentElement {\n  GetWidgetCacheElement(GetWidgetCache widget)\n      : cache = widget.createWidgetCache(),\n        super(widget) {\n    cache._element = this;\n    cache._widget = widget;\n  }\n\n  @override\n  void mount(Element? parent, dynamic newSlot) {\n    cache.onInit();\n    super.mount(parent, newSlot);\n  }\n\n  @override\n  Widget build() => cache.build(this);\n\n  final WidgetCache<GetWidgetCache> cache;\n\n  @override\n  void activate() {\n    super.activate();\n    markNeedsBuild();\n  }\n\n  @override\n  void unmount() {\n    super.unmount();\n    cache.onClose();\n    cache._element = null;\n  }\n}\n\n@optionalTypeArgs\nabstract class WidgetCache<T extends GetWidgetCache> {\n  T? get widget => _widget;\n  T? _widget;\n\n  BuildContext? get context => _element;\n\n  GetWidgetCacheElement? _element;\n\n  @protected\n  @mustCallSuper\n  void onInit() {}\n\n  @protected\n  @mustCallSuper\n  void onClose() {}\n\n  @protected\n  Widget build(BuildContext context);\n}\n"
  },
  {
    "path": "lib/get_state_manager/src/simple/list_notifier.dart",
    "content": "import 'dart:collection';\n\nimport 'package:flutter/foundation.dart';\n\n// This callback remove the listener on addListener function\ntypedef Disposer = void Function();\n\n// replacing StateSetter, return if the Widget is mounted for extra validation.\n// if it brings overhead the extra call,\ntypedef GetStateUpdate = void Function();\n\nclass ListNotifier extends Listenable\n    with ListNotifierSingleMixin, ListNotifierGroupMixin {}\n\n/// A Notifier with single listeners\nclass ListNotifierSingle = ListNotifier with ListNotifierSingleMixin;\n\n/// A notifier with group of listeners identified by id\nclass ListNotifierGroup = ListNotifier with ListNotifierGroupMixin;\n\n/// This mixin add to Listenable the addListener, removerListener and\n/// containsListener implementation\nmixin ListNotifierSingleMixin on Listenable {\n  List<GetStateUpdate>? _updaters = <GetStateUpdate>[];\n\n  // final int _version = 0;\n  // final int _microtaskVersion = 0;\n\n  @override\n  Disposer addListener(GetStateUpdate listener) {\n    assert(_debugAssertNotDisposed());\n    _updaters!.add(listener);\n    return () => _updaters!.remove(listener);\n  }\n\n  bool containsListener(GetStateUpdate listener) {\n    return _updaters?.contains(listener) ?? false;\n  }\n\n  @override\n  void removeListener(VoidCallback listener) {\n    assert(_debugAssertNotDisposed());\n    _updaters!.remove(listener);\n  }\n\n  @protected\n  void refresh() {\n    assert(_debugAssertNotDisposed());\n    _notifyUpdate();\n  }\n\n  @protected\n  void reportRead() {\n    Notifier.instance.read(this);\n  }\n\n  @protected\n  void reportAdd(VoidCallback disposer) {\n    Notifier.instance.add(disposer);\n  }\n\n  void _notifyUpdate() {\n    // if (_microtaskVersion == _version) {\n    //   _microtaskVersion++;\n    //   scheduleMicrotask(() {\n    //     _version++;\n    //     _microtaskVersion = _version;\n    final list = _updaters?.toList() ?? [];\n\n    for (var element in list) {\n      element();\n    }\n    //   });\n    // }\n  }\n\n  bool get isDisposed => _updaters == null;\n\n  bool _debugAssertNotDisposed() {\n    assert(() {\n      if (isDisposed) {\n        throw FlutterError('''A $runtimeType was used after being disposed.\\n\n'Once you have called dispose() on a $runtimeType, it can no longer be used.''');\n      }\n      return true;\n    }());\n    return true;\n  }\n\n  int get listenersLength {\n    assert(_debugAssertNotDisposed());\n    return _updaters!.length;\n  }\n\n  @mustCallSuper\n  void dispose() {\n    assert(_debugAssertNotDisposed());\n    _updaters = null;\n  }\n}\n\nmixin ListNotifierGroupMixin on Listenable {\n  HashMap<Object?, ListNotifierSingleMixin>? _updatersGroupIds =\n      HashMap<Object?, ListNotifierSingleMixin>();\n\n  void _notifyGroupUpdate(Object id) {\n    if (_updatersGroupIds!.containsKey(id)) {\n      _updatersGroupIds![id]!._notifyUpdate();\n    }\n  }\n\n  @protected\n  void notifyGroupChildrens(Object id) {\n    assert(_debugAssertNotDisposed());\n    Notifier.instance.read(_updatersGroupIds![id]!);\n  }\n\n  bool containsId(Object id) {\n    return _updatersGroupIds?.containsKey(id) ?? false;\n  }\n\n  @protected\n  void refreshGroup(Object id) {\n    assert(_debugAssertNotDisposed());\n    _notifyGroupUpdate(id);\n  }\n\n  bool _debugAssertNotDisposed() {\n    assert(() {\n      if (_updatersGroupIds == null) {\n        throw FlutterError('''A $runtimeType was used after being disposed.\\n\n'Once you have called dispose() on a $runtimeType, it can no longer be used.''');\n      }\n      return true;\n    }());\n    return true;\n  }\n\n  void removeListenerId(Object id, VoidCallback listener) {\n    assert(_debugAssertNotDisposed());\n    if (_updatersGroupIds!.containsKey(id)) {\n      _updatersGroupIds![id]!.removeListener(listener);\n    }\n  }\n\n  @mustCallSuper\n  void dispose() {\n    assert(_debugAssertNotDisposed());\n    _updatersGroupIds?.forEach((key, value) => value.dispose());\n    _updatersGroupIds = null;\n  }\n\n  Disposer addListenerId(Object? key, GetStateUpdate listener) {\n    _updatersGroupIds![key] ??= ListNotifierSingle();\n    return _updatersGroupIds![key]!.addListener(listener);\n  }\n\n  /// To dispose an [id] from future updates(), this ids are registered\n  /// by `GetBuilder()` or similar, so is a way to unlink the state change with\n  /// the Widget from the Controller.\n  void disposeId(Object id) {\n    _updatersGroupIds?[id]?.dispose();\n    _updatersGroupIds!.remove(id);\n  }\n}\n\nclass Notifier {\n  Notifier._();\n\n  static Notifier? _instance;\n  static Notifier get instance => _instance ??= Notifier._();\n\n  NotifyData? _notifyData;\n\n  void add(VoidCallback listener) {\n    _notifyData?.disposers.add(listener);\n  }\n\n  void read(ListNotifierSingleMixin updaters) {\n    final listener = _notifyData?.updater;\n    if (listener != null && !updaters.containsListener(listener)) {\n      updaters.addListener(listener);\n      add(() => updaters.removeListener(listener));\n    }\n  }\n\n  T append<T>(NotifyData data, T Function() builder) {\n    _notifyData = data;\n    final result = builder();\n    if (data.disposers.isEmpty && data.throwException) {\n      throw const ObxError();\n    }\n    _notifyData = null;\n    return result;\n  }\n}\n\nclass NotifyData {\n  const NotifyData(\n      {required this.updater,\n      required this.disposers,\n      this.throwException = true});\n  final GetStateUpdate updater;\n  final List<VoidCallback> disposers;\n  final bool throwException;\n}\n\nclass ObxError {\n  const ObxError();\n  @override\n  String toString() {\n    return \"\"\"\n      [Get] the improper use of a GetX has been detected. \n      You should only use GetX or Obx for the specific widget that will be updated.\n      If you are seeing this error, you probably did not insert any observable variables into GetX/Obx \n      or insert them outside the scope that GetX considers suitable for an update \n      (example: GetX => HeavyWidget => variableObservable).\n      If you need to update a parent widget and a child widget, wrap each one in an Obx/GetX.\n      \"\"\";\n  }\n}\n"
  },
  {
    "path": "lib/get_state_manager/src/simple/mixin_builder.dart",
    "content": "import 'package:flutter/material.dart';\n\nimport '../rx_flutter/rx_obx_widget.dart';\nimport 'get_controllers.dart';\nimport 'get_state.dart';\n\nclass MixinBuilder<T extends GetxController> extends StatelessWidget {\n  @required\n  final Widget Function(T) builder;\n  final bool global;\n  final String? id;\n  final bool autoRemove;\n  final void Function(BindElement<T> state)? initState,\n      dispose,\n      didChangeDependencies;\n  final void Function(Binder<T> oldWidget, BindElement<T> state)?\n      didUpdateWidget;\n  final T? init;\n\n  const MixinBuilder({\n    super.key,\n    this.init,\n    this.global = true,\n    required this.builder,\n    this.autoRemove = true,\n    this.initState,\n    this.dispose,\n    this.id,\n    this.didChangeDependencies,\n    this.didUpdateWidget,\n  });\n\n  @override\n  Widget build(BuildContext context) {\n    return GetBuilder<T>(\n        init: init,\n        global: global,\n        autoRemove: autoRemove,\n        initState: initState,\n        dispose: dispose,\n        id: id,\n        didChangeDependencies: didChangeDependencies,\n        didUpdateWidget: didUpdateWidget,\n        builder: (controller) => Obx(() => builder.call(controller)));\n  }\n}\n"
  },
  {
    "path": "lib/get_state_manager/src/simple/simple_builder.dart",
    "content": "import 'dart:async';\n\nimport 'package:flutter/widgets.dart';\n\nimport 'list_notifier.dart';\n\ntypedef ValueBuilderUpdateCallback<T> = void Function(T snapshot);\ntypedef ValueBuilderBuilder<T> = Widget Function(\n    T snapshot, ValueBuilderUpdateCallback<T> updater);\n\n/// Manages a local state like ObxValue, but uses a callback instead of\n/// a Rx value.\n///\n/// Example:\n/// ```\n///  ValueBuilder<bool>(\n///    initialValue: false,\n///    builder: (value, update) => Switch(\n///    value: value,\n///    onChanged: (flag) {\n///       update( flag );\n///    },),\n///    onUpdate: (value) => print(\"Value updated: $value\"),\n///  ),\n///  ```\nclass ValueBuilder<T> extends StatefulWidget {\n  final T initialValue;\n  final ValueBuilderBuilder<T> builder;\n  final void Function()? onDispose;\n  final void Function(T)? onUpdate;\n\n  const ValueBuilder({\n    super.key,\n    required this.initialValue,\n    this.onDispose,\n    this.onUpdate,\n    required this.builder,\n  });\n\n  @override\n  ValueBuilderState<T> createState() => ValueBuilderState<T>();\n}\n\nclass ValueBuilderState<T> extends State<ValueBuilder<T>> {\n  late T value;\n  @override\n  void initState() {\n    value = widget.initialValue;\n    super.initState();\n  }\n\n  @override\n  Widget build(BuildContext context) => widget.builder(value, updater);\n\n  void updater(T newValue) {\n    if (widget.onUpdate != null) {\n      widget.onUpdate!(newValue);\n    }\n    setState(() {\n      value = newValue;\n    });\n  }\n\n  @override\n  void dispose() {\n    super.dispose();\n    widget.onDispose?.call();\n    if (value is ChangeNotifier) {\n      (value as ChangeNotifier?)?.dispose();\n    } else if (value is StreamController) {\n      (value as StreamController?)?.close();\n    }\n  }\n}\n\nclass ObxElement = StatelessElement with StatelessObserverComponent;\n\n// It's a experimental feature\nclass Observer extends ObxStatelessWidget {\n  final WidgetBuilder builder;\n\n  const Observer({super.key, required this.builder});\n\n  @override\n  Widget build(BuildContext context) => builder(context);\n}\n\n/// A StatelessWidget than can listen reactive changes.\nabstract class ObxStatelessWidget extends StatelessWidget {\n  /// Initializes [key] for subclasses.\n  const ObxStatelessWidget({super.key});\n  @override\n  StatelessElement createElement() => ObxElement(this);\n}\n\n/// a Component that can track changes in a reactive variable\nmixin StatelessObserverComponent on StatelessElement {\n  List<Disposer>? disposers = <Disposer>[];\n\n  void getUpdate() {\n    // if (disposers != null && !dirty) {\n    //   markNeedsBuild();\n    // }\n    if (disposers != null) {\n      scheduleMicrotask(markNeedsBuild);\n    }\n  }\n\n  @override\n  Widget build() {\n    return Notifier.instance.append(\n        NotifyData(disposers: disposers!, updater: getUpdate), super.build);\n  }\n\n  @override\n  void unmount() {\n    super.unmount();\n    for (final disposer in disposers!) {\n      disposer();\n    }\n    disposers!.clear();\n    disposers = null;\n  }\n}\n"
  },
  {
    "path": "lib/get_utils/get_utils.dart",
    "content": "export 'src/equality/equality.dart';\nexport 'src/extensions/export.dart';\nexport 'src/get_utils/get_utils.dart';\nexport 'src/platform/platform.dart';\nexport 'src/queue/get_queue.dart';\n"
  },
  {
    "path": "lib/get_utils/src/equality/equality.dart",
    "content": "library;\n\nimport 'dart:collection';\n\nmixin Equality {\n  List get props;\n\n  @override\n  bool operator ==(Object other) {\n    return identical(this, other) ||\n        runtimeType == other.runtimeType &&\n            other is Equality &&\n            const DeepCollectionEquality().equals(props, other.props);\n  }\n\n  @override\n  int get hashCode {\n    return runtimeType.hashCode ^ const DeepCollectionEquality().hash(props);\n  }\n}\n\nconst int _hashMask = 0x7fffffff;\n\n/// A generic equality relation on objects.\nabstract class IEquality<E> {\n  const factory IEquality() = DefaultEquality<E>;\n\n  /// Compare two elements for being equal.\n  ///\n  /// This should be a proper equality relation.\n  bool equals(E e1, E e2);\n\n  /// Get a hashcode of an element.\n  ///\n  /// The hashcode should be compatible with [equals], so that if\n  /// `equals(a, b)` then `hash(a) == hash(b)`.\n  int hash(E e);\n\n  /// Test whether an object is a valid argument to [equals] and [hash].\n  ///\n  /// Some implementations may be restricted to only work on specific types\n  /// of objects.\n  bool isValidKey(Object? o);\n}\n\nclass DefaultEquality<E> implements IEquality<E> {\n  const DefaultEquality();\n  @override\n  bool equals(Object? e1, Object? e2) => e1 == e2;\n  @override\n  int hash(Object? e) => e.hashCode;\n  @override\n  bool isValidKey(Object? o) => true;\n}\n\n/// Equality of objects that compares only the identity of the objects.\nclass IdentityEquality<E> implements IEquality<E> {\n  const IdentityEquality();\n  @override\n  bool equals(E e1, E e2) => identical(e1, e2);\n  @override\n  int hash(E e) => identityHashCode(e);\n  @override\n  bool isValidKey(Object? o) => true;\n}\n\nclass DeepCollectionEquality implements IEquality {\n  final IEquality _base = const DefaultEquality<Never>();\n  final bool _unordered = false;\n  const DeepCollectionEquality();\n\n  @override\n  bool equals(e1, e2) {\n    if (e1 is Set) {\n      return e2 is Set && SetEquality(this).equals(e1, e2);\n    }\n    if (e1 is Map) {\n      return e2 is Map && MapEquality(keys: this, values: this).equals(e1, e2);\n    }\n\n    if (e1 is List) {\n      return e2 is List && ListEquality(this).equals(e1, e2);\n    }\n    if (e1 is Iterable) {\n      return e2 is Iterable && IterableEquality(this).equals(e1, e2);\n    }\n\n    return _base.equals(e1, e2);\n  }\n\n  @override\n  int hash(Object? o) {\n    if (o is Set) return SetEquality(this).hash(o);\n    if (o is Map) return MapEquality(keys: this, values: this).hash(o);\n    if (!_unordered) {\n      if (o is List) return ListEquality(this).hash(o);\n      if (o is Iterable) return IterableEquality(this).hash(o);\n    } else if (o is Iterable) {\n      return UnorderedIterableEquality(this).hash(o);\n    }\n    return _base.hash(o);\n  }\n\n  @override\n  bool isValidKey(Object? o) =>\n      o is Iterable || o is Map || _base.isValidKey(o);\n}\n\n/// Equality on lists.\n///\n/// Two lists are equal if they have the same length and their elements\n/// at each index are equal.\nclass ListEquality<E> implements IEquality<List<E>> {\n  final IEquality<E> _elementEquality;\n  const ListEquality(\n      [IEquality<E> elementEquality = const DefaultEquality<Never>()])\n      : _elementEquality = elementEquality;\n\n  @override\n  bool equals(List<E>? list1, List<E>? list2) {\n    if (identical(list1, list2)) return true;\n    if (list1 == null || list2 == null) return false;\n    var length = list1.length;\n    if (length != list2.length) return false;\n    for (var i = 0; i < length; i++) {\n      if (!_elementEquality.equals(list1[i], list2[i])) return false;\n    }\n    return true;\n  }\n\n  @override\n  int hash(List<E>? list) {\n    if (list == null) return null.hashCode;\n    // Jenkins's one-at-a-time hash function.\n    // This code is almost identical to the one in IterableEquality, except\n    // that it uses indexing instead of iterating to get the elements.\n    var hash = 0;\n    for (var i = 0; i < list.length; i++) {\n      var c = _elementEquality.hash(list[i]);\n      hash = (hash + c) & _hashMask;\n      hash = (hash + (hash << 10)) & _hashMask;\n      hash ^= (hash >> 6);\n    }\n    hash = (hash + (hash << 3)) & _hashMask;\n    hash ^= (hash >> 11);\n    hash = (hash + (hash << 15)) & _hashMask;\n    return hash;\n  }\n\n  @override\n  bool isValidKey(Object? o) => o is List<E>;\n}\n\n/// Equality on maps.\n///\n/// Two maps are equal if they have the same number of entries, and if the\n/// entries of the two maps are pairwise equal on both key and value.\nclass MapEquality<K, V> implements IEquality<Map<K, V>> {\n  final IEquality<K> _keyEquality;\n  final IEquality<V> _valueEquality;\n  const MapEquality(\n      {IEquality<K> keys = const DefaultEquality<Never>(),\n      IEquality<V> values = const DefaultEquality<Never>()})\n      : _keyEquality = keys,\n        _valueEquality = values;\n\n  @override\n  bool equals(Map<K, V>? map1, Map<K, V>? map2) {\n    if (identical(map1, map2)) return true;\n    if (map1 == null || map2 == null) return false;\n    var length = map1.length;\n    if (length != map2.length) return false;\n    Map<_MapEntry, int> equalElementCounts = HashMap();\n    for (var key in map1.keys) {\n      var entry = _MapEntry(this, key, map1[key]);\n      var count = equalElementCounts[entry] ?? 0;\n      equalElementCounts[entry] = count + 1;\n    }\n    for (var key in map2.keys) {\n      var entry = _MapEntry(this, key, map2[key]);\n      var count = equalElementCounts[entry];\n      if (count == null || count == 0) return false;\n      equalElementCounts[entry] = count - 1;\n    }\n    return true;\n  }\n\n  @override\n  int hash(Map<K, V>? map) {\n    if (map == null) return null.hashCode;\n    var hash = 0;\n    for (var key in map.keys) {\n      var keyHash = _keyEquality.hash(key);\n      var valueHash = _valueEquality.hash(map[key] as V);\n      hash = (hash + 3 * keyHash + 7 * valueHash) & _hashMask;\n    }\n    hash = (hash + (hash << 3)) & _hashMask;\n    hash ^= (hash >> 11);\n    hash = (hash + (hash << 15)) & _hashMask;\n    return hash;\n  }\n\n  @override\n  bool isValidKey(Object? o) => o is Map<K, V>;\n}\n\nclass _MapEntry {\n  final MapEquality equality;\n  final Object? key;\n  final Object? value;\n  _MapEntry(this.equality, this.key, this.value);\n\n  @override\n  int get hashCode =>\n      (3 * equality._keyEquality.hash(key) +\n          7 * equality._valueEquality.hash(value)) &\n      _hashMask;\n\n  @override\n  bool operator ==(Object other) =>\n      other is _MapEntry &&\n      equality._keyEquality.equals(key, other.key) &&\n      equality._valueEquality.equals(value, other.value);\n}\n\n/// Equality on iterables.\n///\n/// Two iterables are equal if they have the same elements in the same order.\nclass IterableEquality<E> implements IEquality<Iterable<E>> {\n  final IEquality<E?> _elementEquality;\n  const IterableEquality(\n      [IEquality<E> elementEquality = const DefaultEquality<Never>()])\n      : _elementEquality = elementEquality;\n\n  @override\n  bool equals(Iterable<E>? elements1, Iterable<E>? elements2) {\n    if (identical(elements1, elements2)) return true;\n    if (elements1 == null || elements2 == null) return false;\n    var it1 = elements1.iterator;\n    var it2 = elements2.iterator;\n    while (true) {\n      var hasNext = it1.moveNext();\n      if (hasNext != it2.moveNext()) return false;\n      if (!hasNext) return true;\n      if (!_elementEquality.equals(it1.current, it2.current)) return false;\n    }\n  }\n\n  @override\n  int hash(Iterable<E>? elements) {\n    if (elements == null) return null.hashCode;\n    // Jenkins's one-at-a-time hash function.\n    var hash = 0;\n    for (var element in elements) {\n      var c = _elementEquality.hash(element);\n      hash = (hash + c) & _hashMask;\n      hash = (hash + (hash << 10)) & _hashMask;\n      hash ^= (hash >> 6);\n    }\n    hash = (hash + (hash << 3)) & _hashMask;\n    hash ^= (hash >> 11);\n    hash = (hash + (hash << 15)) & _hashMask;\n    return hash;\n  }\n\n  @override\n  bool isValidKey(Object? o) => o is Iterable<E>;\n}\n\n/// Equality of sets.\n///\n/// Two sets are considered equal if they have the same number of elements,\n/// and the elements of one set can be paired with the elements\n/// of the other set, so that each pair are equal.\nclass SetEquality<E> extends _UnorderedEquality<E, Set<E>> {\n  const SetEquality([super.elementEquality = const DefaultEquality<Never>()]);\n\n  @override\n  bool isValidKey(Object? o) => o is Set<E>;\n}\n\nabstract class _UnorderedEquality<E, T extends Iterable<E>>\n    implements IEquality<T> {\n  final IEquality<E> _elementEquality;\n\n  const _UnorderedEquality(this._elementEquality);\n\n  @override\n  bool equals(T? elements1, T? elements2) {\n    if (identical(elements1, elements2)) return true;\n    if (elements1 == null || elements2 == null) return false;\n    var counts = HashMap<E, int>(\n        equals: _elementEquality.equals,\n        hashCode: _elementEquality.hash,\n        isValidKey: _elementEquality.isValidKey);\n    var length = 0;\n    for (var e in elements1) {\n      var count = counts[e] ?? 0;\n      counts[e] = count + 1;\n      length++;\n    }\n    for (var e in elements2) {\n      var count = counts[e];\n      if (count == null || count == 0) return false;\n      counts[e] = count - 1;\n      length--;\n    }\n    return length == 0;\n  }\n\n  @override\n  int hash(T? elements) {\n    if (elements == null) return null.hashCode;\n    var hash = 0;\n    for (E element in elements) {\n      var c = _elementEquality.hash(element);\n      hash = (hash + c) & _hashMask;\n    }\n    hash = (hash + (hash << 3)) & _hashMask;\n    hash ^= (hash >> 11);\n    hash = (hash + (hash << 15)) & _hashMask;\n    return hash;\n  }\n}\n\n/// Equality of the elements of two iterables without considering order.\n///\n/// Two iterables are considered equal if they have the same number of elements,\n/// and the elements of one set can be paired with the elements\n/// of the other iterable, so that each pair are equal.\nclass UnorderedIterableEquality<E> extends _UnorderedEquality<E, Iterable<E>> {\n  const UnorderedIterableEquality(\n      [super.elementEquality = const DefaultEquality<Never>()]);\n\n  @override\n  bool isValidKey(Object? o) => o is Iterable<E>;\n}\n"
  },
  {
    "path": "lib/get_utils/src/extensions/context_extensions.dart",
    "content": "import 'package:flutter/material.dart';\n\nextension ContextExt on BuildContext {\n  /// The same of [MediaQuery.sizeOf(context)]\n  Size get mediaQuerySize => MediaQuery.sizeOf(this);\n\n  /// The same of [MediaQuery.of(context).size.height]\n  /// Note: updates when you resize your screen (like on a browser or\n  /// desktop window)\n  double get height => mediaQuerySize.height;\n\n  /// The same of [MediaQuery.of(context).size.width]\n  /// Note: updates when you resize your screen (like on a browser or\n  /// desktop window)\n  double get width => mediaQuerySize.width;\n\n  /// Gives you the power to get a portion of the height.\n  /// Useful for responsive applications.\n  ///\n  /// [dividedBy] is for when you want to have a portion of the value you\n  /// would get like for example: if you want a value that represents a third\n  /// of the screen you can set it to 3, and you will get a third of the height\n  ///\n  /// [reducedBy] is a percentage value of how much of the height you want\n  /// if you for example want 46% of the height, then you reduce it by 56%.\n  double heightTransformer({double dividedBy = 1, double reducedBy = 0.0}) {\n    return (mediaQuerySize.height -\n            ((mediaQuerySize.height / 100) * reducedBy)) /\n        dividedBy;\n  }\n\n  /// Gives you the power to get a portion of the width.\n  /// Useful for responsive applications.\n  ///\n  /// [dividedBy] is for when you want to have a portion of the value you\n  /// would get like for example: if you want a value that represents a third\n  /// of the screen you can set it to 3, and you will get a third of the width\n  ///\n  /// [reducedBy] is a percentage value of how much of the width you want\n  /// if you for example want 46% of the width, then you reduce it by 56%.\n  double widthTransformer({double dividedBy = 1, double reducedBy = 0.0}) {\n    return (mediaQuerySize.width - ((mediaQuerySize.width / 100) * reducedBy)) /\n        dividedBy;\n  }\n\n  /// Divide the height proportionally by the given value\n  double ratio({\n    double dividedBy = 1,\n    double reducedByW = 0.0,\n    double reducedByH = 0.0,\n  }) {\n    return heightTransformer(dividedBy: dividedBy, reducedBy: reducedByH) /\n        widthTransformer(dividedBy: dividedBy, reducedBy: reducedByW);\n  }\n\n  /// similar to [MediaQuery.of(context).padding]\n  ThemeData get theme => Theme.of(this);\n\n  /// Check if dark mode theme is enable\n  bool get isDarkMode => (theme.brightness == Brightness.dark);\n\n  /// give access to Theme.of(context).iconTheme.color\n  Color? get iconColor => theme.iconTheme.color;\n\n  /// similar to [MediaQuery.of(context).padding]\n  TextTheme get textTheme => Theme.of(this).textTheme;\n\n  /// similar to [MediaQuery.paddingOf(context)]\n  EdgeInsets get mediaQueryPadding => MediaQuery.paddingOf(this);\n\n  /// similar to [MediaQuery.of(context).padding]\n  MediaQueryData get mediaQuery => MediaQuery.of(this);\n\n  /// similar to [MediaQuery.viewPaddingOf(context)]\n  EdgeInsets get mediaQueryViewPadding => MediaQuery.viewPaddingOf(this);\n\n  /// similar to [MediaQuery.viewInsetsOf(context)]\n  EdgeInsets get mediaQueryViewInsets => MediaQuery.viewInsetsOf(this);\n\n  /// similar to [MediaQuery.orientationOf(context)]\n  Orientation get orientation => MediaQuery.orientationOf(this);\n\n  /// check if device is on landscape mode\n  bool get isLandscape => orientation == Orientation.landscape;\n\n  /// check if device is on portrait mode\n  bool get isPortrait => orientation == Orientation.portrait;\n\n  /// similar to [MediaQuery.devicePixelRatioOf(context)]\n  double get devicePixelRatio => MediaQuery.devicePixelRatioOf(this);\n\n  /// similar to [MediaQuery.textScaleFactorOf(context)]\n  TextScaler get textScaleFactor => MediaQuery.textScalerOf(this);\n\n  /// get the shortestSide from screen\n  double get mediaQueryShortestSide => mediaQuerySize.shortestSide;\n\n  /// True if width be larger than 800\n  bool get showNavbar => (width > 800);\n\n  /// True if the width is smaller than 600p\n  bool get isPhoneOrLess => width <= 600;\n\n  /// True if the width is higher than 600p\n  bool get isPhoneOrWider => width >= 600;\n\n  /// True if the shortestSide is smaller than 600p\n  bool get isPhone => (mediaQueryShortestSide < 600);\n\n  /// True if the width is smaller than 600p\n  bool get isSmallTabletOrLess => width <= 600;\n\n  /// True if the width is higher than 600p\n  bool get isSmallTabletOrWider => width >= 600;\n\n  /// True if the shortestSide is largest than 600p\n  bool get isSmallTablet => (mediaQueryShortestSide >= 600);\n\n  /// True if the shortestSide is largest than 720p\n  bool get isLargeTablet => (mediaQueryShortestSide >= 720);\n\n  /// True if the width is smaller than 720p\n  bool get isLargeTabletOrLess => width <= 720;\n\n  /// True if the width is higher than 720p\n  bool get isLargeTabletOrWider => width >= 720;\n\n  /// True if the current device is Tablet\n  bool get isTablet => isSmallTablet || isLargeTablet;\n\n  /// True if the width is smaller than 1200p\n  bool get isDesktopOrLess => width <= 1200;\n\n  /// True if the width is higher than 1200p\n  bool get isDesktopOrWider => width >= 1200;\n\n  /// same as [isDesktopOrLess]\n  bool get isDesktop => isDesktopOrLess;\n\n  /// Returns a specific value according to the screen size\n  /// if the device width is higher than or equal to 1200 return\n  /// [desktop] value. if the device width is higher than  or equal to 600\n  /// and less than 1200 return [tablet] value.\n  /// if the device width is less than 300  return [watch] value.\n  /// in other cases return [mobile] value.\n  T responsiveValue<T>({\n    T? watch,\n    T? mobile,\n    T? tablet,\n    T? desktop,\n  }) {\n    assert(\n        watch != null || mobile != null || tablet != null || desktop != null);\n\n    var deviceWidth = mediaQuerySize.width;\n    //big screen width can display smaller sizes\n    final strictValues = [\n      if (deviceWidth >= 1200) desktop, //desktop is allowed\n      if (deviceWidth >= 600) tablet, //tablet is allowed\n      if (deviceWidth >= 300) mobile, //mobile is allowed\n      watch, //watch is allowed\n    ].whereType<T>();\n    final looseValues = [\n      watch,\n      mobile,\n      tablet,\n      desktop,\n    ].whereType<T>();\n    return strictValues.firstOrNull ?? looseValues.first;\n  }\n}\n\nextension IterableExt<T> on Iterable<T> {\n  /// The first element, or `null` if the iterable is empty.\n  T? get firstOrNull {\n    var iterator = this.iterator;\n    if (iterator.moveNext()) return iterator.current;\n    return null;\n  }\n}\n"
  },
  {
    "path": "lib/get_utils/src/extensions/double_extensions.dart",
    "content": "import 'dart:math';\n\nextension DoubleExt on double {\n  double toPrecision(int fractionDigits) {\n    var mod = pow(10, fractionDigits.toDouble()).toDouble();\n    return ((this * mod).round().toDouble() / mod);\n  }\n\n  Duration get milliseconds => Duration(microseconds: (this * 1000).round());\n\n  Duration get ms => milliseconds;\n\n  Duration get seconds => Duration(milliseconds: (this * 1000).round());\n\n  Duration get minutes =>\n      Duration(seconds: (this * Duration.secondsPerMinute).round());\n\n  Duration get hours =>\n      Duration(minutes: (this * Duration.minutesPerHour).round());\n\n  Duration get days => Duration(hours: (this * Duration.hoursPerDay).round());\n}\n"
  },
  {
    "path": "lib/get_utils/src/extensions/duration_extensions.dart",
    "content": "import 'dart:async';\n\n/// Duration utilities.\nextension GetDurationUtils on Duration {\n  /// Utility to delay some callback (or code execution).\n  ///\n  /// Sample:\n  /// ```\n  /// void main() async {\n  ///   final _delay = 3.seconds;\n  ///   print('+ wait $_delay');\n  ///   await _delay.delay();\n  ///   print('- finish wait $_delay');\n  ///   print('+ callback in 700ms');\n  ///   await 0.7.seconds.delay(() {\n  /// }\n  ///```\n  Future delay([FutureOr Function()? callback]) async =>\n      Future.delayed(this, callback);\n}\n"
  },
  {
    "path": "lib/get_utils/src/extensions/dynamic_extensions.dart",
    "content": "import '../get_utils/get_utils.dart';\n\nextension GetDynamicUtils on dynamic {\n  bool? get isBlank => GetUtils.isBlank(this);\n\n  void printError(\n          {String info = '', Function logFunction = GetUtils.printFunction}) =>\n      // ignore: unnecessary_this\n      logFunction('Error: ${this.runtimeType}', this, info, isError: true);\n\n  void printInfo(\n          {String info = '',\n          Function printFunction = GetUtils.printFunction}) =>\n      // ignore: unnecessary_this\n      printFunction('Info: ${this.runtimeType}', this, info);\n}\n"
  },
  {
    "path": "lib/get_utils/src/extensions/event_loop_extensions.dart",
    "content": "import 'dart:async';\n\nimport '../../../get_core/src/get_interface.dart';\n\nextension LoopEventsExt on GetInterface {\n  Future<T> toEnd<T>(FutureOr<T> Function() computation) async {\n    await Future.delayed(Duration.zero);\n    final val = computation();\n    return val;\n  }\n\n  FutureOr<T> asap<T>(T Function() computation,\n      {bool Function()? condition}) async {\n    T val;\n    if (condition == null || !condition()) {\n      await Future.delayed(Duration.zero);\n      val = computation();\n    } else {\n      val = computation();\n    }\n    return val;\n  }\n}\n"
  },
  {
    "path": "lib/get_utils/src/extensions/export.dart",
    "content": "export 'context_extensions.dart';\r\nexport 'double_extensions.dart';\r\nexport 'duration_extensions.dart';\r\nexport 'dynamic_extensions.dart';\r\nexport 'event_loop_extensions.dart';\r\nexport 'int_extensions.dart';\r\nexport 'internacionalization.dart' hide FirstWhereExt;\r\nexport 'iterable_extensions.dart';\r\nexport 'num_extensions.dart';\r\nexport 'string_extensions.dart';\r\nexport 'widget_extensions.dart';\r\n"
  },
  {
    "path": "lib/get_utils/src/extensions/int_extensions.dart",
    "content": "extension DurationExt on int {\n  Duration get seconds => Duration(seconds: this);\n\n  Duration get days => Duration(days: this);\n\n  Duration get hours => Duration(hours: this);\n\n  Duration get minutes => Duration(minutes: this);\n\n  Duration get milliseconds => Duration(milliseconds: this);\n\n  Duration get microseconds => Duration(microseconds: this);\n\n  Duration get ms => milliseconds;\n}\n"
  },
  {
    "path": "lib/get_utils/src/extensions/internacionalization.dart",
    "content": "import 'dart:ui';\n\nimport '../../../get_core/get_core.dart';\n\nclass _IntlHost {\n  Locale? locale;\n\n  Locale? fallbackLocale;\n\n  Map<String, Map<String, String>> translations = {};\n}\n\nextension FirstWhereExt<T> on List<T> {\n  /// The first element satisfying [test], or `null` if there are none.\n  T? firstWhereOrNull(bool Function(T element) test) {\n    for (var element in this) {\n      if (test(element)) return element;\n    }\n    return null;\n  }\n}\n\nextension LocalesIntl on GetInterface {\n  static final _intlHost = _IntlHost();\n\n  Locale? get locale => _intlHost.locale;\n\n  Locale? get fallbackLocale => _intlHost.fallbackLocale;\n\n  set locale(Locale? newLocale) => _intlHost.locale = newLocale;\n\n  set fallbackLocale(Locale? newLocale) => _intlHost.fallbackLocale = newLocale;\n\n  Map<String, Map<String, String>> get translations => _intlHost.translations;\n\n  void addTranslations(Map<String, Map<String, String>> tr) {\n    translations.addAll(tr);\n  }\n\n  void clearTranslations() {\n    translations.clear();\n  }\n\n  void appendTranslations(Map<String, Map<String, String>> tr) {\n    tr.forEach((key, map) {\n      if (translations.containsKey(key)) {\n        translations[key]!.addAll(map);\n      } else {\n        translations[key] = map;\n      }\n    });\n  }\n}\n\nextension Trans on String {\n  // Checks whether the language code and country code are present, and\n  // whether the key is also present.\n  bool get _fullLocaleAndKey {\n    return Get.translations.containsKey(\n            \"${Get.locale!.languageCode}_${Get.locale!.countryCode}\") &&\n        Get.translations[\n                \"${Get.locale!.languageCode}_${Get.locale!.countryCode}\"]!\n            .containsKey(this);\n  }\n\n  // Checks if there is a callback language in the absence of the specific\n  // country, and if it contains that key.\n  Map<String, String>? get _getSimilarLanguageTranslation {\n    final translationsWithNoCountry = Get.translations\n        .map((key, value) => MapEntry(key.split(\"_\").first, value));\n    final containsKey = translationsWithNoCountry\n        .containsKey(Get.locale!.languageCode.split(\"_\").first);\n\n    if (!containsKey) {\n      return null;\n    }\n\n    return translationsWithNoCountry[Get.locale!.languageCode.split(\"_\").first];\n  }\n\n  String get tr {\n    // print('language');\n    // print(Get.locale!.languageCode);\n    // print('contains');\n    // print(Get.translations.containsKey(Get.locale!.languageCode));\n    // print(Get.translations.keys);\n    // Returns the key if locale is null.\n    if (Get.locale?.languageCode == null) return this;\n\n    if (_fullLocaleAndKey) {\n      return Get.translations[\n          \"${Get.locale!.languageCode}_${Get.locale!.countryCode}\"]![this]!;\n    }\n    final similarTranslation = _getSimilarLanguageTranslation;\n    if (similarTranslation != null && similarTranslation.containsKey(this)) {\n      return similarTranslation[this]!;\n      // If there is no corresponding language or corresponding key, return\n      // the key.\n    } else if (Get.fallbackLocale != null) {\n      final fallback = Get.fallbackLocale!;\n      final key = \"${fallback.languageCode}_${fallback.countryCode}\";\n\n      if (Get.translations.containsKey(key) &&\n          Get.translations[key]!.containsKey(this)) {\n        return Get.translations[key]![this]!;\n      }\n      if (Get.translations.containsKey(fallback.languageCode) &&\n          Get.translations[fallback.languageCode]!.containsKey(this)) {\n        return Get.translations[fallback.languageCode]![this]!;\n      }\n      return this;\n    } else {\n      return this;\n    }\n  }\n\n  String trArgs([List<String> args = const []]) {\n    var key = tr;\n    if (args.isNotEmpty) {\n      for (final arg in args) {\n        key = key.replaceFirst(RegExp(r'%s'), arg.toString());\n      }\n    }\n    return key;\n  }\n\n  String trPlural([String? pluralKey, int? i, List<String> args = const []]) {\n    return i == 1 ? trArgs(args) : pluralKey!.trArgs(args);\n  }\n\n  String trParams([Map<String, String> params = const {}]) {\n    var trans = tr;\n    if (params.isNotEmpty) {\n      params.forEach((key, value) {\n        trans = trans.replaceAll('@$key', value);\n      });\n    }\n    return trans;\n  }\n\n  String trPluralParams(\n      [String? pluralKey, int? i, Map<String, String> params = const {}]) {\n    return i == 1 ? trParams(params) : pluralKey!.trParams(params);\n  }\n}\n"
  },
  {
    "path": "lib/get_utils/src/extensions/iterable_extensions.dart",
    "content": "extension IterableExtensions<T> on Iterable<T> {\r\n  Iterable<TRes> mapMany<TRes>(\r\n      Iterable<TRes>? Function(T item) selector) sync* {\r\n    for (var item in this) {\r\n      final res = selector(item);\r\n      if (res != null) yield* res;\r\n    }\r\n  }\r\n}\r\n"
  },
  {
    "path": "lib/get_utils/src/extensions/num_extensions.dart",
    "content": "import 'dart:async';\n\nimport '../get_utils/get_utils.dart';\n\nextension GetNumUtils on num {\n  bool isLowerThan(num b) => GetUtils.isLowerThan(this, b);\n\n  bool isGreaterThan(num b) => GetUtils.isGreaterThan(this, b);\n\n  bool isEqual(num b) => GetUtils.isEqual(this, b);\n\n  /// Utility to delay some callback (or code execution).\n  /// TODO: Add a separated implementation of delay() with the ability\n  /// to stop it.\n  ///\n  /// Sample:\n  /// ```\n  /// void main() async {\n  ///   print('+ wait for 2 seconds');\n  ///   await 2.delay();\n  ///   print('- 2 seconds completed');\n  ///   print('+ callback in 1.2sec');\n  ///   1.delay(() => print('- 1.2sec callback called'));\n  ///   print('currently running callback 1.2sec');\n  /// }\n  ///```\n  Future delay([FutureOr Function()? callback]) async => Future.delayed(\n        Duration(milliseconds: (this * 1000).round()),\n        callback,\n      );\n}\n"
  },
  {
    "path": "lib/get_utils/src/extensions/string_extensions.dart",
    "content": "import '../get_utils/get_utils.dart';\n\nextension GetStringUtils on String {\n  /// Discover if the String is a valid number\n  bool get isNum => GetUtils.isNum(this);\n\n  /// Discover if the String is numeric only\n  bool get isNumericOnly => GetUtils.isNumericOnly(this);\n\n  String numericOnly({bool firstWordOnly = false}) =>\n      GetUtils.numericOnly(this, firstWordOnly: firstWordOnly);\n\n  /// Discover if the String is alphanumeric only\n  bool get isAlphabetOnly => GetUtils.isAlphabetOnly(this);\n\n  /// Discover if the String is a boolean\n  bool get isBool => GetUtils.isBool(this);\n\n  /// Discover if the String is a vector\n  bool get isVectorFileName => GetUtils.isVector(this);\n\n  /// Discover if the String is a ImageFileName\n  bool get isImageFileName => GetUtils.isImage(this);\n\n  /// Discover if the String is a AudioFileName\n  bool get isAudioFileName => GetUtils.isAudio(this);\n\n  /// Discover if the String is a VideoFileName\n  bool get isVideoFileName => GetUtils.isVideo(this);\n\n  /// Discover if the String is a TxtFileName\n  bool get isTxtFileName => GetUtils.isTxt(this);\n\n  /// Discover if the String is a Document Word\n  bool get isDocumentFileName => GetUtils.isWord(this);\n\n  /// Discover if the String is a Document Excel\n  bool get isExcelFileName => GetUtils.isExcel(this);\n\n  /// Discover if the String is a Document Powerpoint\n  bool get isPPTFileName => GetUtils.isPPT(this);\n\n  /// Discover if the String is a APK File\n  bool get isAPKFileName => GetUtils.isAPK(this);\n\n  /// Discover if the String is a PDF file\n  bool get isPDFFileName => GetUtils.isPDF(this);\n\n  /// Discover if the String is a HTML file\n  bool get isHTMLFileName => GetUtils.isHTML(this);\n\n  /// Discover if the String is a URL file\n  bool get isURL => GetUtils.isURL(this);\n\n  /// Discover if the String is a Email\n  bool get isEmail => GetUtils.isEmail(this);\n\n  /// Discover if the String is a Phone Number\n  bool get isPhoneNumber => GetUtils.isPhoneNumber(this);\n\n  /// Discover if the String is a DateTime\n  bool get isDateTime => GetUtils.isDateTime(this);\n\n  /// Discover if the String is a MD5 Hash\n  bool get isMD5 => GetUtils.isMD5(this);\n\n  /// Discover if the String is a SHA1 Hash\n  bool get isSHA1 => GetUtils.isSHA1(this);\n\n  /// Discover if the String is a SHA256 Hash\n  bool get isSHA256 => GetUtils.isSHA256(this);\n\n  /// Discover if the String is a binary value\n  bool get isBinary => GetUtils.isBinary(this);\n\n  /// Discover if the String is a ipv4\n  bool get isIPv4 => GetUtils.isIPv4(this);\n\n  bool get isIPv6 => GetUtils.isIPv6(this);\n\n  /// Discover if the String is a Hexadecimal\n  bool get isHexadecimal => GetUtils.isHexadecimal(this);\n\n  /// Discover if the String is a palindrome\n  bool get isPalindrome => GetUtils.isPalindrome(this);\n\n  /// Discover if the String is a passport number\n  bool get isPassport => GetUtils.isPassport(this);\n\n  /// Discover if the String is a currency\n  bool get isCurrency => GetUtils.isCurrency(this);\n\n  /// Discover if the String is a CPF number\n  bool get isCpf => GetUtils.isCpf(this);\n\n  /// Discover if the String is a CNPJ number\n  bool get isCnpj => GetUtils.isCnpj(this);\n\n  /// Discover if the String is a case insensitive\n  bool isCaseInsensitiveContains(String b) =>\n      GetUtils.isCaseInsensitiveContains(this, b);\n\n  /// Discover if the String is a case sensitive and contains any value\n  bool isCaseInsensitiveContainsAny(String b) =>\n      GetUtils.isCaseInsensitiveContainsAny(this, b);\n\n  /// capitalize the String\n  String get capitalize => GetUtils.capitalize(this);\n\n  /// Capitalize the first letter of the String\n  String get capitalizeFirst => GetUtils.capitalizeFirst(this);\n\n  /// remove all whitespace from the String\n  String get removeAllWhitespace => GetUtils.removeAllWhitespace(this);\n\n  /// converter the String\n  String? get camelCase => GetUtils.camelCase(this);\n\n  /// Discover if the String is a valid URL\n  String? get paramCase => GetUtils.paramCase(this);\n\n  /// add segments to the String\n  String createPath([Iterable? segments]) {\n    final path = startsWith('/') ? this : '/$this';\n    return GetUtils.createPath(path, segments);\n  }\n\n  /// capitalize only first letter in String words to upper case\n  String capitalizeAllWordsFirstLetter() =>\n      GetUtils.capitalizeAllWordsFirstLetter(this);\n}\n"
  },
  {
    "path": "lib/get_utils/src/extensions/widget_extensions.dart",
    "content": "import 'package:flutter/widgets.dart';\n\n/// add Padding Property to widget\nextension WidgetPaddingX on Widget {\n  Widget paddingAll(double padding) =>\n      Padding(padding: EdgeInsets.all(padding), child: this);\n\n  Widget paddingSymmetric({double horizontal = 0.0, double vertical = 0.0}) =>\n      Padding(\n          padding:\n              EdgeInsets.symmetric(horizontal: horizontal, vertical: vertical),\n          child: this);\n\n  Widget paddingOnly({\n    double left = 0.0,\n    double top = 0.0,\n    double right = 0.0,\n    double bottom = 0.0,\n  }) =>\n      Padding(\n          padding: EdgeInsets.only(\n              top: top, left: left, right: right, bottom: bottom),\n          child: this);\n\n  Widget get paddingZero => Padding(padding: EdgeInsets.zero, child: this);\n}\n\n/// Add margin property to widget\nextension WidgetMarginX on Widget {\n  Widget marginAll(double margin) =>\n      Container(margin: EdgeInsets.all(margin), child: this);\n\n  Widget marginSymmetric({double horizontal = 0.0, double vertical = 0.0}) =>\n      Container(\n          margin:\n              EdgeInsets.symmetric(horizontal: horizontal, vertical: vertical),\n          child: this);\n\n  Widget marginOnly({\n    double left = 0.0,\n    double top = 0.0,\n    double right = 0.0,\n    double bottom = 0.0,\n  }) =>\n      Container(\n          margin: EdgeInsets.only(\n              top: top, left: left, right: right, bottom: bottom),\n          child: this);\n\n  Widget get marginZero => Container(margin: EdgeInsets.zero, child: this);\n}\n\n/// Allows you to insert widgets inside a CustomScrollView\nextension WidgetSliverBoxX on Widget {\n  Widget get sliverBox => SliverToBoxAdapter(child: this);\n}\n"
  },
  {
    "path": "lib/get_utils/src/get_utils/get_utils.dart",
    "content": "import '../../../get_core/get_core.dart';\n\n/// Returns whether a dynamic value PROBABLY\n/// has the isEmpty getter/method by checking\n/// standard dart types that contains it.\n///\n/// This is here to for the 'DRY'\nbool? _isEmpty(dynamic value) {\n  if (value is String) {\n    return value.toString().trim().isEmpty;\n  }\n  if (value is Iterable || value is Map) {\n    return value.isEmpty as bool?;\n  }\n  return false;\n}\n\n/// Returns whether a dynamic value PROBABLY\n/// has the length getter/method by checking\n/// standard dart types that contains it.\n///\n/// This is here to for the 'DRY'\nbool _hasLength(dynamic value) {\n  return value is Iterable || value is String || value is Map;\n}\n\n/// Obtains a length of a dynamic value\n/// by previously validating it's type\n///\n/// Note: if [value] is double/int\n/// it will be taking the .toString\n/// length of the given value.\n///\n/// Note 2: **this may return null!**\n///\n/// Note 3: null [value] returns null.\nint? _obtainDynamicLength(dynamic value) {\n  if (value == null) {\n    // ignore: avoid_returning_null\n    return null;\n  }\n\n  if (_hasLength(value)) {\n    return value.length as int?;\n  }\n\n  if (value is int) {\n    return value.toString().length;\n  }\n\n  if (value is double) {\n    return value.toString().replaceAll('.', '').length;\n  }\n\n  // ignore: avoid_returning_null\n  return null;\n}\n\nclass GetUtils {\n  GetUtils._();\n\n  /// Checks if data is null.\n  static bool isNull(dynamic value) => value == null;\n\n  /// In dart2js (in flutter v1.17) a var by default is undefined.\n  /// *Use this only if you are in version <- 1.17*.\n  /// So we assure the null type in json conversions to avoid the\n  /// \"value\":value==null?null:value; someVar.nil will force the null type\n  /// if the var is null or undefined.\n  /// `nil` taken from ObjC just to have a shorter syntax.\n  static dynamic nil(dynamic s) => s;\n\n  /// Checks if data is null or blank (empty or only contains whitespace).\n  static bool? isNullOrBlank(dynamic value) {\n    if (isNull(value)) {\n      return true;\n    }\n\n    // Pretty sure that isNullOrBlank should't be validating\n    // iterables... but I'm going to keep this for compatibility.\n    return _isEmpty(value);\n  }\n\n  /// Checks if data is null or blank (empty or only contains whitespace).\n  static bool? isBlank(dynamic value) {\n    return _isEmpty(value);\n  }\n\n  /// Checks if string is int or double.\n  static bool isNum(String value) {\n    if (isNull(value)) {\n      return false;\n    }\n\n    return num.tryParse(value) is num;\n  }\n\n  /// Checks if string consist only numeric.\n  /// Numeric only doesn't accepting \".\" which double data type have\n  static bool isNumericOnly(String s) => hasMatch(s, r'^\\d+$');\n\n  /// Checks if string consist only Alphabet. (No Whitespace)\n  static bool isAlphabetOnly(String s) => hasMatch(s, r'^[a-zA-Z]+$');\n\n  /// Checks if string contains at least one Capital Letter\n  static bool hasCapitalLetter(String s) => hasMatch(s, r'[A-Z]');\n\n  /// Checks if string is boolean.\n  static bool isBool(String value) {\n    if (isNull(value)) {\n      return false;\n    }\n\n    return (value == 'true' || value == 'false');\n  }\n\n  /// Checks if string is an video file.\n  static bool isVideo(String filePath) {\n    var ext = filePath.toLowerCase();\n\n    return ext.endsWith(\".mp4\") ||\n        ext.endsWith(\".avi\") ||\n        ext.endsWith(\".wmv\") ||\n        ext.endsWith(\".rmvb\") ||\n        ext.endsWith(\".mpg\") ||\n        ext.endsWith(\".mpeg\") ||\n        ext.endsWith(\".3gp\");\n  }\n\n  /// Checks if string is an image file.\n  static bool isImage(String filePath) {\n    final ext = filePath.toLowerCase();\n\n    return ext.endsWith(\".jpg\") ||\n        ext.endsWith(\".jpeg\") ||\n        ext.endsWith(\".png\") ||\n        ext.endsWith(\".gif\") ||\n        ext.endsWith(\".bmp\");\n  }\n\n  /// Checks if string is an audio file.\n  static bool isAudio(String filePath) {\n    final ext = filePath.toLowerCase();\n\n    return ext.endsWith(\".mp3\") ||\n        ext.endsWith(\".wav\") ||\n        ext.endsWith(\".wma\") ||\n        ext.endsWith(\".amr\") ||\n        ext.endsWith(\".ogg\");\n  }\n\n  /// Checks if string is an powerpoint file.\n  static bool isPPT(String filePath) {\n    final ext = filePath.toLowerCase();\n\n    return ext.endsWith(\".ppt\") || ext.endsWith(\".pptx\");\n  }\n\n  /// Checks if string is an word file.\n  static bool isWord(String filePath) {\n    final ext = filePath.toLowerCase();\n\n    return ext.endsWith(\".doc\") || ext.endsWith(\".docx\");\n  }\n\n  /// Checks if string is an excel file.\n  static bool isExcel(String filePath) {\n    final ext = filePath.toLowerCase();\n\n    return ext.endsWith(\".xls\") || ext.endsWith(\".xlsx\");\n  }\n\n  /// Checks if string is an apk file.\n  static bool isAPK(String filePath) {\n    return filePath.toLowerCase().endsWith(\".apk\");\n  }\n\n  /// Checks if string is an pdf file.\n  static bool isPDF(String filePath) {\n    return filePath.toLowerCase().endsWith(\".pdf\");\n  }\n\n  /// Checks if string is an txt file.\n  static bool isTxt(String filePath) {\n    return filePath.toLowerCase().endsWith(\".txt\");\n  }\n\n  /// Checks if string is an chm file.\n  static bool isChm(String filePath) {\n    return filePath.toLowerCase().endsWith(\".chm\");\n  }\n\n  /// Checks if string is a vector file.\n  static bool isVector(String filePath) {\n    return filePath.toLowerCase().endsWith(\".svg\");\n  }\n\n  /// Checks if string is an html file.\n  static bool isHTML(String filePath) {\n    return filePath.toLowerCase().endsWith(\".html\");\n  }\n\n  /// Checks if string is a valid username.\n  static bool isUsername(String s) =>\n      hasMatch(s, r'^[a-zA-Z0-9][a-zA-Z0-9_.]+[a-zA-Z0-9]$');\n\n  /// Checks if string is URL.\n  static bool isURL(String s) => hasMatch(s,\n      r\"^((((H|h)(T|t)|(F|f))(T|t)(P|p)((S|s)?))\\://)?(www.|[a-zA-Z0-9].)[a-zA-Z0-9\\-\\.]+\\.[a-zA-Z]{2,7}(\\:[0-9]{1,5})*(/($|[a-zA-Z0-9\\.\\,\\;\\?\\'\\\\\\+&amp;%\\$#\\=~_\\-]+))*$\");\n\n  /// Checks if string is email.\n  static bool isEmail(String s) => hasMatch(s,\n      r'^(([^<>()[\\]\\\\.,;:\\s@\\\"]+(\\.[^<>()[\\]\\\\.,;:\\s@\\\"]+)*)|(\\\".+\\\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$');\n\n  /// Checks if string is phone number.\n  static bool isPhoneNumber(String s) {\n    if (s.length > 16 || s.length < 9) return false;\n    return hasMatch(s, r'^[+]*[(]{0,1}[0-9]{1,4}[)]{0,1}[-\\s\\./0-9]*$');\n  }\n\n  /// Checks if string is DateTime (UTC or Iso8601).\n  static bool isDateTime(String s) =>\n      hasMatch(s, r'^\\d{4}-\\d{2}-\\d{2}[ T]\\d{2}:\\d{2}:\\d{2}.\\d{3}Z?$');\n\n  /// Checks if string is MD5 hash.\n  static bool isMD5(String s) => hasMatch(s, r'^[a-f0-9]{32}$');\n\n  /// Checks if string is SHA1 hash.\n  static bool isSHA1(String s) =>\n      hasMatch(s, r'(([A-Fa-f0-9]{2}\\:){19}[A-Fa-f0-9]{2}|[A-Fa-f0-9]{40})');\n\n  /// Checks if string is SHA256 hash.\n  static bool isSHA256(String s) =>\n      hasMatch(s, r'([A-Fa-f0-9]{2}\\:){31}[A-Fa-f0-9]{2}|[A-Fa-f0-9]{64}');\n\n  /// Checks if string is SSN (Social Security Number).\n  static bool isSSN(String s) => hasMatch(s,\n      r'^(?!0{3}|6{3}|9[0-9]{2})[0-9]{3}-?(?!0{2})[0-9]{2}-?(?!0{4})[0-9]{4}$');\n\n  /// Checks if string is binary.\n  static bool isBinary(String s) => hasMatch(s, r'^[0-1]+$');\n\n  /// Checks if string is IPv4.\n  static bool isIPv4(String s) =>\n      hasMatch(s, r'^(?:(?:^|\\.)(?:2(?:5[0-5]|[0-4]\\d)|1?\\d?\\d)){4}$');\n\n  /// Checks if string is IPv6.\n  static bool isIPv6(String s) => hasMatch(s,\n      r'^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b)\\.){3}(\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b)\\.){3}(\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b)\\.){3}(\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$');\n\n  /// Checks if string is hexadecimal.\n  /// Example: HexColor => #12F\n  static bool isHexadecimal(String s) =>\n      hasMatch(s, r'^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$');\n\n  /// Checks if string is Palindrome.\n  static bool isPalindrome(String string) {\n    final cleanString = string\n        .toLowerCase()\n        .replaceAll(RegExp(r\"\\s+\"), '')\n        .replaceAll(RegExp(r\"[^0-9a-zA-Z]+\"), \"\");\n\n    for (var i = 0; i < cleanString.length; i++) {\n      if (cleanString[i] != cleanString[cleanString.length - i - 1]) {\n        return false;\n      }\n    }\n\n    return true;\n  }\n\n  /// Checks if all data have same value.\n  /// Example: 111111 -> true, wwwww -> true, 1,1,1,1 -> true\n  static bool isOneAKind(dynamic value) {\n    if ((value is String || value is List) && !isNullOrBlank(value)!) {\n      final first = value[0];\n      final len = value.length as num;\n\n      for (var i = 0; i < len; i++) {\n        if (value[i] != first) {\n          return false;\n        }\n      }\n\n      return true;\n    }\n\n    if (value is int) {\n      final stringValue = value.toString();\n      final first = stringValue[0];\n\n      for (var i = 0; i < stringValue.length; i++) {\n        if (stringValue[i] != first) {\n          return false;\n        }\n      }\n\n      return true;\n    }\n\n    return false;\n  }\n\n  /// Checks if string is Passport No.\n  static bool isPassport(String s) =>\n      hasMatch(s, r'^(?!^0+$)[a-zA-Z0-9]{6,9}$');\n\n  /// Checks if string is Currency.\n  static bool isCurrency(String s) => hasMatch(s,\n      r'^(S?\\$|\\₩|Rp|\\¥|\\€|\\₹|\\₽|fr|R\\$|R)?[ ]?[-]?([0-9]{1,3}[,.]([0-9]{3}[,.])*[0-9]{3}|[0-9]+)([,.][0-9]{1,2})?( ?(USD?|AUD|NZD|CAD|CHF|GBP|CNY|EUR|JPY|IDR|MXN|NOK|KRW|TRY|INR|RUB|BRL|ZAR|SGD|MYR))?$');\n\n  /// Checks if length of data is GREATER than maxLength.\n  static bool isLengthGreaterThan(dynamic value, int maxLength) {\n    final length = _obtainDynamicLength(value);\n\n    if (length == null) {\n      return false;\n    }\n\n    return length > maxLength;\n  }\n\n  /// Checks if length of data is GREATER OR EQUAL to maxLength.\n  static bool isLengthGreaterOrEqual(dynamic value, int maxLength) {\n    final length = _obtainDynamicLength(value);\n\n    if (length == null) {\n      return false;\n    }\n\n    return length >= maxLength;\n  }\n\n  /// Checks if length of data is LESS than maxLength.\n  static bool isLengthLessThan(dynamic value, int maxLength) {\n    final length = _obtainDynamicLength(value);\n    if (length == null) {\n      return false;\n    }\n\n    return length < maxLength;\n  }\n\n  /// Checks if length of data is LESS OR EQUAL to maxLength.\n  static bool isLengthLessOrEqual(dynamic value, int maxLength) {\n    final length = _obtainDynamicLength(value);\n\n    if (length == null) {\n      return false;\n    }\n\n    return length <= maxLength;\n  }\n\n  /// Checks if length of data is EQUAL to maxLength.\n  static bool isLengthEqualTo(dynamic value, int otherLength) {\n    final length = _obtainDynamicLength(value);\n\n    if (length == null) {\n      return false;\n    }\n\n    return length == otherLength;\n  }\n\n  /// Checks if length of data is BETWEEN minLength to maxLength.\n  static bool isLengthBetween(dynamic value, int minLength, int maxLength) {\n    if (isNull(value)) {\n      return false;\n    }\n\n    return isLengthGreaterOrEqual(value, minLength) &&\n        isLengthLessOrEqual(value, maxLength);\n  }\n\n  /// Checks if a contains b (Treating or interpreting upper- and lowercase\n  /// letters as being the same).\n  static bool isCaseInsensitiveContains(String a, String b) {\n    return a.toLowerCase().contains(b.toLowerCase());\n  }\n\n  /// Checks if a contains b or b contains a (Treating or\n  /// interpreting upper- and lowercase letters as being the same).\n  static bool isCaseInsensitiveContainsAny(String a, String b) {\n    final lowA = a.toLowerCase();\n    final lowB = b.toLowerCase();\n\n    return lowA.contains(lowB) || lowB.contains(lowA);\n  }\n\n  /// Checks if num a LOWER than num b.\n  static bool isLowerThan(num a, num b) => a < b;\n\n  /// Checks if num a GREATER than num b.\n  static bool isGreaterThan(num a, num b) => a > b;\n\n  /// Checks if num a EQUAL than num b.\n  static bool isEqual(num a, num b) => a == b;\n\n  // Checks if num is a cnpj\n  static bool isCnpj(String cnpj) {\n    // Get only the numbers from the CNPJ\n    final numbers = cnpj.replaceAll(RegExp(r'[^0-9]'), '');\n\n    // Test if the CNPJ has 14 digits\n    if (numbers.length != 14) {\n      return false;\n    }\n\n    // Test if all digits of the CNPJ are the same\n    if (RegExp(r'^(\\d)\\1*$').hasMatch(numbers)) {\n      return false;\n    }\n\n    // Divide digits\n    final digits = numbers.split('').map(int.parse).toList();\n\n    // Calculate the first check digit\n    var calcDv1 = 0;\n    var j = 0;\n    for (var i in Iterable<int>.generate(12, (i) => i < 4 ? 5 - i : 13 - i)) {\n      calcDv1 += digits[j++] * i;\n    }\n    calcDv1 %= 11;\n    final dv1 = calcDv1 < 2 ? 0 : 11 - calcDv1;\n\n    // Test the first check digit\n    if (digits[12] != dv1) {\n      return false;\n    }\n\n    // Calculate the second check digit\n    var calcDv2 = 0;\n    j = 0;\n    for (var i in Iterable<int>.generate(13, (i) => i < 5 ? 6 - i : 14 - i)) {\n      calcDv2 += digits[j++] * i;\n    }\n    calcDv2 %= 11;\n    final dv2 = calcDv2 < 2 ? 0 : 11 - calcDv2;\n\n    // Test the second check digit\n    if (digits[13] != dv2) {\n      return false;\n    }\n\n    return true;\n  }\n\n  /// Checks if the cpf is valid.\n  static bool isCpf(String cpf) {\n    // if (cpf == null) {\n    //   return false;\n    // }\n\n    // get only the numbers\n    final numbers = cpf.replaceAll(RegExp(r'[^0-9]'), '');\n    // Test if the CPF has 11 digits\n    if (numbers.length != 11) {\n      return false;\n    }\n    // Test if all CPF digits are the same\n    if (RegExp(r'^(\\d)\\1*$').hasMatch(numbers)) {\n      return false;\n    }\n\n    // split the digits\n    final digits = numbers.split('').map(int.parse).toList();\n\n    // Calculate the first verifier digit\n    var calcDv1 = 0;\n    for (var i in Iterable<int>.generate(9, (i) => 10 - i)) {\n      calcDv1 += digits[10 - i] * i;\n    }\n    calcDv1 %= 11;\n\n    final dv1 = calcDv1 < 2 ? 0 : 11 - calcDv1;\n\n    // Tests the first verifier digit\n    if (digits[9] != dv1) {\n      return false;\n    }\n\n    // Calculate the second verifier digit\n    var calcDv2 = 0;\n    for (var i in Iterable<int>.generate(10, (i) => 11 - i)) {\n      calcDv2 += digits[11 - i] * i;\n    }\n    calcDv2 %= 11;\n\n    final dv2 = calcDv2 < 2 ? 0 : 11 - calcDv2;\n\n    // Test the second verifier digit\n    if (digits[10] != dv2) {\n      return false;\n    }\n\n    return true;\n  }\n\n  /// Capitalize each word inside string\n  /// Example: your name => Your Name, your name => Your name\n  static String capitalize(String value) {\n    if (isBlank(value)!) return value;\n    return value.split(' ').map(capitalizeFirst).join(' ');\n  }\n\n  /// Uppercase first letter inside string and let the others lowercase\n  /// Example: your name => Your name\n  static String capitalizeFirst(String s) {\n    if (isBlank(s)!) return s;\n    return s[0].toUpperCase() + s.substring(1).toLowerCase();\n  }\n\n  /// Remove all whitespace inside string\n  /// Example: your name => yourname\n  static String removeAllWhitespace(String value) {\n    return value.replaceAll(' ', '');\n  }\n\n  /// camelCase string\n  /// Example: your name => yourName\n  static String? camelCase(String value) {\n    if (isNullOrBlank(value)!) {\n      return null;\n    }\n\n    final separatedWords =\n        value.split(RegExp(r'[!@#<>?\":`~;[\\]\\\\|=+)(*&^%-\\s_]+'));\n    var newString = '';\n\n    for (final word in separatedWords) {\n      newString += word[0].toUpperCase() + word.substring(1).toLowerCase();\n    }\n\n    return newString[0].toLowerCase() + newString.substring(1);\n  }\n\n  /// credits to \"ReCase\" package.\n  static final RegExp _upperAlphaRegex = RegExp(r'[A-Z]');\n  static final _symbolSet = {' ', '.', '/', '_', '\\\\', '-'};\n  static List<String> _groupIntoWords(String text) {\n    var sb = StringBuffer();\n    var words = <String>[];\n    var isAllCaps = text.toUpperCase() == text;\n\n    for (var i = 0; i < text.length; i++) {\n      var char = text[i];\n      var nextChar = i + 1 == text.length ? null : text[i + 1];\n      if (_symbolSet.contains(char)) {\n        continue;\n      }\n      sb.write(char);\n      var isEndOfWord = nextChar == null ||\n          (_upperAlphaRegex.hasMatch(nextChar) && !isAllCaps) ||\n          _symbolSet.contains(nextChar);\n      if (isEndOfWord) {\n        words.add('$sb');\n        sb.clear();\n      }\n    }\n    return words;\n  }\n\n  /// snake_case\n  static String? snakeCase(String? text, {String separator = '_'}) {\n    if (isNullOrBlank(text)!) {\n      return null;\n    }\n    return _groupIntoWords(text!)\n        .map((word) => word.toLowerCase())\n        .join(separator);\n  }\n\n  /// param-case\n  static String? paramCase(String? text) => snakeCase(text, separator: '-');\n\n  /// Extract numeric value of string\n  /// Example: OTP 12312 27/04/2020 => 1231227042020ß\n  /// If firstWordOnly is true, then the example return is \"12312\"\n  /// (first found numeric word)\n  static String numericOnly(String s, {bool firstWordOnly = false}) {\n    var numericOnlyStr = '';\n\n    for (var i = 0; i < s.length; i++) {\n      if (isNumericOnly(s[i])) {\n        numericOnlyStr += s[i];\n      }\n      if (firstWordOnly && numericOnlyStr.isNotEmpty && s[i] == \" \") {\n        break;\n      }\n    }\n\n    return numericOnlyStr;\n  }\n\n  /// Capitalize only the first letter of each word in a string\n  /// Example: getx will make it easy  => Getx Will Make It Easy\n  /// Example 2 : this is an example text => This Is An Example Text\n  static String capitalizeAllWordsFirstLetter(String s) {\n    String lowerCasedString = s.toLowerCase();\n    String stringWithoutExtraSpaces = lowerCasedString.trim();\n\n    if (stringWithoutExtraSpaces.isEmpty) {\n      return \"\";\n    }\n    if (stringWithoutExtraSpaces.length == 1) {\n      return stringWithoutExtraSpaces.toUpperCase();\n    }\n\n    List<String> stringWordsList = stringWithoutExtraSpaces.split(\" \");\n    List<String> capitalizedWordsFirstLetter = stringWordsList\n        .map(\n          (word) {\n            if (word.trim().isEmpty) return \"\";\n            return word.trim();\n          },\n        )\n        .where(\n          (word) => word != \"\",\n        )\n        .map(\n          (word) {\n            if (word.startsWith(RegExp(r'[\\n\\t\\r]'))) {\n              return word;\n            }\n            return word[0].toUpperCase() + word.substring(1).toLowerCase();\n          },\n        )\n        .toList();\n    String finalResult = capitalizedWordsFirstLetter.join(\" \");\n    return finalResult;\n  }\n\n  static bool hasMatch(String? value, String pattern) {\n    return (value == null) ? false : RegExp(pattern).hasMatch(value);\n  }\n\n  static String createPath(String path, [Iterable? segments]) {\n    if (segments == null || segments.isEmpty) {\n      return path;\n    }\n    final list = segments.map((e) => '/$e');\n    return path + list.join();\n  }\n\n  static void printFunction(\n    String prefix,\n    dynamic value,\n    String info, {\n    bool isError = false,\n  }) {\n    Get.log('$prefix $value $info'.trim(), isError: isError);\n  }\n}\n\ntypedef PrintFunctionCallback = void Function(\n  String prefix,\n  dynamic value,\n  String info, {\n  bool? isError,\n});\n"
  },
  {
    "path": "lib/get_utils/src/platform/platform.dart",
    "content": "import 'platform_stub.dart'\n    if (dart.library.js_interop) 'platform_web.dart'\n    if (dart.library.io) 'platform_io.dart';\n\n// ignore: avoid_classes_with_only_static_members\nclass GetPlatform {\n  static bool get isWeb => GeneralPlatform.isWeb;\n\n  static bool get isMacOS => GeneralPlatform.isMacOS;\n\n  static bool get isWindows => GeneralPlatform.isWindows;\n\n  static bool get isLinux => GeneralPlatform.isLinux;\n\n  static bool get isAndroid => GeneralPlatform.isAndroid;\n\n  static bool get isIOS => GeneralPlatform.isIOS;\n\n  static bool get isFuchsia => GeneralPlatform.isFuchsia;\n\n  static bool get isMobile => GetPlatform.isIOS || GetPlatform.isAndroid;\n\n  static bool get isDesktop =>\n      GetPlatform.isMacOS || GetPlatform.isWindows || GetPlatform.isLinux;\n}\n"
  },
  {
    "path": "lib/get_utils/src/platform/platform_io.dart",
    "content": "import 'dart:io';\n\n// ignore: avoid_classes_with_only_static_members\nclass GeneralPlatform {\n  static bool get isWeb => false;\n\n  static bool get isMacOS => Platform.isMacOS;\n\n  static bool get isWindows => Platform.isWindows;\n\n  static bool get isLinux => Platform.isLinux;\n\n  static bool get isAndroid => Platform.isAndroid;\n\n  static bool get isIOS => Platform.isIOS;\n\n  static bool get isFuchsia => Platform.isFuchsia;\n\n  static bool get isDesktop =>\n      Platform.isMacOS || Platform.isWindows || Platform.isLinux;\n}\n"
  },
  {
    "path": "lib/get_utils/src/platform/platform_stub.dart",
    "content": "class GeneralPlatform {\n  static bool get isWeb => throw UnimplementedError();\n\n  static bool get isMacOS => throw UnimplementedError();\n\n  static bool get isWindows => throw UnimplementedError();\n\n  static bool get isLinux => throw UnimplementedError();\n\n  static bool get isAndroid => throw UnimplementedError();\n\n  static bool get isIOS => throw UnimplementedError();\n\n  static bool get isFuchsia => throw UnimplementedError();\n\n  static bool get isDesktop => throw UnimplementedError();\n}\n"
  },
  {
    "path": "lib/get_utils/src/platform/platform_web.dart",
    "content": "import 'package:web/web.dart' as html;\n\nimport '../../get_utils.dart';\n\nhtml.Navigator _navigator = html.window.navigator;\n\n// ignore: avoid_classes_with_only_static_members\nclass GeneralPlatform {\n  static bool get isWeb => true;\n\n  static bool get isMacOS =>\n      _navigator.appVersion.contains('Mac OS') && !GeneralPlatform.isIOS;\n\n  static bool get isWindows => _navigator.appVersion.contains('Win');\n\n  static bool get isLinux =>\n      (_navigator.appVersion.contains('Linux') ||\n          _navigator.appVersion.contains('x11')) &&\n      !isAndroid;\n\n  // @check https://developer.chrome.com/multidevice/user-agent\n  static bool get isAndroid => _navigator.appVersion.contains('Android ');\n\n  static bool get isIOS {\n    // maxTouchPoints is needed to separate iPad iOS13 vs new MacOS\n    return GetUtils.hasMatch(_navigator.platform, r'/iPad|iPhone|iPod/') ||\n        (_navigator.platform == 'MacIntel' && _navigator.maxTouchPoints > 1);\n  }\n\n  static bool get isFuchsia => false;\n\n  static bool get isDesktop => isMacOS || isWindows || isLinux;\n}\n"
  },
  {
    "path": "lib/get_utils/src/queue/get_queue.dart",
    "content": "import 'dart:async';\n\nclass GetMicrotask {\n  int _version = 0;\n  int _microtask = 0;\n\n  int get microtask => _microtask;\n  int get version => _version;\n\n  void exec(Function callback) {\n    if (_microtask == _version) {\n      _microtask++;\n      scheduleMicrotask(() {\n        _version++;\n        _microtask = _version;\n        callback();\n      });\n    }\n  }\n}\n\nclass GetQueue {\n  final List<_Item> _queue = [];\n  bool _active = false;\n\n  Future<T> add<T>(Function job) {\n    var completer = Completer<T>();\n    _queue.add(_Item(completer, job));\n    _check();\n    return completer.future;\n  }\n\n  void cancelAllJobs() {\n    _queue.clear();\n  }\n\n  void _check() async {\n    if (!_active && _queue.isNotEmpty) {\n      _active = true;\n      var item = _queue.removeAt(0);\n      try {\n        item.completer.complete(await item.job());\n      } on Exception catch (e) {\n        item.completer.completeError(e);\n      }\n      _active = false;\n      _check();\n    }\n  }\n}\n\nclass _Item {\n  final dynamic completer;\n  final dynamic job;\n\n  _Item(this.completer, this.job);\n}\n"
  },
  {
    "path": "lib/get_utils/src/widgets/optimized_listview.dart",
    "content": "import 'package:flutter/material.dart';\n\nclass OptimizedListView<T> extends StatelessWidget {\n  final List<T> list;\n  final Axis scrollDirection;\n  final bool reverse;\n  final ScrollController? controller;\n  final bool? primary;\n  final ScrollPhysics? physics;\n  final bool shrinkWrap;\n  final Widget onEmpty;\n  final int length;\n  final Widget Function(BuildContext context, ValueKey key, T item) builder;\n  const OptimizedListView({\n    super.key,\n    required this.list,\n    required this.builder,\n    this.scrollDirection = Axis.vertical,\n    this.reverse = false,\n    this.controller,\n    this.primary,\n    this.physics,\n    this.onEmpty = const SizedBox.shrink(),\n    this.shrinkWrap = false,\n  }) : length = list.length;\n  @override\n  Widget build(BuildContext context) {\n    if (list.isEmpty) return onEmpty;\n\n    return CustomScrollView(\n      controller: controller,\n      reverse: reverse,\n      scrollDirection: scrollDirection,\n      primary: primary,\n      physics: physics,\n      shrinkWrap: shrinkWrap,\n      slivers: <Widget>[\n        SliverList(\n          delegate: SliverChildBuilderDelegate(\n            (context, i) {\n              final item = list[i];\n              final key = ValueKey(item);\n              return builder(context, key, item);\n            },\n            childCount: list.length,\n            addAutomaticKeepAlives: true,\n            findChildIndexCallback: (key) {\n              return list.indexWhere((m) => m == (key as ValueKey<T>).value);\n            },\n          ),\n        ),\n      ],\n    );\n  }\n}\n"
  },
  {
    "path": "lib/instance_manager.dart",
    "content": "/// Get Instance Manager is a modern and intelligent dependency injector\n/// that injects and removes dependencies seasonally.\nlibrary;\n\nexport 'get_core/get_core.dart';\nexport 'get_instance/get_instance.dart';\n"
  },
  {
    "path": "lib/route_manager.dart",
    "content": "///Get Navigator allows you to navigate routes, open snackbars,\n///dialogs and bottomsheets easily, and without the need for context.\nlibrary;\n\nexport 'get_core/get_core.dart';\nexport 'get_navigation/get_navigation.dart';\n"
  },
  {
    "path": "lib/src/responsive/size_percent_extension.dart",
    "content": "import '../../get.dart';\n\n//Converts a double value to a percentage\nextension PercentSized on double {\n  // height: 50.0.hp = 50%\n  double get hp => (Get.height * (this / 100));\n  // width: 30.0.hp = 30%\n  double get wp => (Get.width * (this / 100));\n}\n"
  },
  {
    "path": "lib/state_manager.dart",
    "content": "/// Get State Manager is a light, modern and powerful state manager to Flutter\nlibrary;\n\nexport 'get_core/get_core.dart';\nexport 'get_rx/get_rx.dart';\nexport 'get_state_manager/get_state_manager.dart';\n"
  },
  {
    "path": "lib/utils.dart",
    "content": "/// Get utils is a set of tools that allows you to access high-level\n/// APIs and obtain validation tools for Flutter and GetX\nlibrary;\n\nexport 'get_core/get_core.dart';\nexport 'get_utils/get_utils.dart';\n"
  },
  {
    "path": "pubspec.yaml",
    "content": "name: get\ndescription: Open screens/snackbars/dialogs without context, manage states and inject dependencies easily with GetX.\nversion: 5.0.0-release-candidate-9.3.2\nhomepage: https://github.com/jonataslaw/getx\n\nenvironment:\n  sdk: \">=3.4.0 <4.0.0\"\n  flutter: \">=3.22.0\"\n\ndependencies:\n  flutter:\n    sdk: flutter\n  flutter_web_plugins:\n    sdk: flutter\n  web: \">=1.0.0 <2.0.0\"\n\ndev_dependencies:\n  flutter_lints: ^6.0.0\n  flutter_test:\n    sdk: flutter\n"
  },
  {
    "path": "test/animations/extensions_test.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_test/flutter_test.dart';\nimport 'package:get/get.dart';\n\nvoid main() {\n  group('Animation Extension', () {\n    Widget buildWidget() {\n      return Container(\n        width: 100,\n        height: 100,\n        color: Colors.red,\n      );\n    }\n\n    testWidgets('fadeIn() and fadeOut() can not be used sequentially',\n        (WidgetTester tester) async {\n      final widget = buildWidget();\n\n      expect(() => widget.fadeIn().fadeOut(), throwsAssertionError);\n      expect(() => widget.fadeOut().fadeIn(), throwsAssertionError);\n\n      expect(() => widget.fadeIn(isSequential: true).fadeOut(),\n          throwsAssertionError);\n      expect(() => widget.fadeOut(isSequential: true).fadeIn(),\n          throwsAssertionError);\n    });\n\n    testWidgets('can not use delay when isSequential is true',\n        (WidgetTester tester) async {\n      final widget = buildWidget();\n\n      expect(\n          () => widget.fadeIn(\n              isSequential: true, delay: const Duration(seconds: 1)),\n          throwsAssertionError);\n    });\n\n    testWidgets(\n        'fadeIn() and fadeOut() can be used together when isSequential is true',\n        (WidgetTester tester) async {\n      final widget = buildWidget();\n\n      expect(\n          () => widget.fadeIn(isSequential: true).fadeOut(isSequential: true),\n          isNot(throwsException));\n\n      expect(() => widget.fadeIn().fadeOut(isSequential: true),\n          isNot(throwsException));\n    });\n\n    testWidgets('fadeIn() returns a FadeInAnimation',\n        (WidgetTester tester) async {\n      final widget = buildWidget();\n      const begin = 0.0;\n      const end = 1.0;\n      final animation = widget.fadeIn();\n\n      expect(animation, isA<FadeInAnimation>());\n\n      _testDefaultValues(\n          animation: animation, widget: widget, begin: begin, end: end);\n    });\n\n    testWidgets('fadeOut() returns a animation', (WidgetTester tester) async {\n      final widget = buildWidget();\n      const begin = 1.0;\n      const end = 0.0;\n      final animation = widget.fadeOut();\n\n      expect(animation, isA<FadeOutAnimation>());\n\n      _testDefaultValues(\n          animation: animation, widget: widget, begin: begin, end: end);\n    });\n\n    testWidgets('rotate() returns a RotateAnimation',\n        (WidgetTester tester) async {\n      const begin = 0.9;\n      const end = 1.1;\n      final widget = buildWidget();\n      final animation = widget.rotate(begin: begin, end: end);\n\n      expect(animation, isA<RotateAnimation>());\n\n      _testDefaultValues(\n          animation: animation, widget: widget, begin: begin, end: end);\n    });\n\n    testWidgets('scale() returns a ScaleAnimation',\n        (WidgetTester tester) async {\n      const begin = 0.9;\n      const end = 1.1;\n      final widget = buildWidget();\n      final animation = widget.scale(begin: begin, end: end);\n\n      expect(animation, isA<ScaleAnimation>());\n\n      _testDefaultValues(\n          animation: animation, widget: widget, begin: begin, end: end);\n    });\n\n    testWidgets('slide() returns a SlideAnimation',\n        (WidgetTester tester) async {\n      const begin = 0;\n      const end = 1;\n      final widget = buildWidget();\n      final animation = widget.slide(offset: (_, __) => const Offset(0, 0));\n\n      expect(animation, isA<SlideAnimation>());\n\n      _testDefaultValues(\n          animation: animation, widget: widget, begin: begin, end: end);\n    });\n\n    testWidgets('bounce() returns a BounceAnimation',\n        (WidgetTester tester) async {\n      const begin = 0.9;\n      const end = 1.1;\n      final widget = buildWidget();\n      final animation = widget.bounce(begin: begin, end: end);\n\n      expect(animation, isA<BounceAnimation>());\n\n      _testDefaultValues(\n        animation: animation,\n        widget: widget,\n        begin: begin,\n        end: end,\n        curve: Curves.bounceOut,\n      );\n    });\n\n    testWidgets('spin() returns a SpinAnimation', (WidgetTester tester) async {\n      final widget = buildWidget();\n      const begin = 0.0;\n      const end = 360;\n      final animation = widget.spin();\n\n      expect(animation, isA<SpinAnimation>());\n\n      _testDefaultValues(\n          animation: animation, widget: widget, begin: begin, end: end);\n    });\n\n    testWidgets('size() returns a SizeAnimation', (WidgetTester tester) async {\n      final widget = buildWidget();\n\n      const begin = 0.9;\n      const end = 1.1;\n      final animation = widget.size(begin: begin, end: end);\n\n      expect(animation, isA<SizeAnimation>());\n\n      _testDefaultValues(\n          animation: animation, widget: widget, begin: begin, end: end);\n    });\n\n    testWidgets('blur() returns a BlurAnimation', (WidgetTester tester) async {\n      final widget = buildWidget();\n\n      const begin = 0.9;\n      const end = 1.1;\n      final animation = widget.blur(begin: begin, end: end);\n\n      expect(animation, isA<BlurAnimation>());\n\n      _testDefaultValues(\n          animation: animation, widget: widget, begin: begin, end: end);\n    });\n\n    testWidgets('flip() returns a FlipAnimation', (WidgetTester tester) async {\n      final widget = buildWidget();\n\n      const begin = 0.9;\n      const end = 1.1;\n      final animation = widget.flip(begin: begin, end: end);\n\n      expect(animation, isA<FlipAnimation>());\n\n      _testDefaultValues(\n          animation: animation, widget: widget, begin: begin, end: end);\n    });\n\n    testWidgets('wave() returns a FlipAnimation', (WidgetTester tester) async {\n      final widget = buildWidget();\n\n      const begin = 0.9;\n      const end = 1.1;\n      final animation = widget.wave(begin: begin, end: end);\n\n      expect(animation, isA<WaveAnimation>());\n\n      _testDefaultValues(\n          animation: animation, widget: widget, begin: begin, end: end);\n    });\n  });\n}\n\nvoid _testDefaultValues<T>({\n  required GetAnimatedBuilder animation,\n  required Widget widget,\n  required T begin,\n  required T end,\n  Curve curve = Curves.linear,\n}) {\n  expect(animation.tween.begin, begin);\n  expect(animation.tween.end, end);\n  if (animation.idleValue is Offset) {\n    expect(animation.idleValue, Offset.zero);\n  } else if (animation is FadeOutAnimation) {\n    expect(animation.idleValue, 1);\n  } else {\n    expect(animation.idleValue, 0);\n  }\n\n  expect(animation.delay, Duration.zero);\n  expect(animation.child, widget);\n  expect(animation.curve, curve);\n}\n"
  },
  {
    "path": "test/animations/get_animated_builder_test.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_test/flutter_test.dart';\nimport 'package:get/get.dart';\n\nclass _Wrapper extends StatelessWidget {\n  const _Wrapper({required this.child});\n  final Widget child;\n\n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp(\n      home: Scaffold(body: child),\n    );\n  }\n}\n\nvoid main() {\n  testWidgets('GetAnimatedBuilder defaults', (WidgetTester tester) async {\n    await tester.pumpWidget(\n      _Wrapper(\n        child: GetAnimatedBuilder<int>(\n          duration: const Duration(milliseconds: 500),\n          tween: Tween(begin: 0, end: 10),\n          idleValue: 0,\n          builder: (_, value, __) => Text(value.toString()),\n          delay: Duration.zero,\n          child: Container(),\n        ),\n      ),\n    );\n\n    // Verify that the widget starts with the idle value.\n    expect(find.text('0'), findsOneWidget);\n\n    // Wait for the animation to complete.\n    await tester.pumpAndSettle(const Duration(milliseconds: 500));\n\n    // Verify that the widget ends with the final value.\n    expect(find.text('10'), findsOneWidget);\n  });\n\n  testWidgets('GetAnimatedBuilder changes value over time', (tester) async {\n    await tester.pumpWidget(\n      _Wrapper(\n        child: GetAnimatedBuilder<double>(\n          duration: const Duration(milliseconds: 500),\n          tween: Tween<double>(begin: 0.0, end: 1.0),\n          idleValue: 0.0,\n          builder: (context, value, child) {\n            return Opacity(opacity: value);\n          },\n          delay: const Duration(milliseconds: 500),\n          child: Container(\n            width: 100,\n            height: 100,\n            color: Colors.red,\n          ),\n        ),\n      ),\n    );\n\n    // Initial state is idleValue\n    expect(tester.widget<Opacity>(find.byType(Opacity)).opacity, 0.0);\n\n    // Wait for the delay to finish\n    await tester.pump(const Duration(milliseconds: 500));\n\n    // Verify that the value changes over time\n    await tester.pump(const Duration(milliseconds: 100));\n    expect(tester.widget<Opacity>(find.byType(Opacity)).opacity,\n        closeTo(0.2, 0.01));\n\n    await tester.pump(const Duration(milliseconds: 100));\n    expect(tester.widget<Opacity>(find.byType(Opacity)).opacity,\n        closeTo(0.4, 0.01));\n\n    await tester.pump(const Duration(milliseconds: 100));\n    expect(tester.widget<Opacity>(find.byType(Opacity)).opacity,\n        closeTo(0.6, 0.01));\n\n    await tester.pump(const Duration(milliseconds: 100));\n    expect(tester.widget<Opacity>(find.byType(Opacity)).opacity,\n        closeTo(0.8, 0.01));\n\n    await tester.pump(const Duration(milliseconds: 100));\n    expect(tester.widget<Opacity>(find.byType(Opacity)).opacity,\n        closeTo(1.0, 0.01));\n  });\n\n  testWidgets('onComplete callback is called when animation finishes',\n      (WidgetTester tester) async {\n    AnimationController? controller;\n    var onCompleteCalled = false;\n\n    await tester.pumpWidget(\n      _Wrapper(\n        child: GetAnimatedBuilder<int>(\n          duration: const Duration(milliseconds: 500),\n          tween: Tween(begin: 0, end: 10),\n          idleValue: 0,\n          builder: (_, value, __) => Text(value.toString()),\n          delay: Duration.zero,\n          onComplete: (c) {\n            onCompleteCalled = true;\n            controller = c;\n          },\n          child: Container(),\n        ),\n      ),\n    );\n\n    expect(onCompleteCalled, isFalse);\n\n    // Wait for the animation to complete.\n    await tester.pumpAndSettle(const Duration(milliseconds: 500));\n\n    // Verify that the onComplete callback was called.\n    expect(controller, isNotNull);\n\n    expect(onCompleteCalled, isTrue);\n  });\n\n  testWidgets('onStart callback is called when animation starts',\n      (WidgetTester tester) async {\n    var onStartCalled = false;\n\n    await tester.pumpWidget(\n      _Wrapper(\n        child: GetAnimatedBuilder(\n          duration: const Duration(seconds: 1),\n          delay: Duration.zero,\n          tween: Tween<double>(begin: 0, end: 1),\n          idleValue: 0,\n          builder: (context, value, child) => Container(),\n          child: Container(),\n          onStart: (_) {\n            onStartCalled = true;\n          },\n        ),\n      ),\n    );\n\n    expect(onStartCalled, isFalse);\n\n    await tester.pump(const Duration(milliseconds: 500));\n    expect(onStartCalled, isTrue);\n  });\n\n  testWidgets('GetAnimatedBuilder delay', (WidgetTester tester) async {\n    await tester.pumpWidget(\n      _Wrapper(\n        child: GetAnimatedBuilder<int>(\n          duration: const Duration(milliseconds: 500),\n          tween: Tween(begin: 0, end: 10),\n          idleValue: 0,\n          builder: (_, value, __) => Text(value.toString()),\n          delay: const Duration(milliseconds: 500),\n          child: Container(),\n        ),\n      ),\n    );\n\n    // Verify that the widget starts with the idle value.\n    expect(find.text('0'), findsOneWidget);\n\n    // Wait for the delay to pass.\n    await tester.pump(const Duration(milliseconds: 500));\n\n    // Verify that the animation has started.\n    expect(find.text('0'), findsOneWidget);\n\n    // Wait for the animation to complete.\n    await tester.pumpAndSettle(const Duration(milliseconds: 500));\n\n    // Verify that the widget ends with the final value.\n    expect(find.text('10'), findsOneWidget);\n  });\n\n  testWidgets(\n      'FadeInAnimation in idle should be visible, but not visible when the animation starts',\n      (WidgetTester tester) async {\n    await tester.pumpWidget(\n      _Wrapper(\n        child: FadeInAnimation(\n          delay: const Duration(milliseconds: 500),\n          duration: const Duration(milliseconds: 500),\n          idleValue: 0,\n          child: const Text('Hello'),\n        ),\n      ),\n    );\n\n    // in idle, the opacity should be 1.0\n    expect(tester.widget<Opacity>(find.byType(Opacity)).opacity, 1.0);\n\n    // Wait for the delay to finish\n    await tester.pump(const Duration(milliseconds: 500));\n\n    // When the animation starts the opacity should not be visible\n    expect(tester.widget<Opacity>(find.byType(Opacity)).opacity, 0.0);\n\n    // Verify that the value changes over time\n    await tester.pump(const Duration(milliseconds: 100));\n\n    // The value should be updated\n    expect(tester.widget<Opacity>(find.byType(Opacity)).opacity,\n        closeTo(0.2, 0.01));\n\n    await tester.pump(const Duration(milliseconds: 100));\n    expect(tester.widget<Opacity>(find.byType(Opacity)).opacity,\n        closeTo(0.4, 0.01));\n\n    await tester.pump(const Duration(milliseconds: 100));\n    expect(tester.widget<Opacity>(find.byType(Opacity)).opacity,\n        closeTo(0.6, 0.01));\n\n    await tester.pump(const Duration(milliseconds: 100));\n    expect(tester.widget<Opacity>(find.byType(Opacity)).opacity,\n        closeTo(0.8, 0.01));\n\n    await tester.pump(const Duration(milliseconds: 100));\n    expect(tester.widget<Opacity>(find.byType(Opacity)).opacity,\n        closeTo(1.0, 0.01));\n  });\n\n  testWidgets(\n      'willResetOnDispose should false when fadeOut is the last animation in a sequential animation',\n      (WidgetTester tester) async {\n    await tester.pumpWidget(\n      _Wrapper(\n        child: const Text('Hello')\n            .fadeIn(\n              isSequential: true,\n              duration: const Duration(milliseconds: 500),\n            )\n            .fadeOut(\n              isSequential: true,\n              duration: const Duration(milliseconds: 500),\n            ),\n      ),\n    );\n\n    // The variable starts as false\n    expect(\n        tester\n            .state<GetAnimatedBuilderState>(find.byType(FadeOutAnimation))\n            .willResetOnDispose,\n        false);\n\n    // Jump to middle of next animation\n    await tester.pump(const Duration(milliseconds: 500));\n\n    // The value should be false\n    expect(\n        tester\n            .state<GetAnimatedBuilderState>(find.byType(FadeOutAnimation))\n            .willResetOnDispose,\n        false);\n\n    await tester.pumpAndSettle();\n  });\n\n  testWidgets(\n      'willResetOnDispose should true when fadeOut is not last animation in a sequential animation',\n      (WidgetTester tester) async {\n    await tester.pumpWidget(\n      _Wrapper(\n        child: const Text('Hello')\n            .fadeOut(\n              isSequential: true,\n              duration: const Duration(milliseconds: 500),\n            )\n            .fadeIn(\n              isSequential: true,\n              duration: const Duration(milliseconds: 500),\n            ),\n      ),\n    );\n\n    // The variable starts as true\n    expect(\n        tester\n            .state<GetAnimatedBuilderState>(find.byType(FadeOutAnimation))\n            .willResetOnDispose,\n        true);\n\n    // Jump to middle of next animation\n    await tester.pump(const Duration(milliseconds: 500));\n\n    // The value should be true\n    expect(\n        tester\n            .state<GetAnimatedBuilderState>(find.byType(FadeOutAnimation))\n            .willResetOnDispose,\n        true);\n\n    await tester.pumpAndSettle();\n  });\n\n  testWidgets('RotateAnimation', (WidgetTester tester) async {\n    await tester.pumpWidget(\n      RotateAnimation(\n        duration: const Duration(seconds: 1),\n        delay: Duration.zero,\n        begin: 0.0,\n        end: 360.0,\n        child: Container(),\n      ),\n    );\n    expect(find.byType(RotateAnimation), findsOneWidget);\n    await tester.pumpAndSettle();\n  });\n\n  testWidgets('ScaleAnimation', (WidgetTester tester) async {\n    await tester.pumpWidget(\n      ScaleAnimation(\n        duration: const Duration(seconds: 1),\n        delay: Duration.zero,\n        begin: 1.0,\n        end: 2.0,\n        child: Container(),\n      ),\n    );\n    expect(find.byType(ScaleAnimation), findsOneWidget);\n    await tester.pumpAndSettle();\n  });\n\n  testWidgets('WaveAnimation', (WidgetTester tester) async {\n    await tester.pumpWidget(\n      WaveAnimation(\n        duration: const Duration(seconds: 1),\n        delay: Duration.zero,\n        begin: 1.0,\n        end: 2.0,\n        child: Container(),\n      ),\n    );\n    expect(find.byType(WaveAnimation), findsOneWidget);\n    await tester.pumpAndSettle();\n  });\n\n  testWidgets('WobbleAnimation', (WidgetTester tester) async {\n    await tester.pumpWidget(\n      WobbleAnimation(\n        duration: const Duration(seconds: 1),\n        delay: Duration.zero,\n        begin: 1.0,\n        end: 2.0,\n        child: Container(),\n      ),\n    );\n    expect(find.byType(WobbleAnimation), findsOneWidget);\n    await tester.pumpAndSettle();\n  });\n\n  testWidgets('SlideAnimation', (WidgetTester tester) async {\n    await tester.pumpWidget(\n      SlideAnimation(\n        offsetBuild: (p0, p1) => const Offset(1.0, 1.0),\n        duration: const Duration(seconds: 1),\n        delay: Duration.zero,\n        begin: 0,\n        end: 1,\n        child: Container(),\n      ),\n    );\n    expect(find.byType(SlideAnimation), findsOneWidget);\n    await tester.pumpAndSettle();\n  });\n\n  testWidgets('SlideInLeftAnimation', (WidgetTester tester) async {\n    await tester.pumpWidget(\n      _Wrapper(\n        child: SlideInLeftAnimation(\n          duration: const Duration(seconds: 1),\n          delay: Duration.zero,\n          begin: 1.0,\n          end: 2.0,\n          child: Container(),\n        ),\n      ),\n    );\n    expect(find.byType(SlideInLeftAnimation), findsOneWidget);\n    await tester.pumpAndSettle();\n  });\n\n  testWidgets('SlideInRightAnimation', (WidgetTester tester) async {\n    await tester.pumpWidget(\n      _Wrapper(\n        child: SlideInRightAnimation(\n          duration: const Duration(seconds: 1),\n          delay: Duration.zero,\n          begin: 1.0,\n          end: 2.0,\n          child: Container(),\n        ),\n      ),\n    );\n    expect(find.byType(SlideInRightAnimation), findsOneWidget);\n    await tester.pumpAndSettle();\n  });\n\n  testWidgets('SlideInUpAnimation', (WidgetTester tester) async {\n    await tester.pumpWidget(\n      _Wrapper(\n        child: SlideInUpAnimation(\n          duration: const Duration(seconds: 1),\n          delay: Duration.zero,\n          begin: 1.0,\n          end: 2.0,\n          child: Container(),\n        ),\n      ),\n    );\n    expect(find.byType(SlideInUpAnimation), findsOneWidget);\n    await tester.pumpAndSettle();\n  });\n\n  testWidgets('SlideInDownAnimation', (WidgetTester tester) async {\n    await tester.pumpWidget(\n      _Wrapper(\n        child: SlideInDownAnimation(\n          duration: const Duration(seconds: 1),\n          delay: Duration.zero,\n          begin: 1.0,\n          end: 2.0,\n          child: Container(),\n        ),\n      ),\n    );\n    expect(find.byType(SlideInDownAnimation), findsOneWidget);\n    await tester.pumpAndSettle();\n  });\n\n  testWidgets('BounceAnimation', (WidgetTester tester) async {\n    await tester.pumpWidget(\n      BounceAnimation(\n        duration: const Duration(seconds: 1),\n        delay: Duration.zero,\n        begin: 0.0,\n        end: 1.0,\n        child: Container(),\n      ),\n    );\n    expect(find.byType(BounceAnimation), findsOneWidget);\n    await tester.pumpAndSettle();\n  });\n\n  testWidgets('SpinAnimation', (WidgetTester tester) async {\n    await tester.pumpWidget(\n      SpinAnimation(\n        duration: const Duration(seconds: 1),\n        delay: Duration.zero,\n        child: Container(),\n      ),\n    );\n    expect(find.byType(SpinAnimation), findsOneWidget);\n    await tester.pumpAndSettle();\n  });\n\n  testWidgets('ColorAnimation', (WidgetTester tester) async {\n    await tester.pumpWidget(\n      ColorAnimation(\n        duration: const Duration(seconds: 1),\n        delay: Duration.zero,\n        begin: Colors.blue,\n        end: Colors.red,\n        child: Container(),\n      ),\n    );\n    expect(find.byType(ColorAnimation), findsOneWidget);\n    await tester.pumpAndSettle();\n  });\n\n  testWidgets('SizeAnimation', (WidgetTester tester) async {\n    await tester.pumpWidget(\n      SizeAnimation(\n        duration: const Duration(seconds: 1),\n        delay: Duration.zero,\n        begin: 1.0,\n        end: 2.0,\n        child: Container(),\n      ),\n    );\n    expect(find.byType(SizeAnimation), findsOneWidget);\n    await tester.pumpAndSettle();\n  });\n\n  testWidgets('BlurAnimation', (WidgetTester tester) async {\n    await tester.pumpWidget(\n      BlurAnimation(\n        duration: const Duration(seconds: 1),\n        delay: Duration.zero,\n        begin: 1.0,\n        end: 2.0,\n        child: Container(),\n      ),\n    );\n    expect(find.byType(BlurAnimation), findsOneWidget);\n    await tester.pumpAndSettle();\n  });\n\n  testWidgets('FlipAnimation', (WidgetTester tester) async {\n    await tester.pumpWidget(\n      FlipAnimation(\n        duration: const Duration(seconds: 1),\n        delay: Duration.zero,\n        begin: 1.0,\n        end: 2.0,\n        child: Container(),\n      ),\n    );\n    expect(find.byType(FlipAnimation), findsOneWidget);\n    await tester.pumpAndSettle();\n  });\n}\n"
  },
  {
    "path": "test/benchmarks/benckmark_test.dart",
    "content": "import 'dart:async';\n\nimport 'package:flutter/foundation.dart';\nimport 'package:flutter_test/flutter_test.dart';\nimport 'package:get/state_manager.dart';\n\nint times = 30;\n\nvoid printValue(String value) {\n  // ignore: avoid_print\n  print(value);\n}\n\nFuture<int> valueNotifier() {\n  final c = Completer<int>();\n  final value = ValueNotifier<int>(0);\n  final timer = Stopwatch();\n  timer.start();\n\n  value.addListener(() {\n    if (times == value.value) {\n      timer.stop();\n      printValue(\n          \"\"\"${value.value} listeners notified | [VALUE_NOTIFIER] time: ${timer.elapsedMicroseconds}ms\"\"\");\n      c.complete(timer.elapsedMicroseconds);\n    }\n  });\n\n  for (var i = 0; i < times + 1; i++) {\n    value.value = i;\n  }\n\n  return c.future;\n}\n\nFuture<int> getValue() {\n  final c = Completer<int>();\n  final value = Value<int>(0);\n  final timer = Stopwatch();\n  timer.start();\n\n  value.addListener(() {\n    if (times == value.value) {\n      timer.stop();\n      printValue(\n          \"\"\"${value.value} listeners notified | [GETX_VALUE] time: ${timer.elapsedMicroseconds}ms\"\"\");\n      c.complete(timer.elapsedMicroseconds);\n    }\n  });\n\n  for (var i = 0; i < times + 1; i++) {\n    value.value = i;\n  }\n\n  return c.future;\n}\n\nFuture<int> stream() {\n  final c = Completer<int>();\n\n  final value = StreamController<int>();\n  final timer = Stopwatch();\n  timer.start();\n\n  value.stream.listen((v) {\n    if (times == v) {\n      timer.stop();\n      printValue(\n          \"\"\"$v listeners notified | [STREAM] time: ${timer.elapsedMicroseconds}ms\"\"\");\n      c.complete(timer.elapsedMicroseconds);\n      value.close();\n    }\n  });\n\n  for (var i = 0; i < times + 1; i++) {\n    value.add(i);\n  }\n\n  return c.future;\n}\n\n// Future<int> getStream() {\n//   final c = Completer<int>();\n\n//   final value = GetStream<int>();\n//   final timer = Stopwatch();\n//   timer.start();\n\n//   value.listen((v) {\n//     if (times == v) {\n//       timer.stop();\n//       printValue(\n// \"\"\"$v listeners notified |\n// [GET_STREAM] time: ${timer.elapsedMicroseconds}ms\"\"\");\n//       c.complete(timer.elapsedMicroseconds);\n//     }\n//   });\n\n//   for (var i = 0; i < times + 1; i++) {\n//     value.add(i);\n//   }\n\n//   return c.future;\n// }\n\nFuture<int> miniStream() {\n  final c = Completer<int>();\n\n  final value = MiniStream<int>();\n  final timer = Stopwatch();\n  timer.start();\n\n  value.listen((v) {\n    if (times == v) {\n      timer.stop();\n      printValue(\n          \"\"\"$v listeners notified | [MINI_STREAM] time: ${timer.elapsedMicroseconds}ms\"\"\");\n      c.complete(timer.elapsedMicroseconds);\n    }\n  });\n\n  for (var i = 0; i < times + 1; i++) {\n    value.add(i);\n  }\n\n  return c.future;\n}\n\nvoid main() {\n  test('percentage test', () {\n    printValue('============================================');\n    printValue('PERCENTAGE TEST');\n\n    const referenceValue = 200;\n    const requestedValue = 100;\n\n    printValue('''\nreferenceValue is ${calculePercentage(referenceValue, requestedValue)}% more than requestedValue''');\n    expect(calculePercentage(referenceValue, requestedValue), 100);\n  });\n  test('run benchmarks from ValueNotifier', () async {\n    times = 30;\n    printValue('============================================');\n    printValue('VALUE_NOTIFIER X GETX_VALUE TEST');\n    printValue('-----------');\n    await getValue();\n    await valueNotifier();\n    printValue('-----------');\n\n    times = 30000;\n    final getx = await getValue();\n    final dart = await valueNotifier();\n    printValue('-----------');\n\n    printValue('ValueNotifier delay $dart ms to made $times requests');\n    printValue('GetValue delay $getx ms to made $times requests');\n    printValue('-----------');\n    printValue('''\nGetValue is ${calculePercentage(dart, getx).round()}% faster than Default ValueNotifier with $times requests''');\n  });\n\n  test('run benchmarks from Streams', () async {\n    times = 30;\n    printValue('============================================');\n    printValue('DART STREAM X GET_STREAM X GET_MINI_STREAM TEST');\n    printValue('-----------');\n    // var getx = await getStream();\n    var mini = await miniStream();\n    var dart = await stream();\n    printValue('-----------');\n    printValue('''\nGetStream is ${calculePercentage(dart, mini).round()}% faster than Default Stream with $times requests''');\n    printValue('-----------');\n\n    times = 30000;\n    dart = await stream();\n    // getx = await getStream();\n    mini = await miniStream();\n\n    times = 60000;\n    dart = await stream();\n    // getx = await getStream();\n    mini = await miniStream();\n    printValue('-----------');\n    printValue('dart_stream delay $dart ms to made $times requests');\n    // printValue('getx_stream delay $getx ms to made $times requests');\n    printValue('getx_mini_stream delay $mini ms to made $times requests');\n    printValue('-----------');\n    printValue('''\nGetStream is ${calculePercentage(dart, mini).round()}% faster than Default Stream with $times requests''');\n  });\n}\n\nint calculePercentage(int dart, int getx) {\n  return (dart / getx * 100).round() - 100;\n}\n"
  },
  {
    "path": "test/instance/get_instance_test.dart",
    "content": "// ignore_for_file: avoid_classes_with_only_static_members\n\nimport 'package:flutter_test/flutter_test.dart';\nimport 'package:get/get.dart';\n\nimport 'util/matcher.dart' as m;\n\nclass Mock {\n  static Future<String> test() async {\n    await Future.delayed(Duration.zero);\n    return 'test';\n  }\n}\n\nabstract class MyController with GetLifeCycleMixin {}\n\nclass DisposableController extends MyController {}\n\n// ignore: one_member_abstracts\nabstract class Service {\n  String post();\n}\n\nclass Api implements Service {\n  @override\n  String post() {\n    return 'test';\n  }\n}\n\nvoid main() {\n  TestWidgetsFlutterBinding.ensureInitialized();\n  test('Get.put test', () async {\n    final instance = Get.put<Controller>(Controller());\n    expect(instance, Get.find<Controller>());\n    Get.reset();\n  });\n\n  test('Get start and delete called just one time', () async {\n    Get\n      ..put(Controller())\n      ..put(Controller());\n\n    final controller = Get.find<Controller>();\n    expect(controller.init, 1);\n\n    Get\n      ..delete<Controller>()\n      ..delete<Controller>();\n    expect(controller.close, 1);\n    Get.reset();\n  });\n\n  test('Get.put tag test', () async {\n    final instance = Get.put<Controller>(Controller(), tag: 'one');\n    final instance2 = Get.put<Controller>(Controller(), tag: 'two');\n    expect(instance == instance2, false);\n    expect(Get.find<Controller>(tag: 'one') == Get.find<Controller>(tag: 'two'),\n        false);\n    expect(Get.find<Controller>(tag: 'one') == Get.find<Controller>(tag: 'one'),\n        true);\n    expect(Get.find<Controller>(tag: 'two') == Get.find<Controller>(tag: 'two'),\n        true);\n    Get.reset();\n  });\n\n  test('Get.lazyPut tag test', () async {\n    Get.lazyPut<Controller>(() => Controller(), tag: 'one');\n    Get.lazyPut<Controller>(() => Controller(), tag: 'two');\n\n    expect(Get.find<Controller>(tag: 'one') == Get.find<Controller>(tag: 'two'),\n        false);\n    expect(Get.find<Controller>(tag: 'one') == Get.find<Controller>(tag: 'one'),\n        true);\n    expect(Get.find<Controller>(tag: 'two') == Get.find<Controller>(tag: 'two'),\n        true);\n    Get.reset();\n  });\n\n  test('Get.lazyPut test', () async {\n    final controller = Controller();\n    Get.lazyPut<Controller>(() => controller);\n    final ct1 = Get.find<Controller>();\n    expect(ct1, controller);\n    Get.reset();\n  });\n\n  test('Get.lazyPut fenix test', () async {\n    Get.lazyPut<Controller>(() => Controller(), fenix: true);\n    Get.find<Controller>().increment();\n\n    expect(Get.find<Controller>().count, 1);\n    Get.delete<Controller>();\n    expect(Get.find<Controller>().count, 0);\n    Get.reset();\n  });\n\n  test('Get.lazyPut without fenix', () async {\n    Get.lazyPut<Controller>(() => Controller());\n    Get.find<Controller>().increment();\n\n    expect(Get.find<Controller>().count, 1);\n    Get.delete<Controller>();\n    expect(\n        () => Get.find<Controller>(), throwsA(const m.TypeMatcher<String>()));\n    Get.reset();\n  });\n\n  test('Get.reloadInstance test', () async {\n    Get.lazyPut<Controller>(() => Controller());\n    var ct1 = Get.find<Controller>();\n    ct1.increment();\n    expect(ct1.count, 1);\n    ct1 = Get.find<Controller>();\n    expect(ct1.count, 1);\n    Get.reload<Controller>();\n    ct1 = Get.find<Controller>();\n    expect(ct1.count, 0);\n    Get.reset();\n  });\n\n  test('GetxService test', () async {\n    Get.lazyPut<PermanentService>(() => PermanentService());\n    var sv1 = Get.find<PermanentService>();\n    var sv2 = Get.find<PermanentService>();\n    expect(sv1, sv2);\n    expect(Get.isRegistered<PermanentService>(), true);\n    Get.delete<PermanentService>();\n    expect(Get.isRegistered<PermanentService>(), true);\n    Get.delete<PermanentService>(force: true);\n    expect(Get.isRegistered<PermanentService>(), false);\n    Get.reset();\n  });\n\n  test('Get.lazyPut with abstract class test', () async {\n    final api = Api();\n    Get.lazyPut<Service>(() => api);\n    final ct1 = Get.find<Service>();\n    expect(ct1, api);\n    Get.reset();\n  });\n\n  test('Get.create with abstract class test', () async {\n    Get.spawn<Service>(() => Api());\n    final ct1 = Get.find<Service>();\n    final ct2 = Get.find<Service>();\n    // expect(ct1 is Service, true);\n    // expect(ct2 is Service, true);\n    expect(ct1 == ct2, false);\n    Get.reset();\n  });\n\n  group('test put, delete and check onInit execution', () {\n    tearDownAll(Get.reset);\n\n    test('Get.put test with init check', () async {\n      final instance = Get.put(DisposableController());\n      expect(instance, Get.find<DisposableController>());\n      expect(instance.initialized, true);\n    });\n\n    test('Get.delete test with disposable controller', () async {\n      // Get.put(DisposableController());\n      expect(Get.delete<DisposableController>(), true);\n      expect(() => Get.find<DisposableController>(),\n          throwsA(const m.TypeMatcher<String>()));\n    });\n\n    test('Get.put test after delete with disposable controller and init check',\n        () async {\n      final instance = Get.put<DisposableController>(DisposableController());\n      expect(instance, Get.find<DisposableController>());\n      expect(instance.initialized, true);\n    });\n  });\n\n  group('Get.replace test for replacing parent instance that is', () {\n    tearDown(Get.reset);\n    test('temporary', () async {\n      Get.put(DisposableController());\n      Get.replace<DisposableController>(Controller());\n      final instance = Get.find<DisposableController>();\n      expect(instance is Controller, isTrue);\n      expect((instance as Controller).init, greaterThan(0));\n    });\n\n    test('permanent', () async {\n      Get.put(DisposableController(), permanent: true);\n      Get.replace<DisposableController>(Controller());\n      final instance = Get.find<DisposableController>();\n      expect(instance is Controller, isTrue);\n      expect((instance as Controller).init, greaterThan(0));\n    });\n\n    test('tagged temporary', () async {\n      const tag = 'tag';\n      Get.put(DisposableController(), tag: tag);\n      Get.replace<DisposableController>(Controller(), tag: tag);\n      final instance = Get.find<DisposableController>(tag: tag);\n      expect(instance is Controller, isTrue);\n      expect((instance as Controller).init, greaterThan(0));\n    });\n\n    test('tagged permanent', () async {\n      const tag = 'tag';\n      Get.put(DisposableController(), permanent: true, tag: tag);\n      Get.replace<DisposableController>(Controller(), tag: tag);\n      final instance = Get.find<DisposableController>(tag: tag);\n      expect(instance is Controller, isTrue);\n      expect((instance as Controller).init, greaterThan(0));\n    });\n\n    test('a generic parent type', () async {\n      const tag = 'tag';\n      Get.put<MyController>(DisposableController(), permanent: true, tag: tag);\n      Get.replace<MyController>(Controller(), tag: tag);\n      final instance = Get.find<MyController>(tag: tag);\n      expect(instance is Controller, isTrue);\n      expect((instance as Controller).init, greaterThan(0));\n    });\n  });\n\n  group('Get.lazyReplace replaces parent instance', () {\n    tearDown(Get.reset);\n    test('without fenix', () async {\n      Get.put(DisposableController());\n      Get.lazyReplace<DisposableController>(() => Controller());\n      final instance = Get.find<DisposableController>();\n      expect(instance, isA<Controller>());\n      expect((instance as Controller).init, greaterThan(0));\n    });\n\n    test('with fenix', () async {\n      Get.put(DisposableController());\n      Get.lazyReplace<DisposableController>(() => Controller(), fenix: true);\n      expect(Get.find<DisposableController>(), isA<Controller>());\n      (Get.find<DisposableController>() as Controller).increment();\n\n      expect((Get.find<DisposableController>() as Controller).count, 1);\n      Get.delete<DisposableController>();\n      expect((Get.find<DisposableController>() as Controller).count, 0);\n    });\n\n    test('with fenix when parent is permanent', () async {\n      Get.put(DisposableController(), permanent: true);\n      Get.lazyReplace<DisposableController>(() => Controller());\n      final instance = Get.find<DisposableController>();\n      expect(instance, isA<Controller>());\n      (instance as Controller).increment();\n\n      expect((Get.find<DisposableController>() as Controller).count, 1);\n      Get.delete<DisposableController>();\n      expect((Get.find<DisposableController>() as Controller).count, 0);\n    });\n  });\n\n  group('Get.findOrNull test', () {\n    tearDown(Get.reset);\n    test('checking results', () async {\n      Get.put<int>(1);\n      int? result = Get.findOrNull<int>();\n      expect(result, 1);\n\n      Get.delete<int>();\n      result = Get.findOrNull<int>();\n      expect(result, null);\n    });\n  });\n}\n\nclass PermanentService extends GetxService {}\n\nclass Controller extends DisposableController {\n  int init = 0;\n  int close = 0;\n  int count = 0;\n  @override\n  void onInit() {\n    init++;\n    super.onInit();\n  }\n\n  @override\n  void onClose() {\n    close++;\n    super.onClose();\n  }\n\n  void increment() {\n    count++;\n  }\n}\n"
  },
  {
    "path": "test/instance/util/matcher.dart",
    "content": "// Copyright 2014, the Dart project authors. All rights reserved.\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n\n//     * Redistributions of source code must retain the above copyright\n//       notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n//       copyright notice, this list of conditions and the following\n//       disclaimer in the documentation and/or other materials provided\n//       with the distribution.\n//     * Neither the name of Google Inc. nor the names of its\n//       contributors may be used to endorse or promote products derived\n//       from this software without specific prior written permission.\n\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nimport 'package:flutter_test/flutter_test.dart';\n\nclass FunctionMatcher<T> extends CustomMatcher {\n  final Object Function(T value) _feature;\n\n  FunctionMatcher(String name, this._feature, matcher)\n      : super('`$name`:', '`$name`', matcher);\n\n  @override\n  Object featureValueOf(covariant T actual) => _feature(actual);\n}\n\nclass HavingMatcher<T> implements TypeMatcher<T> {\n  final TypeMatcher<T> _parent;\n  final List<FunctionMatcher<T>> _functionMatchers;\n\n  HavingMatcher(TypeMatcher<T> parent, String description,\n      Object Function(T) feature, dynamic matcher,\n      [Iterable<FunctionMatcher<T>>? existing])\n      : _parent = parent,\n        _functionMatchers = [\n          ...?existing,\n          FunctionMatcher<T>(description, feature, matcher)\n        ];\n\n  @override\n  TypeMatcher<T> having(\n          Object Function(T) feature, String description, dynamic matcher) =>\n      HavingMatcher(_parent, description, feature, matcher, _functionMatchers);\n\n  @override\n  bool matches(dynamic item, Map matchState) {\n    for (var matcher in <Matcher>[_parent].followedBy(_functionMatchers)) {\n      if (!matcher.matches(item, matchState)) {\n        addStateInfo(matchState, {'matcher': matcher});\n        return false;\n      }\n    }\n    return true;\n  }\n\n  @override\n  Description describeMismatch(\n    dynamic item,\n    Description mismatchDescription,\n    Map matchState,\n    bool verbose,\n  ) {\n    var matcher = matchState['matcher'] as Matcher;\n    matcher.describeMismatch(\n        item, mismatchDescription, matchState['state'] as Map, verbose);\n    return mismatchDescription;\n  }\n\n  @override\n  Description describe(Description description) => description\n      .add('')\n      .addDescriptionOf(_parent)\n      .add(' with ')\n      .addAll('', ' and ', '', _functionMatchers);\n}\n\nclass TypeMatcher<T> extends Matcher {\n  const TypeMatcher();\n\n  TypeMatcher<T> having(\n          Object Function(T) feature, String description, dynamic matcher) =>\n      HavingMatcher(this, description, feature, matcher);\n\n  @override\n  Description describe(Description description) {\n    var name = _stripDynamic(T);\n    return description.add(\"<Instance of '$name'>\");\n  }\n\n  @override\n  bool matches(Object? item, Map matchState) => item is T;\n\n  @override\n  Description describeMismatch(\n    dynamic item,\n    Description mismatchDescription,\n    Map matchState,\n    bool verbose,\n  ) {\n    var name = _stripDynamic(T);\n    return mismatchDescription.add(\"is not an instance of '$name'\");\n  }\n}\n\nString _stripDynamic(Type type) =>\n    type.toString().replaceAll(_dart2DynamicArgs, '');\nfinal _dart2DynamicArgs = RegExp('<dynamic(, dynamic)*>');\n"
  },
  {
    "path": "test/internationalization/internationalization_test.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_test/flutter_test.dart';\nimport 'package:get/get.dart';\n\nimport '../navigation/utils/wrapper.dart';\n\nvoid main() {\n  testWidgets(\"Get.defaultDialog smoke test\", (tester) async {\n    await tester.pumpWidget(\n      Wrapper(child: Container()),\n    );\n\n    await tester.pumpAndSettle();\n\n    expect('covid'.tr, 'Corona Virus');\n    expect('total_confirmed'.tr, 'Total Confirmed');\n    expect('total_deaths'.tr, 'Total Deaths');\n\n    Get.updateLocale(const Locale('pt', 'BR'));\n\n    await tester.pumpAndSettle();\n\n    expect('covid'.tr, 'Corona Vírus');\n    expect('total_confirmed'.tr, 'Total confirmado');\n    expect('total_deaths'.tr, 'Total de mortes');\n\n    Get.updateLocale(const Locale('en', 'EN'));\n\n    await tester.pumpAndSettle();\n\n    expect('covid'.tr, 'Corona Virus');\n    expect('total_confirmed'.tr, 'Total Confirmed');\n    expect('total_deaths'.tr, 'Total Deaths');\n  });\n}\n"
  },
  {
    "path": "test/navigation/bottomsheet_test.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_test/flutter_test.dart';\nimport 'package:get/get.dart';\n\nimport 'utils/wrapper.dart';\n\nvoid main() {\n  testWidgets(\"Get.bottomSheet smoke test\", (tester) async {\n    await tester.pumpWidget(\n      Wrapper(child: Container()),\n    );\n\n    await tester.pump();\n\n    Get.bottomSheet(Wrap(\n      children: <Widget>[\n        ListTile(\n          leading: const Icon(Icons.music_note),\n          title: const Text('Music'),\n          onTap: () {},\n        ),\n      ],\n    ));\n\n    await tester.pumpAndSettle();\n\n    expect(find.byIcon(Icons.music_note), findsOneWidget);\n  });\n\n  testWidgets(\"Get.bottomSheet close test\", (tester) async {\n    await tester.pumpWidget(\n      Wrapper(child: Container()),\n    );\n\n    await tester.pump();\n\n    Get.bottomSheet(Wrap(\n      children: <Widget>[\n        ListTile(\n          leading: const Icon(Icons.music_note),\n          title: const Text('Music'),\n          onTap: () {},\n        ),\n      ],\n    ));\n\n    await tester.pumpAndSettle();\n\n    expect(Get.isBottomSheetOpen, true);\n\n    Get.backLegacy();\n    await tester.pumpAndSettle();\n\n    expect(Get.isBottomSheetOpen, false);\n\n    // expect(() => Get.bottomSheet(Container(), isScrollControlled: null),\n    //     throwsAssertionError);\n\n    // expect(() => Get.bottomSheet(Container(), isDismissible: null),\n    //     throwsAssertionError);\n\n    // expect(() => Get.bottomSheet(Container(), enableDrag: null),\n    //     throwsAssertionError);\n\n    await tester.pumpAndSettle();\n  });\n\n  // testWidgets(\n  //   \"GetMaterialApp with debugShowMaterialGrid null\",\n  //   (tester) async {\n  //     expect(\n  //       () => GetMaterialApp(\n  //         debugShowMaterialGrid: null,\n  //       ),\n  //       throwsAssertionError,\n  //     );\n  //   },\n  // );\n}\n"
  },
  {
    "path": "test/navigation/dialog_test.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_test/flutter_test.dart';\nimport 'package:get/get.dart';\n\nimport 'utils/wrapper.dart';\n\nvoid main() {\n  testWidgets(\"Get.defaultDialog smoke test\", (tester) async {\n    await tester.pumpWidget(\n      Wrapper(child: Container()),\n    );\n\n    await tester.pump();\n\n    Get.defaultDialog(\n        onConfirm: () {}, middleText: \"Dialog made in 3 lines of code\");\n\n    await tester.pumpAndSettle();\n\n    expect(find.text(\"Ok\"), findsOneWidget);\n  });\n\n  testWidgets(\"Get.dialog smoke test\", (tester) async {\n    await tester.pumpWidget(\n      Wrapper(child: Container()),\n    );\n\n    await tester.pump();\n\n    Get.dialog(const YourDialogWidget());\n\n    await tester.pumpAndSettle();\n\n    expect(find.byType(YourDialogWidget), findsOneWidget);\n  });\n\n  group(\"Get dialog close tests\", () {\n    /// Set up the test by opening a dialog and checking to ensure state is correct\n    Future<void> setUpCloseTest(WidgetTester tester) async {\n      await tester.pumpWidget(\n        Wrapper(child: Container()),\n      );\n\n      await tester.pump();\n\n      Get.dialog(const YourDialogWidget());\n      await tester.pumpAndSettle();\n\n      expect(find.byType(YourDialogWidget), findsOneWidget);\n      expect(Get.isDialogOpen, true);\n    }\n\n    /// Tear down the test by checking after closing the dialog\n    Future<void> tearDownCloseTest(WidgetTester tester) async {\n      await tester.pumpAndSettle();\n\n      expect(find.byType(YourDialogWidget), findsNothing);\n      expect(Get.isDialogOpen, false);\n      await tester.pumpAndSettle();\n    }\n\n    testWidgets(\"Get dialog close - with backLegacy\", (tester) async {\n      await setUpCloseTest(tester);\n      // Close using backLegacy\n      Get.backLegacy();\n      await tearDownCloseTest(tester);\n    });\n\n    testWidgets(\"Get dialog close - with closeDialog\", (tester) async {\n      await setUpCloseTest(tester);\n      // Close using closeDialog\n      Get.closeDialog();\n      await tearDownCloseTest(tester);\n    });\n  });\n\n  group(\"Get.closeDialog\", () {\n    testWidgets(\"Get.closeDialog - closes dialog and returns value\",\n        (tester) async {\n      await tester.pumpWidget(\n        Wrapper(child: Container()),\n      );\n\n      await tester.pump();\n\n      final result = Get.dialog(const YourDialogWidget());\n      await tester.pumpAndSettle();\n\n      expect(find.byType(YourDialogWidget), findsOneWidget);\n      expect(Get.isDialogOpen, true);\n\n      const dialogResult = \"My dialog result\";\n\n      Get.closeDialog(result: dialogResult);\n      await tester.pumpAndSettle();\n\n      final returnedResult = await result;\n      expect(returnedResult, dialogResult);\n\n      expect(find.byType(YourDialogWidget), findsNothing);\n      expect(Get.isDialogOpen, false);\n      await tester.pumpAndSettle();\n    });\n\n    testWidgets(\"Get.closeDialog - does not close bottomsheets\",\n        (tester) async {\n      await tester.pumpWidget(\n        Wrapper(child: Container()),\n      );\n\n      await tester.pump();\n\n      Get.bottomSheet(const YourDialogWidget());\n      await tester.pumpAndSettle();\n\n      expect(find.byType(YourDialogWidget), findsOneWidget);\n      expect(Get.isDialogOpen, false);\n\n      Get.closeDialog();\n      await tester.pumpAndSettle();\n\n      expect(find.byType(YourDialogWidget), findsOneWidget);\n    });\n  });\n}\n\nclass YourDialogWidget extends StatelessWidget {\n  const YourDialogWidget({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Container();\n  }\n}\n"
  },
  {
    "path": "test/navigation/dispose_dependencies_test.dart",
    "content": "import 'package:flutter/widgets.dart';\nimport 'package:flutter_test/flutter_test.dart';\nimport 'package:get/get.dart';\n\nimport 'utils/wrapper.dart';\n\nvoid main() {\n  testWidgets(\"Test dispose dependencies with unnamed routes\", (tester) async {\n    await tester.pumpWidget(\n      Wrapper(child: Container()),\n    );\n\n    expect(Get.isRegistered<Controller2>(), false);\n    expect(Get.isRegistered<Controller>(), false);\n\n    Get.to(() => const First());\n\n    await tester.pumpAndSettle();\n\n    expect(find.byType(First), findsOneWidget);\n\n    expect(Get.isRegistered<Controller>(), true);\n\n    Get.to(() => const Second());\n\n    await tester.pumpAndSettle();\n\n    expect(find.byType(Second), findsOneWidget);\n\n    expect(Get.isRegistered<Controller>(), true);\n    expect(Get.isRegistered<Controller2>(), true);\n\n    Get.back();\n\n    await tester.pumpAndSettle();\n\n    expect(find.byType(First), findsOneWidget);\n\n    expect(Get.isRegistered<Controller>(), true);\n    expect(Get.isRegistered<Controller2>(), false);\n\n    Get.back();\n\n    await tester.pumpAndSettle();\n\n    expect(Get.isRegistered<Controller>(), false);\n    expect(Get.isRegistered<Controller2>(), false);\n  });\n}\n\nclass Controller extends GetxController {}\n\nclass Controller2 extends GetxController {}\n\nclass First extends StatelessWidget {\n  const First({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    Get.put(Controller());\n    return const Center(\n      child: Text(\"first\"),\n    );\n  }\n}\n\nclass Second extends StatelessWidget {\n  const Second({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    Get.put(Controller2());\n    return const Center(\n      child: Text(\"second\"),\n    );\n  }\n}\n"
  },
  {
    "path": "test/navigation/get_main_test.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_test/flutter_test.dart';\nimport 'package:get/get.dart';\n\nimport 'utils/wrapper.dart';\n\nvoid main() {\n  testWidgets(\"Get.to navigates to provided route\", (tester) async {\n    await tester.pumpWidget(Wrapper(child: Container()));\n\n    Get.to(() => const FirstScreen());\n\n    await tester.pumpAndSettle();\n\n    expect(find.byType(FirstScreen), findsOneWidget);\n  });\n\n  testWidgets(\"Get.toNamed navigates to provided named route\", (tester) async {\n    await tester.pumpWidget(GetMaterialApp(\n      initialRoute: '/first',\n      getPages: [\n        GetPage(page: () => const FirstScreen(), name: '/first'),\n        GetPage(page: () => const SecondScreen(), name: '/second'),\n        GetPage(page: () => const ThirdScreen(), name: '/third')\n      ],\n    ));\n\n    Get.toNamed('/second');\n\n    await tester.pumpAndSettle();\n\n    expect(find.byType(SecondScreen), findsOneWidget);\n  });\n\n  testWidgets(\"unknowroute\", (tester) async {\n    await tester.pumpWidget(GetMaterialApp(\n      initialRoute: '/first',\n      unknownRoute: GetPage(name: '/404', page: () => const Scaffold()),\n      getPages: [\n        GetPage(page: () => const FirstScreen(), name: '/first'),\n        GetPage(page: () => const SecondScreen(), name: '/second'),\n        GetPage(page: () => const ThirdScreen(), name: '/third')\n      ],\n    ));\n\n    Get.toNamed('/secondd');\n\n    await tester.pumpAndSettle();\n\n    expect(Get.rootController.rootDelegate.currentConfiguration?.route?.name,\n        '/404');\n  });\n\n  testWidgets(\"Get.off navigates to provided route\", (tester) async {\n    await tester.pumpWidget(const Wrapper(child: FirstScreen()));\n    // await tester.pump();\n\n    Get.off(() => const SecondScreen());\n\n    await tester.pumpAndSettle();\n\n    expect(find.byType(SecondScreen), findsOneWidget);\n  });\n\n  testWidgets(\"Get.off removes current route\", (tester) async {\n    await tester.pumpWidget(const Wrapper(child: FirstScreen()));\n    await tester.pump();\n\n    Get.off(() => const SecondScreen());\n    Get.back();\n\n    await tester.pumpAndSettle();\n\n    expect(find.byType(FirstScreen), findsNothing);\n  });\n\n  testWidgets(\"Get.offNamed navigates to provided named route\", (tester) async {\n    await tester.pumpWidget(GetMaterialApp(\n      initialRoute: '/first',\n      getPages: [\n        GetPage(name: '/first', page: () => const FirstScreen()),\n        GetPage(name: '/second', page: () => const SecondScreen()),\n        GetPage(name: '/third', page: () => const ThirdScreen()),\n      ],\n    ));\n\n    await tester.pump();\n\n    Get.offNamed('/second');\n\n    await tester.pumpAndSettle();\n\n    expect(find.byType(SecondScreen), findsOneWidget);\n  });\n\n  testWidgets(\"Get.offNamed removes current route\", (tester) async {\n    await tester.pumpWidget(GetMaterialApp(\n      initialRoute: '/first',\n      getPages: [\n        GetPage(name: '/first', page: () => const FirstScreen()),\n        GetPage(name: '/second', page: () => const SecondScreen()),\n        GetPage(name: '/third', page: () => const ThirdScreen()),\n      ],\n    ));\n\n    await tester.pump();\n\n    Get.offNamed('/second');\n    await tester.pumpAndSettle();\n    Get.back();\n\n    await tester.pumpAndSettle();\n\n    expect(find.byType(FirstScreen), findsNothing);\n  });\n\n  testWidgets(\"Get.offNamed removes only current route\", (tester) async {\n    await tester.pumpWidget(GetMaterialApp(\n      initialRoute: '/first',\n      getPages: [\n        GetPage(name: '/first', page: () => const FirstScreen()),\n        GetPage(name: '/second', page: () => const SecondScreen()),\n        GetPage(name: '/third', page: () => const ThirdScreen()),\n      ],\n    ));\n\n    // await tester.pump();\n\n    Get.toNamed('/second');\n    await tester.pumpAndSettle();\n    Get.offNamed('/third');\n    await tester.pumpAndSettle();\n    Get.back();\n    await tester.pumpAndSettle();\n\n    expect(find.byType(FirstScreen), findsOneWidget);\n    await tester.pumpAndSettle();\n  });\n\n  testWidgets(\"Get.offAll navigates to provided route\", (tester) async {\n    await tester.pumpWidget(const Wrapper(child: FirstScreen()));\n    await tester.pump();\n\n    Get.offAll(() => const SecondScreen());\n\n    await tester.pumpAndSettle();\n\n    expect(find.byType(SecondScreen), findsOneWidget);\n  });\n\n  testWidgets(\"Get.offAll removes all previous routes\", (tester) async {\n    await tester.pumpWidget(const Wrapper(child: FirstScreen()));\n    await tester.pump();\n\n    Get.to(() => const SecondScreen());\n    await tester.pumpAndSettle();\n    Get.offAll(() => const ThirdScreen());\n    await tester.pumpAndSettle();\n    Get.back();\n    await tester.pumpAndSettle();\n\n    expect(find.byType(SecondScreen), findsNothing);\n\n    Get.back();\n\n    await tester.pumpAndSettle();\n\n    expect(find.byType(FirstScreen), findsNothing);\n  });\n\n  testWidgets(\"Get.offAllNamed navigates to provided named route\",\n      (tester) async {\n    await tester.pumpWidget(WrapperNamed(\n      initialRoute: '/first',\n      namedRoutes: [\n        GetPage(page: () => const FirstScreen(), name: '/first'),\n        GetPage(page: () => const SecondScreen(), name: '/second'),\n        GetPage(page: () => const ThirdScreen(), name: '/third')\n      ],\n    ));\n\n    await tester.pump();\n\n    Get.toNamed('/second');\n\n    await tester.pumpAndSettle();\n\n    expect(find.byType(SecondScreen), findsOneWidget);\n  });\n\n  testWidgets(\"Get.offAllNamed removes all previous routes\", (tester) async {\n    await tester.pumpWidget(WrapperNamed(\n      initialRoute: '/first',\n      namedRoutes: [\n        GetPage(page: () => const FirstScreen(), name: '/first'),\n        GetPage(page: () => const SecondScreen(), name: '/second'),\n        GetPage(page: () => const ThirdScreen(), name: '/third')\n      ],\n    ));\n\n    await tester.pump();\n\n    Get.toNamed('/second');\n    await tester.pumpAndSettle();\n    Get.offAllNamed('/third');\n    await tester.pumpAndSettle();\n    Get.back();\n    await tester.pumpAndSettle();\n\n    expect(find.byType(SecondScreen), findsNothing);\n\n    Get.back();\n\n    await tester.pumpAndSettle();\n\n    expect(find.byType(FirstScreen), findsNothing);\n  });\n\n  testWidgets(\"Get.offAndToNamed navigates to provided route\", (tester) async {\n    await tester.pumpWidget(WrapperNamed(\n      initialRoute: '/first',\n      namedRoutes: [\n        GetPage(page: () => const FirstScreen(), name: '/first'),\n        GetPage(page: () => const SecondScreen(), name: '/second'),\n        GetPage(page: () => const ThirdScreen(), name: '/third')\n      ],\n    ));\n\n    Get.offAndToNamed('/second');\n\n    await tester.pumpAndSettle();\n\n    expect(find.byType(SecondScreen), findsOneWidget);\n  });\n\n  testWidgets(\"Get.offAndToNamed removes previous route\", (tester) async {\n    await tester.pumpWidget(WrapperNamed(\n      initialRoute: '/first',\n      namedRoutes: [\n        GetPage(page: () => const FirstScreen(), name: '/first'),\n        GetPage(page: () => const SecondScreen(), name: '/second'),\n        GetPage(page: () => const ThirdScreen(), name: '/third')\n      ],\n    ));\n\n    Get.offAndToNamed('/second');\n\n    await tester.pumpAndSettle();\n    Get.back();\n\n    await tester.pumpAndSettle();\n\n    expect(find.byType(FirstScreen), findsNothing);\n  });\n\n  testWidgets(\"Get.offUntil navigates to provided route\", (tester) async {\n    await tester.pumpWidget(Wrapper(child: Container()));\n\n    Get.to(() => const FirstScreen());\n\n    await tester.pumpAndSettle();\n\n    Get.offUntil(\n        () => const ThirdScreen(), (route) => route.name == '/FirstScreen');\n\n    await tester.pumpAndSettle();\n\n    expect(find.byType(ThirdScreen), findsOneWidget);\n  });\n\n  testWidgets(\"Get.until removes each route that meet the predicate\",\n      (tester) async {\n    await tester.pumpWidget(WrapperNamed(\n      initialRoute: '/first',\n      namedRoutes: [\n        GetPage(page: () => const FirstScreen(), name: '/first'),\n        GetPage(page: () => const SecondScreen(), name: '/second'),\n        GetPage(page: () => const ThirdScreen(), name: '/third')\n      ],\n    ));\n\n    Get.toNamed('/second');\n    await tester.pumpAndSettle();\n\n    Get.toNamed('/third');\n    await tester.pumpAndSettle();\n\n    Get.until((route) => route.name == '/first');\n\n    await tester.pumpAndSettle();\n\n    expect(find.byType(FirstScreen), findsOneWidget);\n    expect(find.byType(SecondScreen), findsNothing);\n    expect(find.byType(ThirdScreen), findsNothing);\n  });\n\n  testWidgets(\n      \"Get.offUntil removes previous routes if they don't match predicate\",\n      (tester) async {\n    await tester.pumpWidget(Wrapper(child: Container()));\n\n    Get.to(() => const FirstScreen());\n    await tester.pumpAndSettle();\n    Get.to(() => const SecondScreen());\n    await tester.pumpAndSettle();\n    Get.offUntil(\n        () => const ThirdScreen(), (route) => route.name == '/FirstScreen');\n    await tester.pumpAndSettle();\n    Get.back();\n\n    await tester.pumpAndSettle();\n\n    expect(find.byType(SecondScreen), findsNothing);\n  });\n\n  testWidgets(\n      \"Get.offUntil leaves previous routes that match provided predicate\",\n      (tester) async {\n    await tester.pumpWidget(Wrapper(child: Container()));\n\n    Get.to(() => const FirstScreen());\n    await tester.pumpAndSettle();\n    Get.to(() => const SecondScreen());\n    await tester.pumpAndSettle();\n    Get.offUntil(\n        () => const ThirdScreen(), (route) => route.name == '/FirstScreen');\n    await tester.pumpAndSettle();\n    Get.back();\n\n    await tester.pumpAndSettle();\n\n    expect(find.byType(FirstScreen), findsOneWidget);\n  });\n\n  group('Get.offNamedUntil Tests', () {\n    testWidgets(\"Navigates to provided route\", (tester) async {\n      await tester.pumpWidget(WrapperNamed(\n        initialRoute: '/first',\n        namedRoutes: [\n          GetPage(page: () => const FirstScreen(), name: '/first'),\n          GetPage(page: () => const SecondScreen(), name: '/second'),\n          GetPage(page: () => const ThirdScreen(), name: '/third')\n        ],\n      ));\n\n      Get.offNamedUntil('/second', (route) => route.name == '/first');\n      await tester.pumpAndSettle();\n\n      expect(find.byType(SecondScreen), findsOneWidget);\n      expect(Get.currentRoute, '/second');\n    });\n\n    testWidgets(\"Removes routes that don't match predicate\", (tester) async {\n      await tester.pumpWidget(WrapperNamed(\n        initialRoute: '/first',\n        namedRoutes: [\n          GetPage(page: () => const FirstScreen(), name: '/first'),\n          GetPage(page: () => const SecondScreen(), name: '/second'),\n          GetPage(page: () => const ThirdScreen(), name: '/third')\n        ],\n      ));\n\n      Get.toNamed('/second');\n      await tester.pumpAndSettle();\n      Get.offNamedUntil('/third', (route) => route.name == '/first');\n      await tester.pumpAndSettle();\n\n      expect(find.byType(ThirdScreen), findsOneWidget);\n      expect(Get.currentRoute, '/third');\n      expect(Get.previousRoute, '/first');\n    });\n\n    testWidgets(\"Keeps routes that match predicate\", (tester) async {\n      await tester.pumpWidget(WrapperNamed(\n        initialRoute: '/first',\n        namedRoutes: [\n          GetPage(page: () => const FirstScreen(), name: '/first'),\n          GetPage(page: () => const SecondScreen(), name: '/second'),\n          GetPage(page: () => const ThirdScreen(), name: '/third'),\n        ],\n      ));\n\n      Get.toNamed('/second');\n      await tester.pumpAndSettle();\n      Get.offNamedUntil('/third', (route) => route.name == '/first');\n      await tester.pumpAndSettle();\n      Get.back();\n      await tester.pumpAndSettle();\n\n      expect(find.byType(FirstScreen), findsOneWidget);\n      expect(Get.currentRoute, '/first');\n    });\n\n    testWidgets(\"Handles predicate that never returns true\", (tester) async {\n      await tester.pumpWidget(WrapperNamed(\n        initialRoute: '/first',\n        namedRoutes: [\n          GetPage(page: () => const FirstScreen(), name: '/first'),\n          GetPage(page: () => const SecondScreen(), name: '/second'),\n          GetPage(page: () => const ThirdScreen(), name: '/third'),\n          GetPage(page: () => const FourthScreen(), name: '/fourth'),\n        ],\n      ));\n\n      Get.toNamed('/second');\n      await tester.pumpAndSettle();\n\n      Get.toNamed('/third');\n      await tester.pumpAndSettle();\n\n      Get.offNamedUntil('/fourth', (route) => false);\n      await tester.pumpAndSettle();\n\n      expect(find.byType(FourthScreen), findsOneWidget);\n      expect(Get.currentRoute, '/fourth');\n      expect(Get.previousRoute, '/first');\n    });\n\n    testWidgets(\"Handles complex navigation scenario\", (tester) async {\n      await tester.pumpWidget(WrapperNamed(\n        initialRoute: '/first',\n        namedRoutes: [\n          GetPage(page: () => const FirstScreen(), name: '/first'),\n          GetPage(page: () => const SecondScreen(), name: '/second'),\n          GetPage(page: () => const ThirdScreen(), name: '/third'),\n          GetPage(page: () => const FourthScreen(), name: '/fourth'),\n        ],\n      ));\n\n      Get.toNamed('/second');\n      await tester.pumpAndSettle();\n      Get.toNamed('/third');\n      await tester.pumpAndSettle();\n      Get.offNamedUntil('/fourth', (route) => route.name == '/first');\n      await tester.pumpAndSettle();\n\n      expect(find.byType(FourthScreen), findsOneWidget);\n      expect(Get.currentRoute, '/fourth');\n      expect(Get.previousRoute, '/first');\n\n      Get.back();\n      await tester.pumpAndSettle();\n\n      expect(find.byType(FirstScreen), findsOneWidget);\n      expect(Get.currentRoute, '/first');\n    });\n  });\n\n  testWidgets(\"Get.offNamedUntil navigates to provided route\", (tester) async {\n    await tester.pumpWidget(WrapperNamed(\n      initialRoute: '/first',\n      namedRoutes: [\n        GetPage(page: () => const FirstScreen(), name: '/first'),\n        GetPage(page: () => const SecondScreen(), name: '/second'),\n        GetPage(page: () => const ThirdScreen(), name: '/third')\n      ],\n    ));\n\n    Get.offNamedUntil('/second', (route) => route.name == '/first');\n\n    await tester.pumpAndSettle();\n\n    expect(find.byType(SecondScreen), findsOneWidget);\n  });\n\n  testWidgets(\n      \"Get.offNamedUntil removes previous routes if they don't match predicate\",\n      (tester) async {\n    await tester.pumpWidget(WrapperNamed(\n      initialRoute: '/first',\n      namedRoutes: [\n        GetPage(page: () => const FirstScreen(), name: '/first'),\n        GetPage(page: () => const SecondScreen(), name: '/second'),\n        GetPage(page: () => const ThirdScreen(), name: '/third')\n      ],\n    ));\n\n    Get.toNamed('/second');\n    await tester.pumpAndSettle();\n    Get.offNamedUntil('/third', (route) => route.name == '/first');\n\n    await tester.pumpAndSettle();\n\n    expect(find.byType(SecondScreen), findsNothing);\n  });\n\n  testWidgets(\n      \"Get.offNamedUntil leaves previous routes that match provided predicate\",\n      (tester) async {\n    await tester.pumpWidget(WrapperNamed(\n      initialRoute: '/first',\n      namedRoutes: [\n        GetPage(page: () => const FirstScreen(), name: '/first'),\n        GetPage(page: () => const SecondScreen(), name: '/second'),\n        GetPage(page: () => const ThirdScreen(), name: '/third'),\n      ],\n    ));\n\n    Get.toNamed('/second');\n    await tester.pumpAndSettle();\n    Get.offNamedUntil('/third', (route) => route.name == '/first');\n    await tester.pumpAndSettle();\n    Get.back();\n\n    await tester.pumpAndSettle();\n\n    expect(find.byType(FirstScreen), findsOneWidget);\n  });\n\n  testWidgets(\"Get.back navigates back\", (tester) async {\n    await tester.pumpWidget(\n      Wrapper(\n        defaultTransition: Transition.circularReveal,\n        child: Container(),\n      ),\n    );\n\n    // await tester.pump();\n\n    Get.to(() => const FirstScreen());\n    await tester.pumpAndSettle();\n\n    Get.to(() => const SecondScreen());\n    await tester.pumpAndSettle();\n    Get.back();\n\n    await tester.pumpAndSettle();\n\n    expect(find.byType(FirstScreen), findsOneWidget);\n  });\n\n  testWidgets(\n      \"Get.back with closeOverlays pops both snackbar and current route\",\n      (tester) async {\n    await tester.pumpWidget(\n      Wrapper(\n        defaultTransition: Transition.circularReveal,\n        child: Container(),\n      ),\n    );\n\n    // await tester.pump();\n\n    Get.to(() => const FirstScreen());\n    await tester.pumpAndSettle();\n    Get.to(() => const SecondScreen());\n    await tester.pumpAndSettle();\n    Get.snackbar('title', \"message\");\n    await tester.pumpAndSettle();\n    Get.backLegacy(closeOverlays: true);\n\n    await tester.pumpAndSettle();\n\n    expect(Get.isSnackbarOpen, false);\n\n    expect(find.byType(FirstScreen), findsOneWidget);\n  });\n\n  testWidgets(\"Get.until\", (tester) async {\n    await tester.pumpWidget(WrapperNamed(\n      initialRoute: '/first',\n      namedRoutes: [\n        GetPage(page: () => const FirstScreen(), name: '/first'),\n        GetPage(page: () => const SecondScreen(), name: '/second'),\n        GetPage(page: () => const ThirdScreen(), name: '/third')\n      ],\n    ));\n\n    await tester.pump();\n\n    Get.toNamed('/second');\n    await tester.pumpAndSettle();\n    Get.toNamed('/third');\n    await tester.pumpAndSettle();\n    Get.until((route) => route.name == '/first');\n    await tester.pumpAndSettle();\n\n    expect(find.byType(FirstScreen), findsOneWidget);\n  });\n\n  group(\"Get.defaultTransition smoke test\", () {\n    testWidgets(\"fadeIn\", (tester) async {\n      await tester.pumpWidget(\n        Wrapper(\n          defaultTransition: Transition.fadeIn,\n          child: Container(),\n        ),\n      );\n\n      Get.to(() => const FirstScreen());\n\n      await tester.pumpAndSettle();\n\n      expect(find.byType(FirstScreen), findsOneWidget);\n    });\n\n    testWidgets(\"downToUp\", (tester) async {\n      await tester.pumpWidget(\n        Wrapper(\n          defaultTransition: Transition.downToUp,\n          child: Container(),\n        ),\n      );\n\n      Get.to(() => const FirstScreen());\n\n      await tester.pumpAndSettle();\n\n      expect(find.byType(FirstScreen), findsOneWidget);\n    });\n\n    testWidgets(\"fade\", (tester) async {\n      await tester.pumpWidget(\n        Wrapper(\n          defaultTransition: Transition.fade,\n          child: Container(),\n        ),\n      );\n\n      Get.to(() => const FirstScreen());\n\n      await tester.pumpAndSettle();\n\n      expect(find.byType(FirstScreen), findsOneWidget);\n    });\n\n    testWidgets(\"leftToRight\", (tester) async {\n      await tester.pumpWidget(\n        Wrapper(\n          defaultTransition: Transition.leftToRight,\n          child: Container(),\n        ),\n      );\n\n      Get.to(() => const FirstScreen());\n\n      await tester.pumpAndSettle();\n\n      expect(find.byType(FirstScreen), findsOneWidget);\n    });\n\n    testWidgets(\"leftToRightWithFade\", (tester) async {\n      await tester.pumpWidget(\n        Wrapper(\n          defaultTransition: Transition.leftToRightWithFade,\n          child: Container(),\n        ),\n      );\n\n      Get.to(() => const FirstScreen());\n\n      await tester.pumpAndSettle();\n\n      expect(find.byType(FirstScreen), findsOneWidget);\n    });\n\n    testWidgets(\"leftToRightWithFade\", (tester) async {\n      await tester.pumpWidget(\n        Wrapper(\n          defaultTransition: Transition.rightToLeft,\n          child: Container(),\n        ),\n      );\n\n      Get.to(() => const FirstScreen());\n\n      await tester.pumpAndSettle();\n\n      expect(find.byType(FirstScreen), findsOneWidget);\n    });\n\n    testWidgets(\"defaultTransition\", (tester) async {\n      await tester.pumpWidget(\n        Wrapper(\n          defaultTransition: Transition.rightToLeft,\n          child: Container(),\n        ),\n      );\n\n      Get.to(() => const FirstScreen());\n\n      await tester.pumpAndSettle();\n\n      expect(find.byType(FirstScreen), findsOneWidget);\n    });\n\n    testWidgets(\"rightToLeftWithFade\", (tester) async {\n      await tester.pumpWidget(\n        Wrapper(\n          defaultTransition: Transition.rightToLeftWithFade,\n          child: Container(),\n        ),\n      );\n\n      Get.to(() => const FirstScreen());\n\n      await tester.pumpAndSettle();\n\n      expect(find.byType(FirstScreen), findsOneWidget);\n    });\n\n    testWidgets(\"cupertino\", (tester) async {\n      await tester.pumpWidget(\n        Wrapper(\n          defaultTransition: Transition.cupertino,\n          child: Container(),\n        ),\n      );\n\n      Get.to(() => const FirstScreen());\n\n      await tester.pumpAndSettle();\n\n      expect(find.byType(FirstScreen), findsOneWidget);\n    });\n\n    testWidgets(\"size\", (tester) async {\n      await tester.pumpWidget(\n        Wrapper(\n          defaultTransition: Transition.size,\n          child: Container(),\n        ),\n      );\n\n      Get.to(() => const FirstScreen());\n\n      await tester.pumpAndSettle();\n\n      expect(find.byType(FirstScreen), findsOneWidget);\n    });\n  });\n}\n\nclass Home extends StatelessWidget {\n  const Home({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    // ignore: avoid_unnecessary_containers\n    return Container(child: const Text('Home'));\n  }\n}\n\nclass FirstScreen extends StatelessWidget {\n  const FirstScreen({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    // ignore: avoid_unnecessary_containers\n    return Container(child: const Text('FirstScreen'));\n  }\n}\n\nclass SecondScreen extends StatelessWidget {\n  const SecondScreen({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Container();\n  }\n}\n\nclass ThirdScreen extends StatelessWidget {\n  const ThirdScreen({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Container();\n  }\n}\n\nclass FourthScreen extends StatelessWidget {\n  const FourthScreen({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Container();\n  }\n}\n"
  },
  {
    "path": "test/navigation/middleware_test.dart",
    "content": "import 'package:flutter_test/flutter_test.dart';\nimport 'package:get/get.dart';\n\nimport 'get_main_test.dart';\n\nclass RedirectMiddleware extends GetMiddleware {\n  @override\n  Future<RouteDecoder?> redirectDelegate(RouteDecoder route) async {\n    return RouteDecoder.fromRoute('/second');\n  }\n}\n\nclass Redirect2Middleware extends GetMiddleware {\n  @override\n  Future<RouteDecoder?> redirectDelegate(RouteDecoder route) async {\n    return RouteDecoder.fromRoute('/first');\n  }\n}\n\nclass RedirectMiddlewareNull extends GetMiddleware {\n  @override\n  Future<RouteDecoder?> redirectDelegate(RouteDecoder route) async {\n    return null;\n  }\n}\n\nclass RedirectBypassMiddleware extends GetMiddleware {\n  @override\n  Future<RouteDecoder?> redirectDelegate(RouteDecoder route) async {\n    return route;\n  }\n}\n\nvoid main() {\n  tearDown(() {\n    Get.reset();\n  });\n\n  testWidgets(\"Middleware should redirect to second screen\", (tester) async {\n    // Test setup\n    await tester.pumpWidget(\n      GetMaterialApp(\n        initialRoute: '/',\n        getPages: [\n          GetPage(name: '/', page: () => const Home()),\n          GetPage(\n            name: '/first',\n            page: () => const FirstScreen(),\n            middlewares: [RedirectMiddleware()],\n          ),\n          GetPage(name: '/second', page: () => const SecondScreen()),\n          GetPage(name: '/third', page: () => const ThirdScreen()),\n        ],\n      ),\n    );\n\n    // Act\n    Get.toNamed('/first');\n    await tester.pumpAndSettle();\n\n    // Assert\n    expect(find.byType(SecondScreen), findsOneWidget);\n    expect(find.byType(FirstScreen), findsNothing);\n    expect(Get.currentRoute, '/second');\n  });\n\n  testWidgets(\"Middleware should stop navigation\", (tester) async {\n    // Test setup\n    await tester.pumpWidget(\n      GetMaterialApp(\n        initialRoute: '/',\n        getPages: [\n          GetPage(name: '/', page: () => const Home()),\n          GetPage(\n            name: '/first',\n            page: () => const FirstScreen(),\n            middlewares: [RedirectMiddlewareNull()],\n          ),\n          GetPage(name: '/second', page: () => const SecondScreen()),\n          GetPage(name: '/third', page: () => const ThirdScreen()),\n        ],\n      ),\n    );\n\n    // Act\n    await tester.pumpAndSettle();\n    Get.toNamed('/first');\n    await tester.pumpAndSettle();\n\n    // Assert\n    expect(find.byType(Home), findsOneWidget);\n    expect(find.byType(FirstScreen), findsNothing);\n    expect(Get.currentRoute, '/');\n  });\n\n  testWidgets(\"Middleware should be bypassed\", (tester) async {\n    // Test setup\n    await tester.pumpWidget(\n      GetMaterialApp(\n        initialRoute: '/',\n        getPages: [\n          GetPage(name: '/', page: () => const Home()),\n          GetPage(\n            name: '/first',\n            page: () => const FirstScreen(),\n            middlewares: [RedirectBypassMiddleware()],\n          ),\n          GetPage(name: '/second', page: () => const SecondScreen()),\n          GetPage(name: '/third', page: () => const ThirdScreen()),\n        ],\n      ),\n    );\n\n    // Act\n    await tester.pumpAndSettle();\n    Get.toNamed('/first');\n    await tester.pumpAndSettle();\n\n    // Assert\n    expect(find.byType(FirstScreen), findsOneWidget);\n    expect(find.byType(SecondScreen), findsNothing);\n    expect(find.byType(Home), findsNothing);\n    expect(Get.currentRoute, '/first');\n  });\n\n  testWidgets(\"Middleware should redirect twice\", (tester) async {\n    // Test setup\n    await tester.pumpWidget(\n      GetMaterialApp(\n        initialRoute: '/',\n        getPages: [\n          GetPage(name: '/', page: () => const Home()),\n          GetPage(\n            name: '/first',\n            page: () => const FirstScreen(),\n            middlewares: [RedirectMiddleware()],\n          ),\n          GetPage(name: '/second', page: () => const SecondScreen()),\n          GetPage(name: '/third', page: () => const ThirdScreen()),\n          GetPage(\n            name: '/fourth',\n            page: () => const FourthScreen(),\n            middlewares: [Redirect2Middleware()],\n          ),\n        ],\n      ),\n    );\n\n    // Act\n    Get.toNamed('/fourth');\n    await tester.pumpAndSettle();\n\n    // Assert\n    expect(find.byType(SecondScreen), findsOneWidget);\n    expect(find.byType(FirstScreen), findsNothing);\n    expect(Get.currentRoute, '/second');\n  });\n\n  testWidgets(\"Navigation history should be correct after redirects\",\n      (tester) async {\n    // Test setup\n    await tester.pumpWidget(\n      GetMaterialApp(\n        initialRoute: '/',\n        getPages: [\n          GetPage(name: '/', page: () => const Home()),\n          GetPage(\n            name: '/first',\n            page: () => const FirstScreen(),\n            middlewares: [RedirectMiddleware()],\n          ),\n          GetPage(name: '/second', page: () => const SecondScreen()),\n        ],\n      ),\n    );\n\n    // Act\n    Get.toNamed('/first');\n    await tester.pumpAndSettle();\n\n    // Assert\n    expect(Get.currentRoute, '/second');\n    expect(Get.previousRoute, '/');\n\n    // Act: go back\n    Get.back();\n    await tester.pumpAndSettle();\n\n    // Assert\n    expect(find.byType(Home), findsOneWidget);\n    expect(Get.currentRoute, '/');\n  });\n}\n"
  },
  {
    "path": "test/navigation/parse_route_test.dart",
    "content": "import 'package:flutter/cupertino.dart';\nimport 'package:flutter_test/flutter_test.dart';\nimport 'package:get/get.dart';\n\nvoid main() {\n  test('Parse Page with children', () {\n    final testParams = {'hi': 'value'};\n    final pageTree = GetPage(\n      name: '/city',\n      page: () => Container(),\n      children: [\n        GetPage(\n          name: '/home',\n          page: () => Container(),\n          transition: Transition.rightToLeftWithFade,\n          children: [\n            GetPage(\n              name: '/bed-room',\n              transition: Transition.size,\n              page: () => Container(),\n            ),\n            GetPage(\n              name: '/living-room',\n              transition: Transition.topLevel,\n              page: () => Container(),\n            ),\n          ],\n        ),\n        GetPage(\n          name: '/work',\n          transition: Transition.upToDown,\n          page: () => Container(),\n          children: [\n            GetPage(\n              name: '/office',\n              transition: Transition.zoom,\n              page: () => Container(),\n              children: [\n                GetPage(\n                  name: '/pen',\n                  transition: Transition.cupertino,\n                  page: () => Container(),\n                  parameters: testParams,\n                ),\n                GetPage(\n                  name: '/paper',\n                  page: () => Container(),\n                  transition: Transition.downToUp,\n                ),\n              ],\n            ),\n            GetPage(\n              name: '/meeting-room',\n              transition: Transition.fade,\n              page: () => Container(),\n            ),\n          ],\n        ),\n      ],\n    );\n\n    final tree = ParseRouteTree(routes: <GetPage>[]);\n\n    tree.addRoute(pageTree);\n\n    // tree.addRoute(pageTree);\n    const searchRoute = '/city/work/office/pen';\n    final match = tree.matchRoute(searchRoute);\n    expect(match, isNotNull);\n    expect(match.route!.name, searchRoute);\n    final testRouteParam = match.route!.parameters!;\n    for (final tParam in testParams.entries) {\n      expect(testRouteParam[tParam.key], tParam.value);\n    }\n  });\n\n  test('Parse Page without children', () {\n    final pageTree = [\n      GetPage(\n          name: '/city',\n          page: () => Container(),\n          transition: Transition.cupertino),\n      GetPage(\n          name: '/city/home',\n          page: () => Container(),\n          transition: Transition.downToUp),\n      GetPage(\n          name: '/city/home/bed-room',\n          page: () => Container(),\n          transition: Transition.fade),\n      GetPage(\n          name: '/city/home/living-room',\n          page: () => Container(),\n          transition: Transition.fadeIn),\n      GetPage(\n          name: '/city/work',\n          page: () => Container(),\n          transition: Transition.leftToRight),\n      GetPage(\n          name: '/city/work/office',\n          page: () => Container(),\n          transition: Transition.leftToRightWithFade),\n      GetPage(\n          name: '/city/work/office/pen',\n          page: () => Container(),\n          transition: Transition.native),\n      GetPage(\n          name: '/city/work/office/paper',\n          page: () => Container(),\n          transition: Transition.noTransition),\n      GetPage(\n          name: '/city/work/meeting-room',\n          page: () => Container(),\n          transition: Transition.rightToLeft),\n    ];\n\n    final tree = ParseRouteTree(routes: pageTree);\n\n    // for (var p in pageTree) {\n    //   tree.addRoute(p);\n    // }\n\n    const searchRoute = '/city/work/office/pen';\n    final match = tree.matchRoute(searchRoute);\n    expect(match, isNotNull);\n    expect(match.route!.name, searchRoute);\n  });\n\n  testWidgets(\n    'test params from dynamic route',\n    (tester) async {\n      await tester.pumpWidget(GetMaterialApp(\n        initialRoute: '/first/juan',\n        getPages: [\n          GetPage(page: () => Container(), name: '/first/:name'),\n          GetPage(page: () => Container(), name: '/second/:id'),\n          GetPage(page: () => Container(), name: '/third'),\n          GetPage(page: () => Container(), name: '/last/:id/:name/profile'),\n          GetPage(page: () => Container(), name: '/first/second/:token')\n        ],\n      ));\n\n      expect(Get.parameters['name'], 'juan');\n\n      Get.toNamed('/second/1234');\n\n      await tester.pumpAndSettle();\n\n      expect(Get.parameters['id'], '1234');\n\n      Get.toNamed('/third?name=jonny&job=dev');\n\n      await tester.pumpAndSettle();\n\n      expect(Get.parameters['name'], 'jonny');\n      expect(Get.parameters['job'], 'dev');\n\n      Get.toNamed('/last/1234/ana/profile');\n\n      await tester.pumpAndSettle();\n\n      expect(Get.parameters['id'], '1234');\n      expect(Get.parameters['name'], 'ana');\n\n      Get.toNamed('/last/1234/ana/profile?job=dev');\n\n      await tester.pumpAndSettle();\n\n      expect(Get.parameters['id'], '1234');\n      expect(Get.parameters['name'], 'ana');\n      expect(Get.parameters['job'], 'dev');\n\n      Get.toNamed(\n        'https://www.example.com/first/second/fa9662f4-ec3f-11ee-a806-169a3915b383',\n      );\n      await tester.pumpAndSettle();\n      expect(Get.parameters['token'], 'fa9662f4-ec3f-11ee-a806-169a3915b383');\n    },\n  );\n\n  testWidgets(\n    'params in url by parameters',\n    (tester) async {\n      await tester.pumpWidget(GetMaterialApp(\n        initialRoute: '/first/juan',\n        getPages: [\n          GetPage(page: () => Container(), name: '/first/:name'),\n          GetPage(page: () => Container(), name: '/italy'),\n        ],\n      ));\n\n      // Get.parameters = ({\"varginias\": \"varginia\", \"vinis\": \"viniiss\"});\n      var parameters = <String, String>{\n        \"varginias\": \"varginia\",\n        \"vinis\": \"viniiss\"\n      };\n      // print(\"Get.parameters: ${Get.parameters}\");\n      parameters.addAll({\"a\": \"b\", \"c\": \"d\"});\n      Get.toNamed(\"/italy\", parameters: parameters);\n\n      await tester.pumpAndSettle();\n      expect(Get.parameters['varginias'], 'varginia');\n      expect(Get.parameters['vinis'], 'viniiss');\n      expect(Get.parameters['a'], 'b');\n      expect(Get.parameters['c'], 'd');\n    },\n  );\n}\n"
  },
  {
    "path": "test/navigation/root_widget_test.dart",
    "content": "// import 'package:flutter_test/flutter_test.dart';\n// import 'package:get/get.dart';\n\nvoid main() {\n  // testWidgets(\n  //   \"GetMaterialApp with routes null\",\n  //   (tester) async {\n  //     expect(\n  //         () => GetMaterialApp(\n  //               routes: null,\n  //             ),\n  //         throwsAssertionError);\n  //   },\n  // );\n\n  // testWidgets(\n  //   \"GetMaterialApp with navigatorObservers null\",\n  //   (tester) async {\n  //     expect(\n  //         () => GetMaterialApp(\n  //               navigatorObservers: null,\n  //             ),\n  //         throwsAssertionError);\n  //   },\n  // );\n  // testWidgets(\n  //   \"GetMaterialApp with title null\",\n  //   (tester) async {\n  //     expect(\n  //         () => GetMaterialApp(\n  //               title: null,\n  //             ),\n  //         throwsAssertionError);\n  //   },\n  // );\n  // testWidgets(\n  //   \"GetMaterialApp with debugShowMaterialGrid null\",\n  //   (test) async {\n  //     expect(\n  //       () => GetMaterialApp(\n  //         debugShowMaterialGrid: null,\n  //       ),\n  //       throwsAssertionError,\n  //     );\n  //   },\n  // );\n  // testWidgets(\n  //   \"GetMaterialApp with showPerformanceOverlay null\",\n  //   (test) async {\n  //     expect(\n  //       () => GetMaterialApp(\n  //         showPerformanceOverlay: null,\n  //       ),\n  //       throwsAssertionError,\n  //     );\n  //   },\n  // );\n  // testWidgets(\n  //   \"GetMaterialApp with showSemanticsDebugger null\",\n  //   (test) async {\n  //     expect(\n  //       () => GetMaterialApp(\n  //         showSemanticsDebugger: null,\n  //       ),\n  //       throwsAssertionError,\n  //     );\n  //   },\n  // );\n  // testWidgets(\n  //   \"GetMaterialApp with debugShowCheckedModeBanner null\",\n  //   (tester) async {\n  //     expect(\n  //         () => GetMaterialApp(\n  //               debugShowCheckedModeBanner: null,\n  //             ),\n  //         throwsAssertionError);\n  //   },\n  // );\n\n  // testWidgets(\n  //   \"GetMaterialApp with checkerboardRasterCacheImages null\",\n  //   (tester) async {\n  //     expect(\n  //         () => GetMaterialApp(\n  //               checkerboardRasterCacheImages: null,\n  //             ),\n  //         throwsAssertionError);\n  //   },\n  // );\n\n  // testWidgets(\n  //   \"GetMaterialApp with checkerboardOffscreenLayers null\",\n  //   (tester) async {\n  //     expect(\n  //       () => GetMaterialApp(\n  //         checkerboardOffscreenLayers: null,\n  //       ),\n  //       throwsAssertionError,\n  //     );\n  //   },\n  // );\n}\n"
  },
  {
    "path": "test/navigation/routes_test.dart",
    "content": "void main() {\n  // testWidgets('Back swipe dismiss interrupted by route push',\n  // (tester) async {\n  //   // final scaffoldKey = GlobalKey();\n\n  //   await tester.pumpWidget(\n  //     GetCupertinoApp(\n  //       popGesture: true,\n  //       home: CupertinoPageScaffold(\n  //         // key: scaffoldKey,\n  //         child: Center(\n  //           child: CupertinoButton(\n  //             onPressed: () {\n  //               Get.to(\n  //                   () => CupertinoPageScaffold(\n  //                         child: Center(child: Text('route')),\n  //                       ),\n  //                   preventDuplicateHandlingMode:\n  //                       PreventDuplicateHandlingMode.Recreate);\n  //             },\n  //             child: const Text('push'),\n  //           ),\n  //         ),\n  //       ),\n  //     ),\n  //   );\n\n  //   await tester.pumpAndSettle();\n\n  //   // Check the basic iOS back-swipe dismiss transition. Dragging the pushed\n  //   // route halfway across the screen will trigger the iOS dismiss animation\n\n  //   await tester.tap(find.text('push'));\n  //   await tester.pumpAndSettle();\n  //   expect(find.text('route'), findsOneWidget);\n  //   expect(find.text('push'), findsNothing);\n\n  //   var gesture = await tester.startGesture(const Offset(5, 300));\n  //   await gesture.moveBy(const Offset(400, 0));\n  //   await gesture.up();\n  //   await tester.pump();\n  //   expect(\n  //     // The 'route' route has been dragged to the right, halfway across\n  //     // the screen\n  //     tester.getTopLeft(find.ancestor(\n  //         of: find.text('route'),\n  //         matching: find.byType(CupertinoPageScaffold))),\n  //     const Offset(400, 0),\n  //   );\n  //   expect(\n  //     // The 'push' route is sliding in from the left.\n  //     tester\n  //         .getTopLeft(find.ancestor(\n  //             of: find.text('push'),\n  //             matching: find.byType(CupertinoPageScaffold)))\n  //         .dx,\n  //     moreOrLessEquals(-(400 / 3), epsilon: 1),\n  //   );\n  //   await tester.pumpAndSettle();\n  //   expect(find.text('push'), findsOneWidget);\n  //   expect(\n  //     tester.getTopLeft(find.ancestor(\n  //         of: find.text('push'),\n  // matching: find.byType(CupertinoPageScaffold))),\n  //     Offset.zero,\n  //   );\n  //   expect(find.text('route'), findsNothing);\n\n  //   // Run the dismiss animation 60%, which exposes the route \"push\" button,\n  //   // and then press the button.\n\n  //   await tester.tap(find.text('push'));\n  //   await tester.pumpAndSettle();\n  //   expect(find.text('route'), findsOneWidget);\n  //   expect(find.text('push'), findsNothing);\n\n  //   gesture = await tester.startGesture(const Offset(5, 300));\n  //   await gesture.moveBy(const Offset(400, 0)); // Drag halfway.\n  //   await gesture.up();\n  //   // Trigger the snapping animation.\n  //   // Since the back swipe drag was brought to >=50% of the screen, it will\n  //   // self snap to finish the pop transition as the gesture is lifted.\n  //   //\n  //   // This drag drop animation is 400ms when dropped exactly halfway\n  //   // (800 / [pixel distance remaining], see\n  //   // _CupertinoBackGestureController.dragEnd). It follows a curve that is very\n  //   // steep initially.\n  //   await tester.pump();\n  //   expect(\n  //     tester.getTopLeft(find.ancestor(\n  //         of: find.text('route'),\n  //         matching: find.byType(CupertinoPageScaffold))),\n  //     const Offset(400, 0),\n  //   );\n  //   // Let the dismissing snapping animation go 60%.\n  //   await tester.pump(const Duration(milliseconds: 240));\n  //   expect(\n  //     tester\n  //         .getTopLeft(find.ancestor(\n  //             of: find.text('route'),\n  //             matching: find.byType(CupertinoPageScaffold)))\n  //         .dx,\n  //     moreOrLessEquals(798, epsilon: 1),\n  //   );\n  // });\n}\n"
  },
  {
    "path": "test/navigation/snackbar_test.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_test/flutter_test.dart';\nimport 'package:get/get.dart';\n\nvoid main() {\n  testWidgets(\"test if Get.isSnackbarOpen works with Get.snackbar\",\n      (tester) async {\n    await tester.pumpWidget(\n      GetMaterialApp(\n        popGesture: true,\n        home: ElevatedButton(\n          child: const Text('Open Snackbar'),\n          onPressed: () {\n            Get.snackbar(\n              'title',\n              \"message\",\n              duration: const Duration(seconds: 1),\n              mainButton:\n                  TextButton(onPressed: () {}, child: const Text('button')),\n              isDismissible: false,\n            );\n          },\n        ),\n      ),\n    );\n\n    await tester.pump();\n\n    expect(Get.isSnackbarOpen, false);\n    await tester.tap(find.text('Open Snackbar'));\n\n    expect(Get.isSnackbarOpen, true);\n    await tester.pump(const Duration(seconds: 1));\n    expect(Get.isSnackbarOpen, false);\n  });\n\n  testWidgets(\"Get.rawSnackbar test\", (tester) async {\n    await tester.pumpWidget(\n      GetMaterialApp(\n        popGesture: true,\n        home: ElevatedButton(\n          child: const Text('Open Snackbar'),\n          onPressed: () {\n            Get.rawSnackbar(\n              title: 'title',\n              message: \"message\",\n              onTap: (_) {},\n              shouldIconPulse: true,\n              icon: const Icon(Icons.alarm),\n              showProgressIndicator: true,\n              duration: const Duration(seconds: 1),\n              isDismissible: true,\n              leftBarIndicatorColor: Colors.amber,\n              overlayBlur: 1.0,\n            );\n          },\n        ),\n      ),\n    );\n\n    await tester.pump();\n\n    expect(Get.isSnackbarOpen, false);\n    await tester.tap(\n      find.text('Open Snackbar'),\n    );\n\n    expect(Get.isSnackbarOpen, true);\n    await tester.pump(const Duration(seconds: 1));\n    expect(Get.isSnackbarOpen, false);\n  });\n\n  testWidgets(\"test snackbar queue\", (tester) async {\n    const messageOne = Text('title');\n\n    const messageTwo = Text('titleTwo');\n\n    await tester.pumpWidget(\n      GetMaterialApp(\n        popGesture: true,\n        home: ElevatedButton(\n          child: const Text('Open Snackbar'),\n          onPressed: () {\n            Get.rawSnackbar(\n                messageText: messageOne, duration: const Duration(seconds: 1));\n            Get.rawSnackbar(\n                messageText: messageTwo, duration: const Duration(seconds: 1));\n          },\n        ),\n      ),\n    );\n\n    await tester.pump();\n\n    expect(Get.isSnackbarOpen, false);\n    await tester.tap(find.text('Open Snackbar'));\n    expect(Get.isSnackbarOpen, true);\n\n    await tester.pump(const Duration(milliseconds: 500));\n    expect(find.text('title'), findsOneWidget);\n    expect(find.text('titleTwo'), findsNothing);\n    await tester.pump(const Duration(milliseconds: 500));\n    expect(find.text('title'), findsNothing);\n    expect(find.text('titleTwo'), findsOneWidget);\n    Get.closeAllSnackbars();\n    await tester.pumpAndSettle();\n  });\n\n  testWidgets(\"test snackbar dismissible\", (tester) async {\n    const dismissDirection = DismissDirection.down;\n    const snackBarTapTarget = Key('snackbar-tap-target');\n\n    const GetSnackBar getBar = GetSnackBar(\n      key: ValueKey('dismissible'),\n      message: 'bar1',\n      duration: Duration(seconds: 2),\n      isDismissible: true,\n      snackPosition: SnackPosition.bottom,\n      dismissDirection: dismissDirection,\n    );\n\n    await tester.pumpWidget(GetMaterialApp(\n      home: Scaffold(\n        body: Builder(\n          builder: (context) {\n            return Column(\n              children: <Widget>[\n                GestureDetector(\n                  key: snackBarTapTarget,\n                  onTap: () {\n                    Get.showSnackbar(getBar);\n                  },\n                  behavior: HitTestBehavior.opaque,\n                  child: const SizedBox(\n                    height: 100.0,\n                    width: 100.0,\n                  ),\n                ),\n              ],\n            );\n          },\n        ),\n      ),\n    ));\n\n    await tester.pump();\n\n    expect(Get.isSnackbarOpen, false);\n    expect(find.text('bar1'), findsNothing);\n\n    await tester.tap(find.byKey(snackBarTapTarget));\n    await tester.pumpAndSettle();\n\n    expect(Get.isSnackbarOpen, true);\n    await tester.pump(const Duration(milliseconds: 500));\n    expect(find.byWidget(getBar), findsOneWidget);\n    await tester.ensureVisible(find.byWidget(getBar));\n    await tester.drag(find.byType(Dismissible), const Offset(0.0, 50.0));\n    await tester.pumpAndSettle();\n    await tester.pump(const Duration(milliseconds: 500));\n    expect(Get.isSnackbarOpen, false);\n  });\n\n  testWidgets(\"test snackbar onTap\", (tester) async {\n    const dismissDirection = DismissDirection.vertical;\n    const snackBarTapTarget = Key('snackbar-tap-target');\n    var counter = 0;\n\n    late final GetSnackBar getBar;\n\n    late final SnackbarController getBarController;\n\n    await tester.pumpWidget(GetMaterialApp(\n      home: Scaffold(\n        body: Builder(\n          builder: (context) {\n            return Column(\n              children: <Widget>[\n                GestureDetector(\n                  key: snackBarTapTarget,\n                  onTap: () {\n                    getBar = GetSnackBar(\n                      message: 'bar1',\n                      onTap: (_) {\n                        counter++;\n                      },\n                      duration: const Duration(seconds: 2),\n                      isDismissible: true,\n                      dismissDirection: dismissDirection,\n                    );\n                    getBarController = Get.showSnackbar(getBar);\n                  },\n                  behavior: HitTestBehavior.opaque,\n                  child: const SizedBox(\n                    height: 100.0,\n                    width: 100.0,\n                  ),\n                ),\n              ],\n            );\n          },\n        ),\n      ),\n    ));\n\n    await tester.pumpAndSettle();\n\n    expect(Get.isSnackbarOpen, false);\n    expect(find.text('bar1'), findsNothing);\n\n    await tester.tap(find.byKey(snackBarTapTarget));\n    await tester.pumpAndSettle();\n\n    expect(Get.isSnackbarOpen, true);\n    await tester.pump(const Duration(milliseconds: 500));\n    expect(find.byWidget(getBar), findsOneWidget);\n    await tester.ensureVisible(find.byWidget(getBar));\n    await tester.tap(find.byWidget(getBar));\n    expect(counter, 1);\n    await tester.pump(const Duration(milliseconds: 3000));\n    await getBarController.close(withAnimations: false);\n  });\n\n  testWidgets(\"Get test actions and icon\", (tester) async {\n    const icon = Icon(Icons.alarm);\n    final action = TextButton(onPressed: () {}, child: const Text('button'));\n\n    late final GetSnackBar getBar;\n\n    await tester.pumpWidget(const GetMaterialApp(home: Scaffold()));\n\n    await tester.pump();\n\n    expect(Get.isSnackbarOpen, false);\n    expect(find.text('bar1'), findsNothing);\n\n    getBar = GetSnackBar(\n      message: 'bar1',\n      icon: icon,\n      mainButton: action,\n      leftBarIndicatorColor: Colors.yellow,\n      showProgressIndicator: true,\n      // maxWidth: 100,\n      borderColor: Colors.red,\n      duration: const Duration(seconds: 1),\n      isDismissible: false,\n    );\n    Get.showSnackbar(getBar);\n\n    expect(Get.isSnackbarOpen, true);\n    await tester.pump(const Duration(milliseconds: 500));\n    expect(find.byWidget(getBar), findsOneWidget);\n    expect(find.byWidget(icon), findsOneWidget);\n    expect(find.byWidget(action), findsOneWidget);\n    await tester.pump(const Duration(milliseconds: 500));\n\n    expect(Get.isSnackbarOpen, false);\n  });\n}\n"
  },
  {
    "path": "test/navigation/utils/wrapper.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:get/get.dart';\n\nclass Wrapper extends StatelessWidget {\n  final Widget? child;\n  final List<GetPage>? namedRoutes;\n  final String? initialRoute;\n  final Transition? defaultTransition;\n\n  const Wrapper({\n    super.key,\n    this.child,\n    this.namedRoutes,\n    this.initialRoute,\n    this.defaultTransition,\n  });\n\n  @override\n  Widget build(BuildContext context) {\n    return GetMaterialApp(\n      defaultTransition: defaultTransition,\n      initialRoute: initialRoute,\n      translations: WrapperTranslations(),\n      locale: WrapperTranslations.locale,\n      getPages: namedRoutes,\n      home: namedRoutes == null\n          ? Scaffold(\n              body: child,\n            )\n          : null,\n    );\n  }\n}\n\nclass WrapperNamed extends StatelessWidget {\n  final Widget? child;\n  final List<GetPage>? namedRoutes;\n  final String? initialRoute;\n  final Transition? defaultTransition;\n\n  const WrapperNamed({\n    super.key,\n    this.child,\n    this.namedRoutes,\n    this.initialRoute,\n    this.defaultTransition,\n  });\n\n  @override\n  Widget build(BuildContext context) {\n    return GetMaterialApp(\n      defaultTransition: defaultTransition,\n      initialRoute: initialRoute,\n      getPages: namedRoutes,\n    );\n  }\n}\n\nclass WrapperTranslations extends Translations {\n  static const fallbackLocale = Locale('en', 'US');\n  static Locale? get locale => const Locale('en', 'US');\n  @override\n  Map<String, Map<String, String>> get keys => {\n        'en_US': {\n          'covid': 'Corona Virus',\n          'total_confirmed': 'Total Confirmed',\n          'total_deaths': 'Total Deaths',\n        },\n        'pt_BR': {\n          'covid': 'Corona Vírus',\n          'total_confirmed': 'Total confirmado',\n          'total_deaths': 'Total de mortes',\n        },\n      };\n}\n"
  },
  {
    "path": "test/rx/rx_workers_test.dart",
    "content": "import 'dart:async';\n\nimport 'package:flutter_test/flutter_test.dart';\nimport 'package:get/get.dart';\n\nvoid main() {\n  test('once', () async {\n    final count = 0.obs;\n    var result = -1;\n    once(count, (dynamic val) {\n      result = val as int;\n    });\n    count.value++;\n    await Future.delayed(Duration.zero);\n    expect(1, result);\n    count.value++;\n    await Future.delayed(Duration.zero);\n    expect(1, result);\n    count.value++;\n    await Future.delayed(Duration.zero);\n    expect(1, result);\n  });\n\n  test('ever', () async {\n    final count = 0.obs;\n    var result = -1;\n    ever<int>(count, (value) {\n      result = value;\n    });\n    count.value++;\n    await Future.delayed(Duration.zero);\n    expect(1, result);\n    count.value++;\n    await Future.delayed(Duration.zero);\n    expect(2, result);\n    count.value++;\n    await Future.delayed(Duration.zero);\n    expect(3, result);\n  });\n\n  test('debounce', () async {\n    final count = 0.obs;\n    int? result = -1;\n    debounce(count, (dynamic val) {\n      // print(_);\n      result = val as int?;\n    }, time: const Duration(milliseconds: 100));\n\n    count.value++;\n    count.value++;\n    count.value++;\n    count.value++;\n    await Future.delayed(Duration.zero);\n    expect(-1, result);\n    await Future.delayed(const Duration(milliseconds: 100));\n    expect(4, result);\n  });\n\n  test('interval', () async {\n    final count = 0.obs;\n    int? result = -1;\n    interval<int>(count, (v) {\n      result = v;\n    }, time: const Duration(milliseconds: 100));\n\n    count.value++;\n    await Future.delayed(Duration.zero);\n    await Future.delayed(const Duration(milliseconds: 100));\n    expect(result, 1);\n    count.value++;\n    count.value++;\n    count.value++;\n    await Future.delayed(Duration.zero);\n    await Future.delayed(const Duration(milliseconds: 100));\n    expect(result, 2);\n    count.value++;\n    await Future.delayed(Duration.zero);\n    await Future.delayed(const Duration(milliseconds: 100));\n    expect(result, 5);\n  });\n\n  test('bindStream test', () async {\n    int? count = 0;\n    final controller = StreamController<int>();\n    final rx = 0.obs;\n\n    rx.listen((value) {\n      count = value;\n    });\n    rx.bindStream(controller.stream);\n    expect(count, 0);\n    controller.add(555);\n\n    await Future.delayed(Duration.zero);\n    expect(count, 555);\n    controller.close();\n  });\n\n  test('Rx same value will not call the same listener when call', () async {\n    var reactiveInteger = RxInt(2);\n    var timesCalled = 0;\n    reactiveInteger.listen((newInt) {\n      timesCalled++;\n    });\n\n    // we call 3\n    reactiveInteger.call(3);\n    // then repeat twice\n    reactiveInteger.call(3);\n    reactiveInteger.call(3);\n\n    await Future.delayed(const Duration(milliseconds: 100));\n    expect(1, timesCalled);\n  });\n\n  test('Rx different value will call the listener when trigger', () async {\n    var reactiveInteger = RxInt(0);\n    var timesCalled = 0;\n    reactiveInteger.listen((newInt) {\n      timesCalled++;\n    });\n\n    // we call 3\n    reactiveInteger.trigger(1);\n    // then repeat twice\n    reactiveInteger.trigger(2);\n    reactiveInteger.trigger(3);\n\n    await Future.delayed(const Duration(milliseconds: 100));\n\n    expect(3, timesCalled);\n  });\n\n  test('Rx same value will call the listener when trigger', () async {\n    var reactiveInteger = RxInt(2);\n    var timesCalled = 0;\n    reactiveInteger.listen((newInt) {\n      timesCalled++;\n    });\n\n    // we call 3\n    reactiveInteger.trigger(3);\n    // then repeat twice\n    reactiveInteger.trigger(3);\n    reactiveInteger.trigger(3);\n    reactiveInteger.trigger(1);\n\n    await Future.delayed(const Duration(milliseconds: 100));\n    expect(4, timesCalled);\n  });\n\n  test('Rx String with non null values', () async {\n    final reactiveString = Rx<String>(\"abc\");\n    String? currentString;\n    reactiveString.listen((newString) {\n      currentString = newString;\n    });\n\n    expect(reactiveString.endsWith(\"c\"), true);\n\n    // we call 3\n    reactiveString(\"b\");\n\n    await Future.delayed(Duration.zero);\n    expect(currentString, \"b\");\n  });\n\n  test('Rx String with null values', () async {\n    var reactiveString = Rx<String?>(null);\n    String? currentString;\n\n    reactiveString.listen((newString) {\n      currentString = newString;\n    });\n\n    // we call 3\n    reactiveString(\"abc\");\n\n    await Future.delayed(Duration.zero);\n    expect(reactiveString.endsWith(\"c\"), true);\n    expect(currentString, \"abc\");\n  });\n\n  test('Number of times \"ever\" is called in RxList', () async {\n    final list = [1, 2, 3].obs;\n    var count = 0;\n    ever<List<int>>(list, (value) {\n      count++;\n    });\n\n    list.add(4);\n    await Future.delayed(Duration.zero);\n    expect(count, 1);\n\n    count = 0;\n    list.addAll([4, 5]);\n    await Future.delayed(Duration.zero);\n    expect(count, 1);\n\n    count = 0;\n    list.remove(2);\n    await Future.delayed(Duration.zero);\n    expect(count, 1);\n\n    count = 0;\n    list.removeWhere((element) => element == 2);\n    await Future.delayed(Duration.zero);\n    expect(count, 1);\n\n    count = 0;\n    list.retainWhere((element) => element == 1);\n    await Future.delayed(Duration.zero);\n    expect(count, 1);\n  });\n}\n"
  },
  {
    "path": "test/state_manager/get_mixin_state_test.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_test/flutter_test.dart';\nimport 'package:get/get.dart';\nimport 'package:get/get_state_manager/src/simple/mixin_builder.dart';\n\nvoid main() {\n  testWidgets(\"MixinBuilder with reactive and not reactive\", (tester) async {\n    await tester.pumpWidget(\n      MaterialApp(\n        home: MixinBuilder<Controller>(\n          init: Controller(),\n          builder: (controller) {\n            return Column(\n              children: [\n                Text(\n                  'Count: ${controller.counter.value}',\n                ),\n                Text(\n                  'Count2: ${controller.count}',\n                ),\n                Text(\n                  'Double: ${controller.doubleNum.value}',\n                ),\n                Text(\n                  'String: ${controller.string.value}',\n                ),\n                Text(\n                  'List: ${controller.list.length}',\n                ),\n                Text(\n                  'Bool: ${controller.boolean.value}',\n                ),\n                Text(\n                  'Map: ${controller.map.length}',\n                ),\n                TextButton(\n                  child: const Text(\"increment\"),\n                  onPressed: () => controller.increment(),\n                ),\n                TextButton(\n                  child: const Text(\"increment2\"),\n                  onPressed: () => controller.increment2(),\n                )\n              ],\n            );\n          },\n        ),\n      ),\n    );\n\n    expect(find.text(\"Count: 0\"), findsOneWidget);\n    expect(find.text(\"Count2: 0\"), findsOneWidget);\n    expect(find.text(\"Double: 0.0\"), findsOneWidget);\n    expect(find.text(\"String: string\"), findsOneWidget);\n    expect(find.text(\"Bool: true\"), findsOneWidget);\n    expect(find.text(\"List: 0\"), findsOneWidget);\n    expect(find.text(\"Map: 0\"), findsOneWidget);\n\n    Controller.to.increment();\n\n    await tester.pump();\n\n    expect(find.text(\"Count: 1\"), findsOneWidget);\n\n    await tester.tap(find.text('increment'));\n\n    await tester.pump();\n\n    expect(find.text(\"Count: 2\"), findsOneWidget);\n\n    await tester.tap(find.text('increment2'));\n\n    await tester.pump();\n\n    expect(find.text(\"Count2: 1\"), findsOneWidget);\n  });\n\n  // testWidgets(\n  //   \"MixinBuilder with build null\",\n  //   (tester) async {\n  //     expect(\n  //       () => MixinBuilder<Controller>(\n  //         init: Controller(),\n  //         builder: null,\n  //       ),\n  //       throwsAssertionError,\n  //     );\n  //   },\n  // );\n}\n\nclass Controller extends GetxController {\n  static Controller get to => Get.find();\n  int count = 0;\n  RxInt counter = 0.obs;\n  RxDouble doubleNum = 0.0.obs;\n  RxString string = \"string\".obs;\n  RxList list = [].obs;\n  RxMap map = {}.obs;\n  RxBool boolean = true.obs;\n\n  void increment() {\n    counter.value++;\n  }\n\n  void increment2() {\n    count++;\n    update();\n  }\n}\n"
  },
  {
    "path": "test/state_manager/get_obx_test.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_test/flutter_test.dart';\nimport 'package:get/get.dart';\n\nvoid main() {\n  testWidgets(\"GetxController smoke test\", (tester) async {\n    final controller = Get.put(Controller());\n    await tester.pumpWidget(\n      MaterialApp(\n        home: Column(\n          children: [\n            Obx(\n              () => Column(children: [\n                Text('Count: ${controller.counter.value}'),\n                Text('Double: ${controller.doubleNum.value}'),\n                Text('String: ${controller.string.value}'),\n                Text('List: ${controller.list.length}'),\n                Text('Bool: ${controller.boolean.value}'),\n                Text('Map: ${controller.map.length}'),\n                TextButton(\n                  onPressed: controller.increment,\n                  child: const Text(\"increment\"),\n                ),\n                Obx(() => Text('Obx: ${controller.map.length}'))\n              ]),\n            ),\n          ],\n        ),\n      ),\n    );\n\n    expect(find.text(\"Count: 0\"), findsOneWidget);\n    expect(find.text(\"Double: 0.0\"), findsOneWidget);\n    expect(find.text(\"String: string\"), findsOneWidget);\n    expect(find.text(\"Bool: true\"), findsOneWidget);\n    expect(find.text(\"List: 0\"), findsOneWidget);\n    expect(find.text(\"Map: 0\"), findsOneWidget);\n    expect(find.text(\"Obx: 0\"), findsOneWidget);\n\n    Controller.to.increment();\n\n    await tester.pump();\n\n    expect(find.text(\"Count: 1\"), findsOneWidget);\n\n    await tester.tap(find.text('increment'));\n\n    await tester.pump();\n\n    expect(find.text(\"Count: 2\"), findsOneWidget);\n  });\n}\n\nclass Controller extends GetxController {\n  static Controller get to => Get.find();\n\n  RxInt counter = 0.obs;\n  RxDouble doubleNum = 0.0.obs;\n  RxString string = \"string\".obs;\n  RxList list = [].obs;\n  RxMap map = {}.obs;\n  RxBool boolean = true.obs;\n\n  void increment() {\n    counter.value++;\n  }\n}\n"
  },
  {
    "path": "test/state_manager/get_rxstate_test.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_test/flutter_test.dart';\nimport 'package:get/get.dart';\n\nvoid main() {\n  Get.lazyPut<Controller2>(() => Controller2());\n  testWidgets(\"GetxController smoke test\", (tester) async {\n    await tester.pumpWidget(\n      MaterialApp(\n        home: GetX<Controller>(\n          init: Controller(),\n          builder: (controller) {\n            return Column(\n              children: [\n                Text(\n                  'Count: ${controller.counter.value}',\n                ),\n                Text(\n                  'Double: ${controller.doubleNum.value}',\n                ),\n                Text(\n                  'String: ${controller.string.value}',\n                ),\n                Text(\n                  'List: ${controller.list.length}',\n                ),\n                Text(\n                  'Bool: ${controller.boolean.value}',\n                ),\n                Text(\n                  'Map: ${controller.map.length}',\n                ),\n                TextButton(\n                  child: const Text(\"increment\"),\n                  onPressed: () => controller.increment(),\n                ),\n                GetX<Controller2>(builder: (controller) {\n                  return Text('lazy ${controller.lazy.value}');\n                }),\n                GetX<ControllerNonGlobal>(\n                    init: ControllerNonGlobal(),\n                    global: false,\n                    builder: (controller) {\n                      return Text('single ${controller.nonGlobal.value}');\n                    })\n              ],\n            );\n          },\n        ),\n      ),\n    );\n\n    expect(find.text(\"Count: 0\"), findsOneWidget);\n    expect(find.text(\"Double: 0.0\"), findsOneWidget);\n    expect(find.text(\"String: string\"), findsOneWidget);\n    expect(find.text(\"Bool: true\"), findsOneWidget);\n    expect(find.text(\"List: 0\"), findsOneWidget);\n    expect(find.text(\"Map: 0\"), findsOneWidget);\n\n    Controller.to.increment();\n\n    await tester.pump();\n\n    expect(find.text(\"Count: 1\"), findsOneWidget);\n\n    await tester.tap(find.text('increment'));\n\n    await tester.pump();\n\n    expect(find.text(\"Count: 2\"), findsOneWidget);\n    expect(find.text(\"lazy 0\"), findsOneWidget);\n    expect(find.text(\"single 0\"), findsOneWidget);\n  });\n}\n\nclass Controller2 extends GetxController {\n  RxInt lazy = 0.obs;\n}\n\nclass ControllerNonGlobal extends GetxController {\n  RxInt nonGlobal = 0.obs;\n}\n\nclass Controller extends GetxController {\n  static Controller get to => Get.find();\n\n  RxInt counter = 0.obs;\n  RxDouble doubleNum = 0.0.obs;\n  RxString string = \"string\".obs;\n  RxList list = [].obs;\n  RxMap map = {}.obs;\n  RxBool boolean = true.obs;\n\n  void increment() {\n    counter.value++;\n  }\n}\n"
  },
  {
    "path": "test/state_manager/get_state_test.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_test/flutter_test.dart';\nimport 'package:get/get.dart';\n\nvoid main() {\n  Get.lazyPut<Controller2>(() => Controller2());\n  testWidgets(\"GetxController smoke test\", (test) async {\n    await test.pumpWidget(\n      MaterialApp(\n        home: GetBuilder<Controller>(\n          init: Controller(),\n          builder: (controller) => Column(\n            children: [\n              Text(\n                '${controller.counter}',\n              ),\n              TextButton(\n                child: const Text(\"increment\"),\n                onPressed: () => controller.increment(),\n              ),\n              TextButton(\n                child: const Text(\"incrementWithId\"),\n                onPressed: () => controller.incrementWithId(),\n              ),\n              GetBuilder<Controller>(\n                  id: '1',\n                  didChangeDependencies: (_) {\n                    // print(\"didChangeDependencies called\");\n                  },\n                  builder: (controller) {\n                    return Text('id ${controller.counter}');\n                  }),\n              GetBuilder<Controller2>(builder: (controller) {\n                return Text('lazy ${controller.test}');\n              }),\n              GetBuilder<ControllerNonGlobal>(\n                  init: ControllerNonGlobal(),\n                  global: false,\n                  builder: (controller) {\n                    return Text('single ${controller.nonGlobal}');\n                  })\n            ],\n          ),\n        ),\n      ),\n    );\n\n    expect(find.text(\"0\"), findsOneWidget);\n\n    Controller.to.increment();\n\n    await test.pump();\n\n    expect(find.text(\"1\"), findsOneWidget);\n\n    await test.tap(find.text('increment'));\n\n    await test.pump();\n\n    expect(find.text(\"2\"), findsOneWidget);\n\n    await test.tap(find.text('incrementWithId'));\n\n    await test.pump();\n\n    expect(find.text(\"id 3\"), findsOneWidget);\n    expect(find.text(\"lazy 0\"), findsOneWidget);\n    expect(find.text(\"single 0\"), findsOneWidget);\n  });\n\n  // testWidgets(\n  //   \"MixinBuilder with build null\",\n  //   (test) async {\n  //     expect(\n  //       () => GetBuilder<Controller>(\n  //         init: Controller(),\n  //         builder: null,\n  //       ),\n  //       throwsAssertionError,\n  //     );\n  //   },\n  // );\n}\n\nclass Controller extends GetxController {\n  static Controller get to => Get.find();\n\n  int counter = 0;\n\n  void increment() {\n    counter++;\n    update();\n  }\n\n  void incrementWithId() {\n    counter++;\n    update(['1']);\n  }\n}\n\nclass Controller2 extends GetxController {\n  int test = 0;\n}\n\nclass ControllerNonGlobal extends GetxController {\n  int nonGlobal = 0;\n}\n"
  },
  {
    "path": "test/utils/extensions/context_extensions_test.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_test/flutter_test.dart';\nimport 'package:get/get.dart';\n\nimport '../../navigation/utils/wrapper.dart';\n\nvoid main() {\n  testWidgets(\"Get.defaultDialog smoke test\", (tester) async {\n    await tester.pumpWidget(Wrapper(child: Container()));\n    await tester.pumpAndSettle();\n\n    final BuildContext context = tester.element(find.byType(Container));\n\n    var mediaQuery = MediaQuery.of(context);\n    expect(mediaQuery, context.mediaQuery);\n    var mediaQuerySize = mediaQuery.size;\n    expect(mediaQuerySize, context.mediaQuerySize);\n    var theme = Theme.of(context);\n    expect(theme, context.theme);\n    var textTheme = theme.textTheme;\n    expect(textTheme, context.textTheme);\n    var devicePixelRatio = mediaQuery.devicePixelRatio;\n    expect(devicePixelRatio, context.devicePixelRatio);\n    var height = mediaQuerySize.height;\n    expect(height, context.height);\n    final heightTransformer =\n        (mediaQuerySize.height - ((mediaQuerySize.height / 100) * 0)) / 1;\n    expect(heightTransformer, context.heightTransformer());\n    var iconColor = theme.iconTheme.color;\n    expect(iconColor, context.iconColor);\n    var isDarkMode = (theme.brightness == Brightness.dark);\n    expect(isDarkMode, context.isDarkMode);\n    var orientation = mediaQuery.orientation;\n    expect(orientation, context.orientation);\n    var isLandscape = orientation == Orientation.landscape;\n    expect(isLandscape, context.isLandscape);\n    var mediaQueryShortestSide = mediaQuerySize.shortestSide;\n    expect(mediaQueryShortestSide, context.mediaQueryShortestSide);\n    var width = mediaQuerySize.width;\n    expect(width, context.width);\n\n    var isLargeTabletOrWider = (width >= 720);\n    expect(isLargeTabletOrWider, context.isLargeTabletOrWider);\n    var isPhoneOrLess = (width < 600);\n    expect(isPhoneOrLess, context.isPhoneOrLess);\n    var isPortrait = orientation == Orientation.portrait;\n    expect(isPortrait, context.isPortrait);\n    var isSmallTabletOrWider = (width >= 600);\n    expect(isSmallTabletOrWider, context.isSmallTabletOrWider);\n    var isTablet = isSmallTabletOrWider || isLargeTabletOrWider;\n    expect(isTablet, context.isSmallTabletOrWider);\n    var mediaQueryPadding = mediaQuery.padding;\n    expect(mediaQueryPadding, context.mediaQueryPadding);\n    var mediaQueryViewInsets = mediaQuery.viewInsets;\n    expect(mediaQueryViewInsets, context.mediaQueryViewInsets);\n    var mediaQueryViewPadding = mediaQuery.viewPadding;\n    expect(mediaQueryViewPadding, context.mediaQueryViewPadding);\n    var widthTransformer =\n        (mediaQuerySize.width - ((mediaQuerySize.width / 100) * 0)) / 1;\n    expect(widthTransformer, context.widthTransformer());\n    var ratio = heightTransformer / widthTransformer;\n    expect(ratio, context.ratio());\n\n    var showNavbar = (width > 800);\n    expect(showNavbar, context.showNavbar);\n    var textScaleFactor = mediaQuery.textScaler;\n    expect(textScaleFactor, context.textScaleFactor);\n  });\n}\n"
  },
  {
    "path": "test/utils/extensions/double_extensions_test.dart",
    "content": "import 'package:flutter_test/flutter_test.dart';\nimport 'package:get/utils.dart';\n\nvoid main() {\n  group('DoubleExt', () {\n    test('toPrecision', () {\n      expect(3.14159.toPrecision(2), equals(3.14));\n      expect(3.14159.toPrecision(4), equals(3.1416));\n      expect(1.0.toPrecision(0), equals(1.0));\n      expect(123456789.123456789.toPrecision(4), equals(123456789.1235));\n      expect((-3.14159).toPrecision(2), equals(-3.14));\n    });\n\n    test('milliseconds', () {\n      expect(1000.0.ms, equals(const Duration(milliseconds: 1000)));\n      expect(\n          1.5.ms, equals(const Duration(milliseconds: 1, microseconds: 500)));\n      expect((-2000.0).ms, equals(const Duration(milliseconds: -2000)));\n    });\n\n    test('seconds', () {\n      expect(60.0.seconds, equals(const Duration(seconds: 60)));\n      expect(1.5.seconds, equals(const Duration(milliseconds: 1500)));\n      expect((-120.0).seconds, equals(const Duration(seconds: -120)));\n    });\n\n    test('minutes', () {\n      expect(2.5.minutes, equals(const Duration(minutes: 2, seconds: 30)));\n      expect(1.2.minutes, equals(const Duration(seconds: 72)));\n      expect((-3.0).minutes, equals(const Duration(minutes: -3)));\n    });\n\n    test('hours', () {\n      expect(1.5.hours, equals(const Duration(hours: 1, minutes: 30)));\n      expect(0.25.hours, equals(const Duration(minutes: 15)));\n      expect((-2.0).hours, equals(const Duration(hours: -2)));\n    });\n\n    test('days', () {\n      expect(1.5.days, equals(const Duration(days: 1, hours: 12)));\n      expect(0.25.days, equals(const Duration(hours: 6)));\n      expect((-3.0).days, equals(const Duration(days: -3)));\n    });\n  });\n}\n"
  },
  {
    "path": "test/utils/extensions/dynamic_extensions_test.dart",
    "content": "import 'package:flutter_test/flutter_test.dart';\nimport 'package:get/utils.dart';\n\nvoid main() {\n  test('String test', () {\n    var value = 'string';\n    var expected = '';\n    void logFunction(String prefix, dynamic value, String info,\n        {bool isError = false}) {\n      expected = '$prefix $value $info'.trim();\n    }\n\n    value.printError(logFunction: logFunction);\n    expect(expected, 'Error: String string');\n  });\n  test('Int test', () {\n    var value = 1;\n    var expected = '';\n    void logFunction(String prefix, dynamic value, String info,\n        {bool isError = false}) {\n      expected = '$prefix $value $info'.trim();\n    }\n\n    value.printError(logFunction: logFunction);\n    expect(expected, 'Error: int 1');\n  });\n  test('Double test', () {\n    var value = 1.0;\n    var expected = '';\n    void logFunction(String prefix, dynamic value, String info,\n        {bool isError = false}) {\n      expected = '$prefix $value $info'.trim();\n    }\n\n    value.printError(logFunction: logFunction);\n    expect(expected, 'Error: double 1.0');\n  });\n}\n"
  },
  {
    "path": "test/utils/extensions/int_extensions_test.dart",
    "content": "import 'package:flutter_test/flutter_test.dart';\nimport 'package:get/get.dart';\n\nvoid main() {\n  group('DurationExt', () {\n    test('seconds', () {\n      expect(1.seconds, equals(const Duration(seconds: 1)));\n      expect(\n          2.5.seconds, equals(const Duration(seconds: 2, milliseconds: 500)));\n      expect((-1).seconds, equals(const Duration(seconds: -1)));\n    });\n\n    test('days', () {\n      expect(1.days, equals(const Duration(days: 1)));\n      expect((-1).days, equals(const Duration(days: -1)));\n    });\n\n    test('hours', () {\n      expect(1.hours, equals(const Duration(hours: 1)));\n      expect((-1).hours, equals(const Duration(hours: -1)));\n    });\n\n    test('minutes', () {\n      expect(1.minutes, equals(const Duration(minutes: 1)));\n      expect((-1).minutes, equals(const Duration(minutes: -1)));\n    });\n\n    test('milliseconds', () {\n      expect(1.milliseconds, equals(const Duration(milliseconds: 1)));\n      expect((-1).milliseconds, equals(const Duration(milliseconds: -1)));\n    });\n\n    test('microseconds', () {\n      expect(1.microseconds, equals(const Duration(microseconds: 1)));\n      expect((-1).microseconds, equals(const Duration(microseconds: -1)));\n    });\n\n    test('ms', () {\n      expect(1.ms, equals(const Duration(milliseconds: 1)));\n      expect((-1).ms, equals(const Duration(milliseconds: -1)));\n    });\n  });\n}\n"
  },
  {
    "path": "test/utils/extensions/num_extensions_test.dart",
    "content": "import 'package:flutter_test/flutter_test.dart';\nimport 'package:get/utils.dart';\n\nvoid main() {\n  num x = 5;\n  num y = 7;\n  num z = 5;\n\n  var doubleX = 2.1;\n  var doubleY = 3.1;\n  var doubleZ = 5.0;\n  var pi = 3.14159265359;\n\n  group('num extensions text', () {\n    test('var.isLowerThan(value)', () {\n      expect(x.isLowerThan(y), true);\n      expect(y.isLowerThan(x), false);\n      expect(x.isLowerThan(z), false);\n      expect(doubleX.isLowerThan(doubleY), true);\n      expect(doubleY.isLowerThan(pi), true);\n      expect(x.isLowerThan(doubleX), false);\n      expect(z.isLowerThan(doubleZ), false);\n    });\n    test('var.isGreaterThan(value)', () {\n      expect(x.isGreaterThan(y), false);\n      expect(y.isGreaterThan(x), true);\n      expect(x.isGreaterThan(z), false);\n      expect(doubleX.isGreaterThan(doubleY), false);\n      expect(doubleY.isGreaterThan(pi), false);\n      expect(pi.isGreaterThan(3.14159265359), false);\n      expect(y.isGreaterThan(doubleY), true);\n      expect(z.isGreaterThan(doubleZ), false);\n    });\n    test('var.isEqual(value)', () {\n      expect(x.isEqual(y), false);\n      expect(y.isEqual(x), false);\n      expect(x.isEqual(5), true);\n      expect(y.isEqual(7), true);\n      expect(doubleX.isEqual(doubleY), false);\n      expect(doubleY.isEqual(pi), false);\n      expect(pi.isEqual(3.14159265359), true);\n      expect(z.isEqual(doubleZ), true);\n    });\n  });\n}\n"
  },
  {
    "path": "test/utils/extensions/string_extensions_test.dart",
    "content": "import 'package:flutter_test/flutter_test.dart';\nimport 'package:get/utils.dart';\n\nvoid main() {\n  group('String extensions', () {\n    const text = \"oi\";\n    const digit = \"5\";\n    const specialCaracters = \"#\\$!%@\";\n    const alphaNumeric = \"123asd\";\n    const numbers = \"123\";\n    const letters = \"foo\";\n    // String notInitializedVar;\n\n    test('var.isNum', () {\n      expect(digit.isNum, true);\n      expect(text.isNum, false);\n    });\n\n    test('var.capitalizeAllWordsFirstLetter()', () {\n      final List<String> sentences = [\n        \"getx\",\n        \"this is an example sentence\",\n        \"this is an example sentence with a number 5\",\n        \"this is an example sentence with a number 5 and a special character #\",\n        \"this is an example sentence with a number 5 and a special character # and b letter C\",\n        \"    emm, lemme        think !\",\n        \"Bro, $letters is a good word\",\n        \"THIS IS A SENTENCE WITH ALL CAPITAL LETTERS\",\n        \"\"\n      ];\n      expect(text.capitalizeAllWordsFirstLetter(), \"Oi\");\n      expect(digit.capitalizeAllWordsFirstLetter(), \"5\");\n      expect(specialCaracters.capitalizeAllWordsFirstLetter(), \"#\\$!%@\");\n      expect(alphaNumeric.capitalizeAllWordsFirstLetter(), \"123asd\");\n      expect(numbers.capitalizeAllWordsFirstLetter(), \"123\");\n      expect(letters.capitalizeAllWordsFirstLetter(), \"Foo\");\n      expect(sentences[0].capitalizeAllWordsFirstLetter(), \"Getx\");\n      expect(sentences[1].capitalizeAllWordsFirstLetter(),\n          \"This Is An Example Sentence\");\n      expect(sentences[2].capitalizeAllWordsFirstLetter(),\n          \"This Is An Example Sentence With A Number 5\");\n      expect(sentences[3].capitalizeAllWordsFirstLetter(),\n          \"This Is An Example Sentence With A Number 5 And A Special Character #\");\n      expect(sentences[4].capitalizeAllWordsFirstLetter(),\n          \"This Is An Example Sentence With A Number 5 And A Special Character # And B Letter C\");\n      expect(\n          sentences[5].capitalizeAllWordsFirstLetter(), \"Emm, Lemme Think !\");\n      expect(sentences[6].capitalizeAllWordsFirstLetter(),\n          \"Bro, Foo Is A Good Word\");\n      expect(sentences[7].capitalizeAllWordsFirstLetter(),\n          \"This Is A Sentence With All Capital Letters\");\n      expect(sentences[8].capitalizeAllWordsFirstLetter(), \"\");\n    });\n\n    test('var.isNumericOnly', () {\n      expect(numbers.isNumericOnly, true);\n      expect(letters.isNumericOnly, false);\n      expect(specialCaracters.isNumericOnly, false);\n      expect(alphaNumeric.isNumericOnly, false);\n    });\n\n    test('var.isAlphabetOnly', () {\n      expect(alphaNumeric.isAlphabetOnly, false);\n      expect(numbers.isAlphabetOnly, false);\n      expect(letters.isAlphabetOnly, true);\n    });\n\n    test('var.isBool', () {\n      const trueString = 'true';\n      // expect(notInitializedVar.isBool, false);\n      expect(letters.isBool, false);\n      expect(trueString.isBool, true);\n    });\n\n    test('var.isVectorFileName', () {\n      const path = \"logo.svg\";\n      const fullPath = \"C:/Users/Getx/Documents/logo.svg\";\n      expect(path.isVectorFileName, true);\n      expect(fullPath.isVectorFileName, true);\n      expect(alphaNumeric.isVectorFileName, false);\n    });\n\n    test('var.isImageFileName', () {\n      const jpgPath = \"logo.jpg\";\n      const jpegPath = \"logo.jpeg\";\n      const pngPath = \"logo.png\";\n      const gifPath = \"logo.gif\";\n      const bmpPath = \"logo.bmp\";\n      const svgPath = \"logo.svg\";\n\n      expect(jpgPath.isImageFileName, true);\n      expect(jpegPath.isImageFileName, true);\n      expect(pngPath.isImageFileName, true);\n      expect(gifPath.isImageFileName, true);\n      expect(bmpPath.isImageFileName, true);\n      expect(svgPath.isImageFileName, false);\n    });\n\n    test('var.isAudioFileName', () {\n      const mp3Path = \"logo.mp3\";\n      const wavPath = \"logo.wav\";\n      const wmaPath = \"logo.wma\";\n      const amrPath = \"logo.amr\";\n      const oggPath = \"logo.ogg\";\n      const svgPath = \"logo.svg\";\n\n      expect(mp3Path.isAudioFileName, true);\n      expect(wavPath.isAudioFileName, true);\n      expect(wmaPath.isAudioFileName, true);\n      expect(amrPath.isAudioFileName, true);\n      expect(oggPath.isAudioFileName, true);\n      expect(svgPath.isAudioFileName, false);\n    });\n\n    test('var.isVideoFileName', () {\n      const mp4Path = \"logo.mp4\";\n      const aviPath = \"logo.avi\";\n      const wmvPath = \"logo.wmv\";\n      const rmvbPath = \"logo.rmvb\";\n      const mpgPath = \"logo.mpg\";\n      const mpegPath = \"logo.mpeg\";\n      const threegpPath = \"logo.3gp\";\n      const svgPath = \"logo.svg\";\n\n      expect(mp4Path.isVideoFileName, true);\n      expect(aviPath.isVideoFileName, true);\n      expect(wmvPath.isVideoFileName, true);\n      expect(rmvbPath.isVideoFileName, true);\n      expect(mpgPath.isVideoFileName, true);\n      expect(mpegPath.isVideoFileName, true);\n      expect(threegpPath.isVideoFileName, true);\n      expect(svgPath.isAudioFileName, false);\n    });\n\n    test('var.isTxtFileName', () {\n      const txtPath = 'file.txt';\n      expect(txtPath.isTxtFileName, true);\n      expect(alphaNumeric.isTxtFileName, false);\n    });\n\n    test('var.isDocumentFileName', () {\n      const docPath = \"file.doc\";\n      const docxPath = \"file.docx\";\n\n      expect(docPath.isDocumentFileName, true);\n      expect(docxPath.isDocumentFileName, true);\n      expect(alphaNumeric.isDocumentFileName, false);\n    });\n\n    test('var.isExcelFileName', () {\n      const xlsPath = \"file.xls\";\n      const xlsxPath = \"file.xlsx\";\n\n      expect(xlsPath.isExcelFileName, true);\n      expect(xlsxPath.isExcelFileName, true);\n      expect(alphaNumeric.isExcelFileName, false);\n    });\n\n    test('var.isPPTFileName', () {\n      const pptPath = \"file.ppt\";\n      const pptxPath = \"file.pptx\";\n\n      expect(pptPath.isPPTFileName, true);\n      expect(pptxPath.isPPTFileName, true);\n      expect(alphaNumeric.isPPTFileName, false);\n    });\n\n    test('var.isAPKFileName', () {\n      const apkPath = \"file.apk\";\n\n      expect(apkPath.isAPKFileName, true);\n      expect(alphaNumeric.isAPKFileName, false);\n    });\n\n    test('var.isPDFFileName', () {\n      const pdfPath = \"file.pdf\";\n\n      expect(pdfPath.isPDFFileName, true);\n      expect(alphaNumeric.isPDFFileName, false);\n    });\n    test('var.isHTMLFileName', () {\n      const htmlPath = \"file.html\";\n\n      expect(htmlPath.isHTMLFileName, true);\n      expect(alphaNumeric.isHTMLFileName, false);\n    });\n    test('var.isURL', () {\n      // Url's generated in https://www.randomlists.com/urls\n      final urls = [\n        'http://www.example.com/aunt/babies.aspx#act',\n        'http://adjustment.example.com/bedroom/animal.htm',\n        'http://blade.example.com/arch/basketball',\n        'https://www.example.com/air/advice.php',\n        'http://www.example.com/balance/arch.html?blow=aftermath&bait=bath',\n        'http://authority.example.com/',\n        'http://example.com/advice.html',\n        'https://www.example.com/',\n        'https://www.example.com/bee?act=art&bells=board',\n        'http://example.org/',\n        'https://www.example.com/',\n        'https://example.com/bed',\n        'https://www.example.edu/acoustics',\n        'https://www.example.com/bells',\n        'http://board.example.com/',\n        'http://book.example.com/afterthought?advertisement=ball&birth=argument',\n        'http://birds.example.org/ball.aspx?apparatus=border&brother=aftermath',\n        'https://www.example.org/books/book?bedroom=birds',\n        'http://advice.example.com/',\n        'http://example.com/',\n        'http://example.com/bedroom/alarm',\n        'https://example.com/advice/approval',\n        'http://anger.example.net/?breath=brother&air=bell#ball',\n        'http://appliance.example.com/bee/badge',\n        'http://www.example.org/berry.aspx',\n        'http://example.org/',\n        'http://birds.example/',\n      ];\n\n      for (final url in urls) {\n        expect(url.isURL, true);\n      }\n      expect(alphaNumeric.isURL, false);\n    });\n    test('var.isEmail', () {\n      final emails = [\n        'hellfire@comcast.net',\n        'hllam@icloud.com',\n        'tskirvin@live.com',\n        'choset@comcast.net',\n        'parksh@live.com',\n        'kassiesa@yahoo.com',\n        'kramulous@comcast.net',\n        'froodian@me.com',\n        'shawnce@yahoo.ca',\n        'cgreuter@gmail.com',\n        'aprakash@verizon.net',\n        'dhrakar@gmail.com',\n        'wmszeliga@yahoo.ca',\n        'bmorrow@icloud.com',\n        'seurat@comcast.net',\n        'dialworld@yahoo.ca',\n        'johndo@yahoo.ca',\n        'empathy@yahoo.com.pt',\n        'openldap@verizon.net',\n        'elflord@outlook.com',\n        'kaiser@me.com',\n        'carcus@att.net',\n        'garland@hotmail.com',\n        'clkao@yahoo.ca',\n        'daveed@mac.com',\n        'parasite@icloud.com',\n        'drolsky@aol.com',\n        'reziac@outlook.com',\n        'storerm@yahoo.ca',\n        'johnbob@hotmail.com.br',\n      ];\n\n      for (final email in emails) {\n        expect(email.isEmail, true);\n      }\n      expect(alphaNumeric.isEmail, false);\n    });\n    test('var.isPhoneNumber', () {\n      final phoneNumbers = [\n        '+1202-555-0145',\n        '+1202-555-0139',\n        '+1202-555-0101',\n        '+1202-555-0136',\n        '+1202-555-0190',\n        '+1202-555-0156',\n        '(738) 952-5253',\n        '(861) 965-1597',\n        '(732) 372-9760',\n        '(532) 766-4719',\n        '(987) 472-7813',\n        '(455) 443-8171',\n        '(915) 685-8658',\n        '(572) 207-1898',\n        '(81) 6 2499-9538',\n        '(31) 32304-4263',\n        '(64) 25242-6375',\n        '(41) 19308-7925',\n        '(67) 61684-0395',\n        '(60) 54706-3569',\n        '(31) 33110055',\n        '(11) 3344-5599',\n        '(31) 977447788',\n        '(31) 66557744',\n        '(21) 946576541',\n        '(11) 3432-3333',\n        '02131973585858'\n      ];\n\n      for (final phone in phoneNumbers) {\n        // print('testing $phone');\n        expect(phone.isPhoneNumber, true);\n      }\n\n      const bigRandomNumber = '168468468465241327987624987327987';\n      expect(bigRandomNumber.isPhoneNumber, false);\n\n      expect(alphaNumeric.isPhoneNumber, false);\n    });\n    test('var.isDateTime', () {\n      final dateTimes = [\n        '2003-07-05 05:51:47.000Z',\n        '1991-05-11 11:57:30.000Z',\n        '2002-01-04 10:00:41.000Z',\n        '1995-11-04 19:43:25.000Z',\n        '2006-07-12 20:06:46.000Z',\n        '2000-08-10 00:06:23.000Z',\n        '1998-07-31 10:56:50.000Z',\n        '1995-04-27 11:49:34.000Z',\n        '1998-07-26 15:43:11.000Z',\n        '1999-02-04 10:03:01.000Z',\n        '1998-05-02 12:17:55.000Z',\n        '2013-05-26 10:47:22.000Z',\n        '1991-07-07 20:25:42.000Z',\n        '2018-11-03 09:27:38.000Z',\n        '1992-12-22 08:20:26.000Z',\n        '1997-07-01 23:11:59.000Z',\n        '2012-04-13 16:00:04.000Z',\n        '1997-01-06 18:37:51.000Z',\n        '2008-08-23 11:11:29.000Z',\n        '1996-02-06 03:46:43.000Z',\n        '2016-01-03 10:57:15.000Z',\n        '2014-04-16 17:20:50.000Z',\n        '1994-07-13 03:55:16.000Z',\n        '2004-11-15 03:45:11.000Z',\n        '2007-12-18 18:21:21.000Z',\n        '1995-01-31 03:55:44.000Z',\n        '2013-08-09 04:48:37.000Z',\n        '2001-09-07 17:13:55.000Z',\n        '1993-06-18 13:21:21.000Z',\n        '1991-02-06 03:05:47.000Z',\n        '2000-09-22 18:48:55.000Z',\n        '2000-06-01 02:13:57.000Z',\n        '1991-08-07 21:08:35.000Z',\n        '1998-08-15 07:27:12.000Z',\n        '2002-07-03 10:34:25.000Z',\n        '2013-10-05 00:37:45.000Z',\n        '2012-09-10 20:07:21.000Z',\n        '2017-06-18 14:38:06.000Z',\n        '2000-03-09 11:27:49.000Z',\n        '2016-01-16 22:01:20.000Z',\n      ];\n\n      for (final dateTime in dateTimes) {\n        // print('testing $dateTime');\n        expect(dateTime.isDateTime, true);\n      }\n      expect(alphaNumeric.isDateTime, false);\n    });\n    test('var.isMD5', () {\n      final md5s = [\n        '176cfa006065a2a2bd8d3f1f83531b64',\n        '713fca6d088132e863497a79d1bd9572',\n        '7decc2fb2aca5cbd8a2cae5de1b50edb',\n        '85ed9bc4e4a8ae65add67886f5dfe02f',\n        'e4f0097f84a11f0298c83ecf6aa0fec3',\n        '70a2712b47127b431d7119b3a511b145',\n        'dd54069e3f97787e79592f6e3a307e93',\n        '5b64677b69da7370ee69523281ce935c',\n        '6150ce23f4b071e1cde49021b57c5a17',\n        '2781566b09a84a695297482cdcb1ffd0',\n        '54fe4ce16862aac01768b5831390d557',\n        '2747268afaa9898a320b8cc5580f143e',\n        'ce3c2d105fb2740c5bf59347b47603a8',\n        'cccef3bbc8cd2530c6de78af586ebcee',\n        '502115b10c767f50ab55270be095512e',\n        'b084ea385e849eaedf4fefaf6dd5f1a9',\n        '1f167339977225fe63a86388083fc64f',\n        '6abd5f472dba5e4688ad6dd14f975870',\n        '7e7f9ef53fb6e3ce2a4fb56665548eb8',\n        'de134fce82421dd2b3fab751fbfa190d',\n        'b0d8492572a52d1f2360535612c5dc82',\n      ];\n\n      for (final md5 in md5s) {\n        expect(md5.isMD5, true);\n      }\n\n      expect(alphaNumeric.isMD5, false);\n    });\n    test('var.isSHA1', () {\n      final sha1s = [\n        '1A310CF5DC8CE513586F74EE19CE90BD4BCC5AED',\n        'B458B077B5075C316CFD03619D627F529A0555BF',\n        '902C6A2850B4348BE445D637689CCAE5C5EF3552',\n        '8DC86C0DD0FD2960D62573AB142F90572A7421D5',\n        '7E18C8EA5F05BB2F385A9E34657B8D439A83BF82',\n        '3EC857A133E801C0B3198371C17C1A3A3D73DFE8',\n        'E32590E41805BEFD524205DAE0A56F429DCCC4E7',\n        '943A9164A126457203680B49F0309B5F15F0117E',\n        'C5E1442484AF49A92E1CC51F95AE4E8305F49DB6',\n        'B0C3B071F8ADBEE2222AA07ECFF51C3C040AA0A0',\n        '722ED6929057BF801F29590C423A40F4EF8C710E',\n        'F484FA4DC5EC1E063F0752112D9BF3B9763D6E41',\n        '2A87522644011223A27FD62C87FA926A1838F271',\n      ];\n\n      for (final sha1 in sha1s) {\n        expect(sha1.isSHA1, true);\n      }\n\n      expect(alphaNumeric.isSHA1, false);\n    });\n    test('var.isSHA256', () {\n      final sha256s = [\n        'FC694FFE78167EAE21EA4EBF072D8AB6ECF847162D1F65600BF019BA9805DB2D',\n        '3B64F1C349B548E72688A8EEFFA2F418A62BA2E22CF5BD954B4B1912C963D7FA',\n        'EF69D763148B8A222980BD164943F754937DF12771083889DDB69C18245C2904',\n        '9896D3134156E546FFC003C2C9CFED88D46C2BC214B39CF21192EAAF875A7C0A',\n        '2C70E9735D7DAB56427BAA09E6C63912BEAD9C7938F6B16C4954B78F46D1C3CF',\n        '423E095C8074BC1C440D874D999C18025445CD39211D98362E827E55863DD0B2',\n        '4FCDB44D5521663F713A5821DE9401D64D44050C2AF62EBA758B1D128AC4C279',\n        'BD91C9BBC044C94C283D0DF3AA1E8CDBF1BF35BF325E8196BA15FCA5238A3A40',\n        '7B9434447F3B1236221D40CB707D1909886CC9E8CA25EB18DCCFDC70F0A3AE9F',\n        'FBD3A0B1C5F9906EF3BFB5EDD846F77BA252070E036EC1F4F57BDD912F02987D',\n        'B8369EE116ADE797285DC973DDAA69433F255DC0AEEC7936378D4D08B2A7FDD2',\n        '6B6FE6891A5DFCCF2900A2A1F513196827AF5A95AB2DE1590B878BEFCCF12603',\n        'F2CB3614CD070450912EBEC399C63527D2A839C4E5BB2FE281BA1C5D5EA64257',\n        '822805E8FA05909AD7D3D6DBFBB1AE61D7A3C70209DB2A37C415BD5E11764866',\n        '40DAC792B52101BB1506AD880F0378EFACF46B019427A3D0E01DE2B09B06B6ED',\n        'E765A129579AF2F31C681973844490F8EA146DA8ADC07671F9FB71F0FE10E296',\n        '2B5B6DC7EF398D1420D23327295BCDCDDA8AAEDB7FE6C6129D1D31432B676CB7',\n        '67F20826370162C472791055E10E44624D40E35F29E60592B239692836474323',\n        'BD16B1ED024E353B5B2334201EC63C0B3E181F0DFD226A36825EF18F6A7D8D97',\n        'AC98F969AA56810BE672C770BE30EF79F7F77AE6EFB2A90D56FA2AD5506D8BD7',\n      ];\n\n      for (final sha256 in sha256s) {\n        expect(sha256.isSHA256, true);\n      }\n\n      expect(alphaNumeric.isSHA256, false);\n    });\n    test('var.isBinary', () {\n      final binaries = [\n        '00111100',\n        '00001111',\n        '10110110',\n        '01101110',\n        '01110101',\n        '00010100',\n        '11100010',\n        '11000001',\n        '11000110',\n        '11011101',\n        '10001101',\n        '10101110',\n        '11001110',\n        '10001011',\n        '11111101',\n        '11010110',\n        '11110011',\n        '01111010',\n        '11110011',\n        '01000111',\n      ];\n\n      for (final binary in binaries) {\n        expect(binary.isBinary, true);\n      }\n\n      expect(alphaNumeric.isBinary, false);\n    });\n    test('var.isIPv4', () {\n      final ipv4s = [\n        '155.162.247.250',\n        '121.99.222.180',\n        '142.197.183.237',\n        '176.60.213.134',\n        '12.190.123.58',\n        '105.75.28.173',\n        '121.120.116.138',\n        '20.195.194.189',\n        '234.171.207.97',\n        '153.122.129.170',\n        '224.226.28.80',\n        '236.196.62.84',\n        '122.71.160.46',\n        '151.24.85.63',\n        '37.109.242.32',\n        '235.47.62.53',\n        '151.1.242.190',\n        '227.197.221.85',\n        '12.118.136.231',\n        '51.73.246.208',\n      ];\n\n      for (final ipv4 in ipv4s) {\n        expect(ipv4.isIPv4, true);\n      }\n\n      expect(alphaNumeric.isIPv4, false);\n    });\n    test('var.isIPv6', () {\n      final ipv6s = [\n        'f856:62fc:9091:e649:e928:d771:f40c:1439',\n        'b8d5:3f85:5ae5:c63a:6b5f:f7e6:ea6b:871d',\n        '2f91:979a:90b0:55d1:40b7:3e6f:a210:598e',\n        'd35d:49fc:fbe4:9841:e4d3:f006:b04b:e242',\n        '2e0f:2912:e4e8:33d5:e833:0ac5:c73a:30b3',\n        '6af9:878a:a80f:f520:fc2b:a05c:b0dd:b93f',\n        '3329:1ce5:ab09:0120:945c:057b:ed4a:7869',\n        'b77d:5523:2f1b:ff07:93a5:378f:a9c7:e2f2',\n        'b669:64fa:1be7:af47:28fc:07f4:38bd:ae05',\n        'aa77:1f7e:8539:a01a:706d:6f74:7fc3:8407',\n        '16f9:9bcc:32d6:96de:5087:620b:c0c0:25cb',\n        'baad:273f:7e63:29cd:c742:c1ed:d0f9:062d',\n        'ae62:5b09:05fa:4611:5da9:a40a:f1ef:2a9d',\n        '4d2a:353a:9f6b:2070:9605:ab97:92c0:7956',\n        'bfcb:39f8:5119:458f:85fa:9e54:8c53:acd5',\n        '0c1a:c6f3:06af:9588:23b4:e7fb:c307:febd',\n        'ddaa:3c91:f554:dbe5:8447:9464:a9ae:2200',\n        '8787:c939:5002:a4f6:19b2:6521:4cde:8111',\n        'b515:5c17:6590:46dd:4ca8:1db3:a86c:e006',\n        '1083:d492:f42e:2c99:f050:f67f:07c5:23f9',\n      ];\n\n      for (final ipv6 in ipv6s) {\n        expect(ipv6.isIPv6, true);\n      }\n\n      expect(alphaNumeric.isIPv6, false);\n    });\n    test('var.isHexadecimal', () {\n      final hexadecimals = [\n        '#56E97B',\n        '#597E2A',\n        '#F45D5C',\n        '#A350DC',\n        '#2DA48E',\n        '#98CB3C',\n        '#F7DCD1',\n        '#B1F9BE',\n        '#D17855',\n        '#6F35CB',\n        '#DCBE21',\n        '#4C2E46',\n        '#145F3F',\n        '#F9776D',\n        '#62E9DC',\n        '#2F1030',\n        '#C4F888',\n        '#8E6D85',\n        '#8C64CE',\n        '#4DFF4E',\n      ];\n\n      for (final hexadecimal in hexadecimals) {\n        expect(hexadecimal.isHexadecimal, true);\n      }\n\n      expect(alphaNumeric.isHexadecimal, false);\n    });\n    test('var.isPalindrome', () {\n      final palindroms = [\n        'Anna',\n        'Civic',\n        'Kayak',\n        'Level',\n        'Madam',\n        'Mom',\n        'Noon',\n        'Racecar',\n        'Radar',\n        'Redder',\n        'Refer',\n        'Repaper',\n        'Don\\'t nod.',\n        'I did, did I?',\n        'My gym',\n        'Red rum, sir, is murder',\n        'Step on no pets',\n        'Top spot',\n        'Was it a cat I saw?',\n        'Eva, can I see bees in a cave?',\n        'No lemon, no melon',\n        'A base do teto desaba.',\n        'A cara rajada da jararaca.',\n        'Acuda cadela da Leda caduca.',\n        'A dama admirou o rim da amada.',\n        'A Daniela ama a lei? Nada!',\n\n        // TODO make isPalindrome regex support UTF8 characters\n        // 'Adias a data da saída.',\n        // 'A diva em Argel alegra-me a vida.',\n        // 'A droga do dote é todo da gorda.',\n        // 'A gorda ama a droga.',\n        // 'A grama é amarga.',\n        // 'Aí, Lima falou: “Olá, família!”.',\n        // 'anã',\n        // 'anilina',\n        // 'ata',\n        // 'arara',\n        // 'asa',\n        // 'ele',\n        // 'esse',\n        // 'mamam',\n        // 'matam',\n        // 'metem',\n        // 'mirim',\n        // 'oco',\n        // 'omissíssimo',\n      ];\n      for (final palindrom in palindroms) {\n        // print(\"testing $palindrom\");\n        expect(palindrom.isPalindrome, true);\n      }\n      expect(alphaNumeric.isPalindrome, false);\n    });\n    test('var.isPassport', () {\n      final passports = [\n        '12ss46',\n        'jdmg5dg',\n        '5f7fj5d7',\n        'w8a9s6f3z',\n      ];\n\n      for (final passport in passports) {\n        expect(passport.isPassport, true);\n      }\n\n      expect(specialCaracters.isPassport, false);\n    });\n\n    test('var.isCurrency', () {\n      final currencies = [\n        'R\\$50.58',\n        '\\$82.48',\n        '₩54.24',\n        '¥81.04',\n        '€4.06',\n        '₹37.40',\n        '₽18.12',\n        'fr95.15',\n        'R81.04',\n        '9.35USD',\n        '98.48AUD',\n        '29.20NZD',\n        '50.58CAD',\n        '82.48CHF',\n        '54.24GBP',\n        '81.04CNY',\n        '4.06EUR',\n        '37.40JPY',\n        '18.12IDR',\n        '95.15MXN',\n        '81.04NOK',\n        '9.35KRW',\n        '98.48TRY',\n        '29.20INR',\n      ];\n\n      for (final currency in currencies) {\n        // print('currency $currency');\n        expect(currency.isCurrency, true);\n      }\n\n      expect(specialCaracters.isCurrency, false);\n    });\n\n    test('var.isCpf', () {\n      final cpfs = [\n        '370.559.380-31',\n        '055.878.430-50',\n        '655.232.870-24',\n        '86497047000',\n        '12341309046',\n        '31496294033',\n      ];\n\n      for (final cpf in cpfs) {\n        expect(cpf.isCpf, true);\n      }\n\n      expect(specialCaracters.isCpf, false);\n    });\n    test('var.isCnpj', () {\n      final cnpjs = [\n        '11.066.893/0001-94',\n        '21.883.660/0001-38',\n        '59.705.218/0001-94',\n      ];\n\n      for (final cnpj in cnpjs) {\n        expect(cnpj.isCnpj, true);\n      }\n\n      expect(specialCaracters.isCnpj, false);\n    });\n\n    test('var.isCaseInsensitiveContains(string)', () {\n      const phrase = 'Back to Square One';\n\n      expect(phrase.isCaseInsensitiveContains('to'), true);\n      expect(phrase.isCaseInsensitiveContains('square'), true);\n      expect(phrase.isCaseInsensitiveContains('On'), true);\n      expect(phrase.isCaseInsensitiveContains('foo'), false);\n    });\n\n    test('var.isCaseInsensitiveContainsAny(string)', () {\n      const phrase = 'Back to Square One';\n\n      expect(phrase.isCaseInsensitiveContainsAny('to'), true);\n      expect(phrase.isCaseInsensitiveContainsAny('square'), true);\n      expect(phrase.isCaseInsensitiveContainsAny('On'), true);\n      expect(phrase.isCaseInsensitiveContainsAny('foo'), false);\n      expect('to'.isCaseInsensitiveContainsAny(phrase), true);\n      expect('square'.isCaseInsensitiveContainsAny('qu'), true);\n    });\n\n    test('var.capitalize', () {\n      expect('foo bar'.capitalize, 'Foo Bar');\n      expect('FoO bAr'.capitalize, 'Foo Bar');\n      expect('FOO BAR'.capitalize, 'Foo Bar');\n      // expect(null.capitalize, null);\n      expect(''.capitalize, '');\n      expect('foo  bar '.capitalize, 'Foo  Bar ');\n    });\n\n    test('var.capitalizeFirst', () {\n      expect('foo bar'.capitalizeFirst, 'Foo bar');\n      expect('FoO bAr'.capitalizeFirst, 'Foo bar');\n      expect('FOO BAR'.capitalizeFirst, 'Foo bar');\n      expect(''.capitalizeFirst, '');\n    });\n\n    test('var.removeAllWhitespace', () {\n      //late String nullString;\n      expect('foo bar'.removeAllWhitespace, 'foobar');\n      expect('foo'.removeAllWhitespace, 'foo');\n      expect(''.removeAllWhitespace, '');\n      // expect(nullString.removeAllWhitespace, null);\n    });\n\n    test('var.camelCase', () {\n      expect('foo bar'.camelCase, 'fooBar');\n      expect('the fox jumped in the water'.camelCase, 'theFoxJumpedInTheWater');\n      expect('foo_bar'.camelCase, 'fooBar');\n      expect(''.camelCase, null);\n    });\n\n    test('var.numericOnly()', () {\n      expect('date: 2020/09/13, time: 00:00'.numericOnly(), '202009130000');\n      expect(\n        'and 1, and 2, and 1 2 3'.numericOnly(),\n        '12123',\n      );\n      expect(''.numericOnly(), '');\n    });\n  });\n}\n"
  },
  {
    "path": "test/utils/extensions/widget_extensions_test.dart",
    "content": "import 'package:flutter/widgets.dart';\nimport 'package:flutter_test/flutter_test.dart';\nimport 'package:get/utils.dart';\n\nclass Foo extends StatelessWidget {\n  const Foo({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return const SizedBox.shrink();\n  }\n}\n\nvoid main() {\n  group('Group test for PaddingX Extension', () {\n    testWidgets('Test of paddingAll', (tester) async {\n      Widget containerTest = const Foo();\n\n      expect(find.byType(Padding), findsNothing);\n\n      await tester.pumpWidget(containerTest.paddingAll(16));\n\n      expect(find.byType(Padding), findsOneWidget);\n    });\n\n    testWidgets('Test of paddingOnly', (tester) async {\n      Widget containerTest = const Foo();\n\n      expect(find.byType(Padding), findsNothing);\n\n      await tester.pumpWidget(containerTest.paddingOnly(top: 16));\n\n      expect(find.byType(Padding), findsOneWidget);\n    });\n\n    testWidgets('Test of paddingSymmetric', (tester) async {\n      Widget containerTest = const Foo();\n\n      expect(find.byType(Padding), findsNothing);\n\n      await tester.pumpWidget(containerTest.paddingSymmetric(vertical: 16));\n\n      expect(find.byType(Padding), findsOneWidget);\n    });\n\n    testWidgets('Test of paddingZero', (tester) async {\n      Widget containerTest = const Foo();\n\n      expect(find.byType(Padding), findsNothing);\n\n      await tester.pumpWidget(containerTest.paddingZero);\n\n      expect(find.byType(Padding), findsOneWidget);\n    });\n  });\n\n  group('Group test for MarginX Extension', () {\n    testWidgets('Test of marginAll', (tester) async {\n      Widget containerTest = const Foo();\n\n      await tester.pumpWidget(containerTest.marginAll(16));\n\n      expect(find.byType(Container), findsOneWidget);\n    });\n\n    testWidgets('Test of marginOnly', (tester) async {\n      Widget containerTest = const Foo();\n\n      await tester.pumpWidget(containerTest.marginOnly(top: 16));\n\n      expect(find.byType(Container), findsOneWidget);\n    });\n\n    testWidgets('Test of marginSymmetric', (tester) async {\n      Widget containerTest = const Foo();\n\n      await tester.pumpWidget(containerTest.marginSymmetric(vertical: 16));\n\n      expect(find.byType(Container), findsOneWidget);\n    });\n\n    testWidgets('Test of marginZero', (tester) async {\n      Widget containerTest = const Foo();\n\n      await tester.pumpWidget(containerTest.marginZero);\n\n      expect(find.byType(Container), findsOneWidget);\n    });\n  });\n}\n"
  },
  {
    "path": "test/utils/get_utils_test.dart",
    "content": "import 'package:flutter_test/flutter_test.dart';\nimport 'package:get/get.dart';\n\nclass TestClass {\n  final name = \"John\";\n}\n\nclass EmptyClass {}\n\nvoid main() {\n  dynamic newId(dynamic e) => e;\n\n  test('null isNullOrBlank should be true for null', () {\n    expect(GetUtils.isNullOrBlank(null), true);\n  });\n\n  test('isNullOrBlank should be false for unsupported types', () {\n    expect(GetUtils.isNullOrBlank(5), false);\n    expect(GetUtils.isNullOrBlank(0), false);\n\n    expect(GetUtils.isNullOrBlank(5.0), equals(false));\n    expect(GetUtils.isNullOrBlank(0.0), equals(false));\n\n    TestClass? testClass;\n    expect(GetUtils.isNullOrBlank(testClass), equals(true));\n    expect(GetUtils.isNullOrBlank(TestClass()), equals(false));\n    expect(GetUtils.isNullOrBlank(EmptyClass()), equals(false));\n  });\n\n  test('isNullOrBlank should validate strings', () {\n    expect(GetUtils.isNullOrBlank(\"\"), true);\n    expect(GetUtils.isNullOrBlank(\"  \"), true);\n\n    expect(GetUtils.isNullOrBlank(\"foo\"), false);\n    expect(GetUtils.isNullOrBlank(\" foo \"), false);\n\n    expect(GetUtils.isNullOrBlank(\"null\"), false);\n  });\n\n  test('isNullOrBlank should validate iterables', () {\n    expect(GetUtils.isNullOrBlank([].map(newId)), true);\n    expect(GetUtils.isNullOrBlank([1].map(newId)), false);\n  });\n\n  test('isNullOrBlank should validate lists', () {\n    expect(GetUtils.isNullOrBlank(const []), true);\n    expect(GetUtils.isNullOrBlank(['oi', 'foo']), false);\n    expect(GetUtils.isNullOrBlank([{}, {}]), false);\n    expect(GetUtils.isNullOrBlank(['foo'][0]), false);\n  });\n\n  test('isNullOrBlank should validate sets', () {\n    expect(GetUtils.isNullOrBlank(<dynamic>{}), true);\n    expect(GetUtils.isNullOrBlank({1}), false);\n    expect(GetUtils.isNullOrBlank({'fluorine', 'chlorine', 'bromine'}), false);\n  });\n\n  test('isNullOrBlank should validate maps', () {\n    expect(GetUtils.isNullOrBlank({}), true);\n    expect(GetUtils.isNullOrBlank({1: 1}), false);\n    expect(GetUtils.isNullOrBlank({\"other\": \"thing\"}), false);\n\n    final map = {\"foo\": 'bar', \"one\": \"um\"};\n    expect(GetUtils.isNullOrBlank(map[\"foo\"]), false);\n    expect(GetUtils.isNullOrBlank(map[\"other\"]), true);\n  });\n  group('GetUtils.isLength* functions', () {\n    test('isLengthEqualTo should validate iterable lengths', () {\n      // iterables should cover list and set\n      expect(GetUtils.isLengthEqualTo([].map(newId), 0), true);\n      expect(GetUtils.isLengthEqualTo([1, 2].map(newId), 2), true);\n\n      expect(GetUtils.isLengthEqualTo({}, 0), true);\n      expect(GetUtils.isLengthEqualTo({1: 1, 2: 1}, 2), true);\n      expect(GetUtils.isLengthEqualTo({}, 2), false);\n\n      expect(GetUtils.isLengthEqualTo(\"\", 0), true);\n      expect(GetUtils.isLengthEqualTo(\"a\", 0), false);\n      expect(GetUtils.isLengthEqualTo(\"a\", 1), true);\n    });\n\n    test('isLengthGreaterOrEqual should validate lengths', () {\n      // iterables should cover list and set\n      expect(GetUtils.isLengthGreaterOrEqual([].map(newId), 0), true);\n      expect(GetUtils.isLengthGreaterOrEqual([1, 2].map(newId), 2), true);\n      expect(GetUtils.isLengthGreaterOrEqual([1, 2].map(newId), 1), true);\n\n      expect(GetUtils.isLengthGreaterOrEqual({}, 0), true);\n      expect(GetUtils.isLengthGreaterOrEqual({1: 1, 2: 1}, 1), true);\n      expect(GetUtils.isLengthGreaterOrEqual({1: 1, 2: 1}, 2), true);\n      expect(GetUtils.isLengthGreaterOrEqual({}, 2), false);\n\n      expect(GetUtils.isLengthGreaterOrEqual(\"\", 0), true);\n      expect(GetUtils.isLengthGreaterOrEqual(\"a\", 0), true);\n      expect(GetUtils.isLengthGreaterOrEqual(\"\", 1), false);\n    });\n\n    test('isLengthLessOrEqual should validate lengths', () {\n      // iterables should cover list and set\n      expect(GetUtils.isLengthLessOrEqual([].map(newId), 0), true);\n      expect(GetUtils.isLengthLessOrEqual([1, 2].map(newId), 2), true);\n      expect(GetUtils.isLengthLessOrEqual([1, 2].map(newId), 1), false);\n\n      expect(GetUtils.isLengthLessOrEqual({}, 0), true);\n      expect(GetUtils.isLengthLessOrEqual({1: 1, 2: 1}, 1), false);\n      expect(GetUtils.isLengthLessOrEqual({1: 1, 2: 1}, 3), true);\n      expect(GetUtils.isLengthLessOrEqual({}, 2), true);\n\n      expect(GetUtils.isLengthLessOrEqual(\"\", 0), true);\n      expect(GetUtils.isLengthLessOrEqual(\"a\", 2), true);\n      expect(GetUtils.isLengthLessOrEqual(\"a\", 0), false);\n    });\n  });\n}\n"
  },
  {
    "path": "test/utils/platform_test.dart",
    "content": "@TestOn('vm')\nlibrary;\n\nimport 'dart:io';\n\nimport 'package:flutter_test/flutter_test.dart';\nimport 'package:get/get.dart';\n\nvoid main() {\n  test('Platform test', () {\n    expect(GetPlatform.isAndroid, Platform.isAndroid);\n    expect(GetPlatform.isIOS, Platform.isIOS);\n    expect(GetPlatform.isFuchsia, Platform.isFuchsia);\n    expect(GetPlatform.isLinux, Platform.isLinux);\n    expect(GetPlatform.isMacOS, Platform.isMacOS);\n    expect(GetPlatform.isWindows, Platform.isWindows);\n    expect(GetPlatform.isWeb, false);\n  });\n}\n"
  },
  {
    "path": "test/utils/platform_web_test.dart",
    "content": "@TestOn('browser')\nlibrary;\n\nimport 'dart:io';\n\nimport 'package:flutter_test/flutter_test.dart';\nimport 'package:get/get.dart';\n\nvoid main() {\n  test('Platform test', () {\n    expect(GetPlatform.isAndroid, Platform.isAndroid);\n    expect(GetPlatform.isIOS, Platform.isIOS);\n    expect(GetPlatform.isFuchsia, Platform.isFuchsia);\n    expect(GetPlatform.isLinux, Platform.isLinux);\n    expect(GetPlatform.isMacOS, Platform.isMacOS);\n    expect(GetPlatform.isWindows, Platform.isWindows);\n    expect(GetPlatform.isWeb, true);\n  });\n}\n"
  }
]