Ahmed Fwela

Merge branch 'master' of git://github.com/jonataslaw/getx

Showing 44 changed files with 2103 additions and 1865 deletions

Too many changes to show.

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

  1 +## [4.5.1] - Big Update
  2 +Fix Snackbar when it have action and icon the same time
  3 +
  4 +## [4.5.0] - Big Update
  5 +To have a context-free, page-agnostic snackbar, we used OverlayRoute to display a partial route.
  6 +However this had several problems:
  7 +
  8 +1: There was no possibility to close the page without closing the snackbar
  9 +2: Get.back() could cause problems with tests of Get.isSnackbarOpen not being properly invoked
  10 +3: Sometimes when using iOS popGesture with an open snackbar, some visual inconsistency might appear.
  11 +4: 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.
  12 +
  13 +We 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.
  14 +
  15 +Using 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.
  16 +
  17 +For backwards compatibility, Get.back() still works for closing routes and overlays, however two new commands have been added: Get.closeCurrentSnackbar() and Get.closeAllSnackbars().
  18 +Maybe 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.
  19 +
  20 +Snackbars 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.
  21 +
  22 +Fixed 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.
  23 +
  24 +Errors 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.
  25 +
  26 +Update locale also now returns a Future, allowing you to perform an action only when the language has already changed (@MHosssam)
  27 +
  28 +We are very happy to announce that GetX is now documented in Japanese as well, thanks to (@toshi-kuji)
  29 +
  30 +GetX 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)
  31 +
  32 +@maxzod has also started translating the docs into Arabic, we hope the documentation will be complete soon.
  33 +
  34 +Some remaining package logs have been moved to Get.log (@gairick-saha)
  35 +
  36 +RxList.removeWhere received performance optimizations (@zuvola)
  37 +
  38 +Optimizations in GetConnect and added the ability to modify all request items in GetConnect (@rodrigorahman)
  39 +
  40 +The current route could be inconsistent if a dialog were opened after a transition, fixed by @xiangzy1
  41 +
  42 +Fixed try/catch case missed in socket_notifier (@ShookLyngs)
  43 +
  44 +Also we had fixes in the docs: @DeathGun3344 @pinguluk
  45 +
  46 +GetX 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.
  47 +
  48 +This update is a preparation update for version 5, which will be released later this year.
  49 +
  50 +Breaking and Depreciation:
  51 +GetBar is now deprecated, use GetSnackbar instead.
  52 +dismissDirection now gets a DismissDirection, making the Snackbar more customizable.
  53 +
  54 +
  55 +
  56 +
  57 +
1 ## [4.3.8] 58 ## [4.3.8]
2 - Fix nav2 toNamed remove the route 59 - Fix nav2 toNamed remove the route
3 60
1 ![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png) 1 ![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png)
2 2
3 [![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get) 3 [![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)
  4 +[![popularity](https://badges.bar/get/popularity)](https://pub.dev/packages/sentry/score)
4 [![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score) 5 [![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)
  6 +[![pub points](https://badges.bar/get/pub%20points)](https://pub.dev/packages/get/score)
5 ![building](https://github.com/jonataslaw/get/workflows/build/badge.svg) 7 ![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)
6 [![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart) 8 [![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart)
7 [![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N) 9 [![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N)
@@ -3,6 +3,9 @@ @@ -3,6 +3,9 @@
3 *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).* 3 *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).*
4 4
5 [![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get) 5 [![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)
  6 +[![popularity](https://badges.bar/get/popularity)](https://pub.dev/packages/sentry/score)
  7 +[![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)
  8 +[![pub points](https://badges.bar/get/pub%20points)](https://pub.dev/packages/get/score)
6 ![building](https://github.com/jonataslaw/get/workflows/build/badge.svg) 9 ![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)
7 [![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart) 10 [![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart)
8 [![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N) 11 [![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N)
@@ -3,7 +3,9 @@ @@ -3,7 +3,9 @@
3 **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).** 3 **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).**
4 4
5 [![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get) 5 [![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)
  6 +[![popularity](https://badges.bar/get/popularity)](https://pub.dev/packages/sentry/score)
6 [![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score) 7 [![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)
  8 +[![pub points](https://badges.bar/get/pub%20points)](https://pub.dev/packages/get/score)
7 ![building](https://github.com/jonataslaw/get/workflows/build/badge.svg) 9 ![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)
8 [![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart) 10 [![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart)
9 [![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N) 11 [![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N)
@@ -3,7 +3,9 @@ @@ -3,7 +3,9 @@
3 **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).** 3 **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).**
4 4
5 [![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get) 5 [![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)
  6 +[![popularity](https://badges.bar/get/popularity)](https://pub.dev/packages/sentry/score)
6 [![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score) 7 [![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)
  8 +[![pub points](https://badges.bar/get/pub%20points)](https://pub.dev/packages/get/score)
7 ![building](https://github.com/jonataslaw/get/workflows/build/badge.svg) 9 ![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)
8 [![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart) 10 [![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart)
9 [![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N) 11 [![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N)
@@ -3,7 +3,9 @@ @@ -3,7 +3,9 @@
3 **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)** 3 **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)**
4 4
5 [![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get) 5 [![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)
  6 +[![popularity](https://badges.bar/get/popularity)](https://pub.dev/packages/sentry/score)
6 [![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score) 7 [![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)
  8 +[![pub points](https://badges.bar/get/pub%20points)](https://pub.dev/packages/get/score)
7 ![building](https://github.com/jonataslaw/get/workflows/build/badge.svg) 9 ![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)
8 [![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart) 10 [![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart)
9 [![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N) 11 [![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N)
1 ![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png) 1 ![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png)
2 2
3 [![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get) 3 [![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)
  4 +[![popularity](https://badges.bar/get/popularity)](https://pub.dev/packages/sentry/score)
4 [![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score) 5 [![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)
  6 +[![pub points](https://badges.bar/get/pub%20points)](https://pub.dev/packages/get/score)
5 ![building](https://github.com/jonataslaw/get/workflows/build/badge.svg) 7 ![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)
6 [![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart) 8 [![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart)
7 [![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N) 9 [![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N)
1 ![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png) 1 ![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png)
2 2
3 [![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get) 3 [![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)
  4 +[![popularity](https://badges.bar/get/popularity)](https://pub.dev/packages/sentry/score)
4 [![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score) 5 [![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)
  6 +[![pub points](https://badges.bar/get/pub%20points)](https://pub.dev/packages/get/score)
5 ![building](https://github.com/jonataslaw/get/workflows/build/badge.svg) 7 ![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)
6 [![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart) 8 [![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart)
7 [![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N) 9 [![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N)
1 ![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png) 1 ![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png)
2 2
3 [![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get) 3 [![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)
  4 +[![popularity](https://badges.bar/get/popularity)](https://pub.dev/packages/sentry/score)
4 [![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score) 5 [![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)
  6 +[![pub points](https://badges.bar/get/pub%20points)](https://pub.dev/packages/get/score)
5 ![building](https://github.com/jonataslaw/get/workflows/build/badge.svg) 7 ![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)
6 [![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart) 8 [![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart)
7 [![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N) 9 [![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N)
@@ -3,6 +3,9 @@ @@ -3,6 +3,9 @@
3 *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)* 3 *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)*
4 4
5 [![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get) 5 [![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)
  6 +[![popularity](https://badges.bar/get/popularity)](https://pub.dev/packages/sentry/score)
  7 +[![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)
  8 +[![pub points](https://badges.bar/get/pub%20points)](https://pub.dev/packages/get/score)
6 ![building](https://github.com/jonataslaw/get/workflows/build/badge.svg) 9 ![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)
7 [![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart) 10 [![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart)
8 [![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N) 11 [![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N)
@@ -3,7 +3,9 @@ @@ -3,7 +3,9 @@
3 **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)** 3 **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)**
4 4
5 [![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get) 5 [![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)
  6 +[![popularity](https://badges.bar/get/popularity)](https://pub.dev/packages/sentry/score)
6 [![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score) 7 [![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)
  8 +[![pub points](https://badges.bar/get/pub%20points)](https://pub.dev/packages/get/score)
7 ![building](https://github.com/jonataslaw/get/workflows/build/badge.svg) 9 ![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)
8 [![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart) 10 [![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart)
9 [![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N) 11 [![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N)
@@ -3,6 +3,9 @@ @@ -3,6 +3,9 @@
3 _Языки: Русский (этот файл), [вьетнамский](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)._ 3 _Языки: Русский (этот файл), [вьетнамский](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)._
4 4
5 [![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get) 5 [![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)
  6 +[![popularity](https://badges.bar/get/popularity)](https://pub.dev/packages/sentry/score)
  7 +[![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)
  8 +[![pub points](https://badges.bar/get/pub%20points)](https://pub.dev/packages/get/score)
6 ![building](https://github.com/jonataslaw/get/workflows/build/badge.svg) 9 ![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)
7 [![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart) 10 [![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart)
8 [![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N) 11 [![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N)
@@ -3,7 +3,9 @@ @@ -3,7 +3,9 @@
3 **🌎 اردو ( 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)** 3 **🌎 اردو ( 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)**
4 4
5 [![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get) 5 [![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)
  6 +[![popularity](https://badges.bar/get/popularity)](https://pub.dev/packages/sentry/score)
6 [![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score) 7 [![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)
  8 +[![pub points](https://badges.bar/get/pub%20points)](https://pub.dev/packages/get/score)
7 ![building](https://github.com/jonataslaw/get/workflows/build/badge.svg) 9 ![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)
8 [![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart) 10 [![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart)
9 [![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N) 11 [![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N)
@@ -3,6 +3,9 @@ @@ -3,6 +3,9 @@
3 _语言: 中文, [英文](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)._ 3 _语言: 中文, [英文](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)._
4 4
5 [![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get) 5 [![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)
  6 +[![popularity](https://badges.bar/get/popularity)](https://pub.dev/packages/sentry/score)
  7 +[![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)
  8 +[![pub points](https://badges.bar/get/pub%20points)](https://pub.dev/packages/get/score)
6 ![building](https://github.com/jonataslaw/get/workflows/build/badge.svg) 9 ![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)
7 [![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart) 10 [![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart)
8 [![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N) 11 [![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N)
  1 +// ignore_for_file: file_names
  2 +
1 const Map<String, String> en_US = { 3 const Map<String, String> en_US = {
2 'covid': 'Corona Virus', 4 'covid': 'Corona Virus',
3 'total_confirmed': 'Total Confirmed', 5 'total_confirmed': 'Total Confirmed',
  1 +// ignore_for_file: file_names
  2 +
1 const Map<String, String> pt_BR = { 3 const Map<String, String> pt_BR = {
2 'covid': 'Corona Vírus', 4 'covid': 'Corona Vírus',
3 'total_confirmed': 'Total confirmado', 5 'total_confirmed': 'Total confirmado',
@@ -7,4 +9,4 @@ const Map<String, String> pt_BR = { @@ -7,4 +9,4 @@ const Map<String, String> pt_BR = {
7 'total_infecteds': 'Total de infectados', 9 'total_infecteds': 'Total de infectados',
8 'details': 'Detalhes', 10 'details': 'Detalhes',
9 'total_recovered': 'Total de recuperados' 11 'total_recovered': 'Total de recuperados'
10 -};  
  12 +};
1 import 'package:flutter/material.dart'; 1 import 'package:flutter/material.dart';
2 import 'package:get/get.dart'; 2 import 'package:get/get.dart';
3 3
4 -import 'en_US.dart';  
5 -import 'pt_BR.dart'; 4 +import 'en_us.dart';
  5 +import 'pt_br.dart';
6 6
7 class TranslationService extends Translations { 7 class TranslationService extends Translations {
8 static Locale? get locale => Get.deviceLocale; 8 static Locale? get locale => Get.deviceLocale;
@@ -21,6 +21,12 @@ class HomeView extends GetView<HomeController> { @@ -21,6 +21,12 @@ class HomeView extends GetView<HomeController> {
21 child: Scaffold( 21 child: Scaffold(
22 backgroundColor: Colors.transparent, 22 backgroundColor: Colors.transparent,
23 appBar: AppBar( 23 appBar: AppBar(
  24 + leading: IconButton(
  25 + icon: Icon(Icons.add),
  26 + onPressed: () {
  27 + Get.snackbar('title', 'message');
  28 + },
  29 + ),
24 title: Text('covid'.tr), 30 title: Text('covid'.tr),
25 backgroundColor: Colors.white10, 31 backgroundColor: Colors.white10,
26 elevation: 0, 32 elevation: 0,
@@ -3,7 +3,6 @@ import 'package:get/get.dart'; @@ -3,7 +3,6 @@ import 'package:get/get.dart';
3 3
4 import '../controllers/dashboard_controller.dart'; 4 import '../controllers/dashboard_controller.dart';
5 5
6 -  
7 class DashboardView extends GetView<DashboardController> { 6 class DashboardView extends GetView<DashboardController> {
8 @override 7 @override
9 Widget build(BuildContext context) { 8 Widget build(BuildContext context) {
  1 +// ignore_for_file: non_constant_identifier_names
  2 +
1 part of 'app_pages.dart'; 3 part of 'app_pages.dart';
2 // DO NOT EDIT. This is code generated via package:get_cli/get_cli.dart 4 // DO NOT EDIT. This is code generated via package:get_cli/get_cli.dart
3 5
4 abstract class Routes { 6 abstract class Routes {
5 - Routes._();  
6 -  
7 static const HOME = _Paths.HOME; 7 static const HOME = _Paths.HOME;
8 - static const PROFILE = _Paths.HOME + _Paths.PROFILE;  
9 8
  9 + static const PROFILE = _Paths.HOME + _Paths.PROFILE;
10 static const SETTINGS = _Paths.SETTINGS; 10 static const SETTINGS = _Paths.SETTINGS;
11 11
12 static const PRODUCTS = _Paths.HOME + _Paths.PRODUCTS; 12 static const PRODUCTS = _Paths.HOME + _Paths.PRODUCTS;
13 - static String PRODUCT_DETAILS(String productId) => '$PRODUCTS/$productId'; 13 +
14 static const LOGIN = _Paths.LOGIN; 14 static const LOGIN = _Paths.LOGIN;
  15 + static const DASHBOARD = _Paths.HOME + _Paths.DASHBOARD;
  16 + Routes._();
15 static String LOGIN_THEN(String afterSuccessfulLogin) => 17 static String LOGIN_THEN(String afterSuccessfulLogin) =>
16 '$LOGIN?then=${Uri.encodeQueryComponent(afterSuccessfulLogin)}'; 18 '$LOGIN?then=${Uri.encodeQueryComponent(afterSuccessfulLogin)}';
17 - static const DASHBOARD = _Paths.HOME + _Paths.DASHBOARD; 19 + static String PRODUCT_DETAILS(String productId) => '$PRODUCTS/$productId';
18 } 20 }
19 21
20 abstract class _Paths { 22 abstract class _Paths {
@@ -138,7 +138,11 @@ class HeaderValue { @@ -138,7 +138,11 @@ class HeaderValue {
138 stringBuffer.write(_value); 138 stringBuffer.write(_value);
139 if (parameters != null && parameters!.isNotEmpty) { 139 if (parameters != null && parameters!.isNotEmpty) {
140 _parameters!.forEach((name, value) { 140 _parameters!.forEach((name, value) {
141 - stringBuffer..write('; ')..write(name)..write('=')..write(value); 141 + stringBuffer
  142 + ..write('; ')
  143 + ..write(name)
  144 + ..write('=')
  145 + ..write(value);
142 }); 146 });
143 } 147 }
144 return stringBuffer.toString(); 148 return stringBuffer.toString();
1 import 'dart:convert'; 1 import 'dart:convert';
2 2
  3 +/// Signature for [SocketNotifier.addCloses].
  4 +typedef CloseSocket = void Function(Close);
  5 +
  6 +/// Signature for [SocketNotifier.addMessages].
  7 +typedef MessageSocket = void Function(dynamic val);
  8 +
  9 +/// Signature for [SocketNotifier.open].
  10 +typedef OpenSocket = void Function();
  11 +
  12 +/// Wrapper class to message and reason from SocketNotifier
3 class Close { 13 class Close {
4 final String? message; 14 final String? message;
5 final int? reason; 15 final int? reason;
@@ -12,12 +22,8 @@ class Close { @@ -12,12 +22,8 @@ class Close {
12 } 22 }
13 } 23 }
14 24
15 -typedef OpenSocket = void Function();  
16 -  
17 -typedef CloseSocket = void Function(Close);  
18 -  
19 -typedef MessageSocket = void Function(dynamic val);  
20 - 25 +/// This class manages the transmission of messages over websockets using
  26 +/// GetConnect
21 class SocketNotifier { 27 class SocketNotifier {
22 List<void Function(dynamic)>? _onMessages = <MessageSocket>[]; 28 List<void Function(dynamic)>? _onMessages = <MessageSocket>[];
23 Map<String, void Function(dynamic)>? _onEvents = <String, MessageSocket>{}; 29 Map<String, void Function(dynamic)>? _onEvents = <String, MessageSocket>{};
@@ -26,22 +32,42 @@ class SocketNotifier { @@ -26,22 +32,42 @@ class SocketNotifier {
26 32
27 late OpenSocket open; 33 late OpenSocket open;
28 34
29 - void addMessages(MessageSocket socket) {  
30 - _onMessages!.add((socket)); 35 + /// subscribe to close events
  36 + void addCloses(CloseSocket socket) {
  37 + _onCloses!.add(socket);
  38 + }
  39 +
  40 + /// subscribe to error events
  41 + void addErrors(CloseSocket socket) {
  42 + _onErrors!.add((socket));
31 } 43 }
32 44
  45 + /// subscribe to named events
33 void addEvents(String event, MessageSocket socket) { 46 void addEvents(String event, MessageSocket socket) {
34 _onEvents![event] = socket; 47 _onEvents![event] = socket;
35 } 48 }
36 49
37 - void addCloses(CloseSocket socket) {  
38 - _onCloses!.add(socket); 50 + /// subscribe to message events
  51 + void addMessages(MessageSocket socket) {
  52 + _onMessages!.add((socket));
39 } 53 }
40 54
41 - void addErrors(CloseSocket socket) {  
42 - _onErrors!.add((socket)); 55 + /// Dispose messages, events, closes and errors subscriptions
  56 + void dispose() {
  57 + _onMessages = null;
  58 + _onEvents = null;
  59 + _onCloses = null;
  60 + _onErrors = null;
43 } 61 }
44 62
  63 + /// Notify all subscriptions on [addCloses]
  64 + void notifyClose(Close err) {
  65 + for (var item in _onCloses!) {
  66 + item(err);
  67 + }
  68 + }
  69 +
  70 + /// Notify all subscriptions on [addMessages]
45 void notifyData(dynamic data) { 71 void notifyData(dynamic data) {
46 for (var item in _onMessages!) { 72 for (var item in _onMessages!) {
47 item(data); 73 item(data);
@@ -51,12 +77,7 @@ class SocketNotifier { @@ -51,12 +77,7 @@ class SocketNotifier {
51 } 77 }
52 } 78 }
53 79
54 - void notifyClose(Close err) {  
55 - for (var item in _onCloses!) {  
56 - item(err);  
57 - }  
58 - }  
59 - 80 + /// Notify all subscriptions on [addErrors]
60 void notifyError(Close err) { 81 void notifyError(Close err) {
61 // rooms.removeWhere((key, value) => value.contains(_ws)); 82 // rooms.removeWhere((key, value) => value.contains(_ws));
62 for (var item in _onErrors!) { 83 for (var item in _onErrors!) {
@@ -72,15 +93,9 @@ class SocketNotifier { @@ -72,15 +93,9 @@ class SocketNotifier {
72 if (_onEvents!.containsKey(event)) { 93 if (_onEvents!.containsKey(event)) {
73 _onEvents![event]!(data); 94 _onEvents![event]!(data);
74 } 95 }
  96 + // ignore: avoid_catches_without_on_clauses
75 } catch (_) { 97 } catch (_) {
76 return; 98 return;
77 } 99 }
78 } 100 }
79 -  
80 - void dispose() {  
81 - _onMessages = null;  
82 - _onEvents = null;  
83 - _onCloses = null;  
84 - _onErrors = null;  
85 - }  
86 } 101 }
@@ -4,15 +4,8 @@ import 'dart:convert'; @@ -4,15 +4,8 @@ import 'dart:convert';
4 import 'dart:html'; 4 import 'dart:html';
5 5
6 import '../../../get_core/get_core.dart'; 6 import '../../../get_core/get_core.dart';
7 -  
8 import 'socket_notifier.dart'; 7 import 'socket_notifier.dart';
9 8
10 -enum ConnectionStatus {  
11 - connecting,  
12 - connected,  
13 - closed,  
14 -}  
15 -  
16 class BaseWebSocket { 9 class BaseWebSocket {
17 String url; 10 String url;
18 WebSocket? socket; 11 WebSocket? socket;
@@ -21,6 +14,8 @@ class BaseWebSocket { @@ -21,6 +14,8 @@ class BaseWebSocket {
21 bool isDisposed = false; 14 bool isDisposed = false;
22 bool allowSelfSigned; 15 bool allowSelfSigned;
23 16
  17 + ConnectionStatus? connectionStatus;
  18 + Timer? _t;
24 BaseWebSocket( 19 BaseWebSocket(
25 this.url, { 20 this.url, {
26 this.ping = const Duration(seconds: 5), 21 this.ping = const Duration(seconds: 5),
@@ -30,9 +25,12 @@ class BaseWebSocket { @@ -30,9 +25,12 @@ class BaseWebSocket {
30 ? url.replaceAll('https:', 'wss:') 25 ? url.replaceAll('https:', 'wss:')
31 : url.replaceAll('http:', 'ws:'); 26 : url.replaceAll('http:', 'ws:');
32 } 27 }
33 - ConnectionStatus? connectionStatus;  
34 - Timer? _t;  
35 28
  29 + void close([int? status, String? reason]) {
  30 + socket?.close(status, reason);
  31 + }
  32 +
  33 + // ignore: use_setters_to_change_properties
36 void connect() { 34 void connect() {
37 try { 35 try {
38 connectionStatus = ConnectionStatus.connecting; 36 connectionStatus = ConnectionStatus.connecting;
@@ -68,9 +66,18 @@ class BaseWebSocket { @@ -68,9 +66,18 @@ class BaseWebSocket {
68 } 66 }
69 } 67 }
70 68
71 - // ignore: use_setters_to_change_properties  
72 - void onOpen(OpenSocket fn) {  
73 - socketNotifier!.open = fn; 69 + void dispose() {
  70 + socketNotifier!.dispose();
  71 + socketNotifier = null;
  72 + isDisposed = true;
  73 + }
  74 +
  75 + void emit(String event, dynamic data) {
  76 + send(jsonEncode({'type': event, 'data': data}));
  77 + }
  78 +
  79 + void on(String event, MessageSocket message) {
  80 + socketNotifier!.addEvents(event, message);
74 } 81 }
75 82
76 void onClose(CloseSocket fn) { 83 void onClose(CloseSocket fn) {
@@ -85,12 +92,9 @@ class BaseWebSocket { @@ -85,12 +92,9 @@ class BaseWebSocket {
85 socketNotifier!.addMessages(fn); 92 socketNotifier!.addMessages(fn);
86 } 93 }
87 94
88 - void on(String event, MessageSocket message) {  
89 - socketNotifier!.addEvents(event, message);  
90 - }  
91 -  
92 - void close([int? status, String? reason]) {  
93 - socket?.close(status, reason); 95 + // ignore: use_setters_to_change_properties
  96 + void onOpen(OpenSocket fn) {
  97 + socketNotifier!.open = fn;
94 } 98 }
95 99
96 void send(dynamic data) { 100 void send(dynamic data) {
@@ -103,14 +107,10 @@ class BaseWebSocket { @@ -103,14 +107,10 @@ class BaseWebSocket {
103 Get.log('WebSocket not connected, message $data not sent'); 107 Get.log('WebSocket not connected, message $data not sent');
104 } 108 }
105 } 109 }
  110 +}
106 111
107 - void emit(String event, dynamic data) {  
108 - send(jsonEncode({'type': event, 'data': data}));  
109 - }  
110 -  
111 - void dispose() {  
112 - socketNotifier!.dispose();  
113 - socketNotifier = null;  
114 - isDisposed = true;  
115 - } 112 +enum ConnectionStatus {
  113 + connecting,
  114 + connected,
  115 + closed,
116 } 116 }
@@ -4,30 +4,28 @@ import 'dart:io'; @@ -4,30 +4,28 @@ import 'dart:io';
4 import 'dart:math'; 4 import 'dart:math';
5 5
6 import '../../../get_core/get_core.dart'; 6 import '../../../get_core/get_core.dart';
7 -  
8 import 'socket_notifier.dart'; 7 import 'socket_notifier.dart';
9 8
10 -enum ConnectionStatus {  
11 - connecting,  
12 - connected,  
13 - closed,  
14 -}  
15 -  
16 class BaseWebSocket { 9 class BaseWebSocket {
17 String url; 10 String url;
18 WebSocket? socket; 11 WebSocket? socket;
19 SocketNotifier? socketNotifier = SocketNotifier(); 12 SocketNotifier? socketNotifier = SocketNotifier();
20 bool isDisposed = false; 13 bool isDisposed = false;
  14 + Duration ping;
  15 + bool allowSelfSigned;
  16 + ConnectionStatus? connectionStatus;
  17 +
21 BaseWebSocket( 18 BaseWebSocket(
22 this.url, { 19 this.url, {
23 this.ping = const Duration(seconds: 5), 20 this.ping = const Duration(seconds: 5),
24 this.allowSelfSigned = true, 21 this.allowSelfSigned = true,
25 }); 22 });
26 - Duration ping;  
27 - bool allowSelfSigned;  
28 23
29 - ConnectionStatus? connectionStatus; 24 + void close([int? status, String? reason]) {
  25 + socket?.close(status, reason);
  26 + }
30 27
  28 + // ignore: use_setters_to_change_properties
31 Future connect() async { 29 Future connect() async {
32 if (isDisposed) { 30 if (isDisposed) {
33 socketNotifier = SocketNotifier(); 31 socketNotifier = SocketNotifier();
@@ -60,9 +58,18 @@ class BaseWebSocket { @@ -60,9 +58,18 @@ class BaseWebSocket {
60 } 58 }
61 } 59 }
62 60
63 - // ignore: use_setters_to_change_properties  
64 - void onOpen(OpenSocket fn) {  
65 - socketNotifier!.open = fn; 61 + void dispose() {
  62 + socketNotifier!.dispose();
  63 + socketNotifier = null;
  64 + isDisposed = true;
  65 + }
  66 +
  67 + void emit(String event, dynamic data) {
  68 + send(jsonEncode({'type': event, 'data': data}));
  69 + }
  70 +
  71 + void on(String event, MessageSocket message) {
  72 + socketNotifier!.addEvents(event, message);
66 } 73 }
67 74
68 void onClose(CloseSocket fn) { 75 void onClose(CloseSocket fn) {
@@ -77,12 +84,9 @@ class BaseWebSocket { @@ -77,12 +84,9 @@ class BaseWebSocket {
77 socketNotifier!.addMessages(fn); 84 socketNotifier!.addMessages(fn);
78 } 85 }
79 86
80 - void on(String event, MessageSocket message) {  
81 - socketNotifier!.addEvents(event, message);  
82 - }  
83 -  
84 - void close([int? status, String? reason]) {  
85 - socket?.close(status, reason); 87 + // ignore: use_setters_to_change_properties
  88 + void onOpen(OpenSocket fn) {
  89 + socketNotifier!.open = fn;
86 } 90 }
87 91
88 void send(dynamic data) async { 92 void send(dynamic data) async {
@@ -95,16 +99,6 @@ class BaseWebSocket { @@ -95,16 +99,6 @@ class BaseWebSocket {
95 } 99 }
96 } 100 }
97 101
98 - void dispose() {  
99 - socketNotifier!.dispose();  
100 - socketNotifier = null;  
101 - isDisposed = true;  
102 - }  
103 -  
104 - void emit(String event, dynamic data) {  
105 - send(jsonEncode({'type': event, 'data': data}));  
106 - }  
107 -  
108 Future<WebSocket> _connectForSelfSignedCert(String url) async { 102 Future<WebSocket> _connectForSelfSignedCert(String url) async {
109 try { 103 try {
110 var r = Random(); 104 var r = Random();
@@ -136,3 +130,9 @@ class BaseWebSocket { @@ -136,3 +130,9 @@ class BaseWebSocket {
136 } 130 }
137 } 131 }
138 } 132 }
  133 +
  134 +enum ConnectionStatus {
  135 + connecting,
  136 + connected,
  137 + closed,
  138 +}
@@ -17,5 +17,5 @@ export 'src/routes/get_route.dart'; @@ -17,5 +17,5 @@ export 'src/routes/get_route.dart';
17 export 'src/routes/observers/route_observer.dart'; 17 export 'src/routes/observers/route_observer.dart';
18 export 'src/routes/route_middleware.dart'; 18 export 'src/routes/route_middleware.dart';
19 export 'src/routes/transitions_type.dart'; 19 export 'src/routes/transitions_type.dart';
20 -export 'src/snackbar/snack.dart';  
21 -export 'src/snackbar/snack_route.dart'; 20 +export 'src/snackbar/snackbar.dart';
  21 +export 'src/snackbar/snackbar_controller.dart';
@@ -11,243 +11,56 @@ import 'dialog/dialog_route.dart'; @@ -11,243 +11,56 @@ import 'dialog/dialog_route.dart';
11 import 'root/parse_route.dart'; 11 import 'root/parse_route.dart';
12 import 'root/root_controller.dart'; 12 import 'root/root_controller.dart';
13 import 'routes/transitions_type.dart'; 13 import 'routes/transitions_type.dart';
  14 +import 'snackbar/snackbar_controller.dart';
14 15
15 -extension ExtensionSnackbar on GetInterface {  
16 - void rawSnackbar({  
17 - String? title,  
18 - String? message,  
19 - Widget? titleText,  
20 - Widget? messageText,  
21 - Widget? icon,  
22 - bool instantInit = true,  
23 - bool shouldIconPulse = true,  
24 - double? maxWidth,  
25 - EdgeInsets margin = const EdgeInsets.all(0.0),  
26 - EdgeInsets padding = const EdgeInsets.all(16),  
27 - double borderRadius = 0.0,  
28 - Color? borderColor,  
29 - double borderWidth = 1.0,  
30 - Color backgroundColor = const Color(0xFF303030),  
31 - Color? leftBarIndicatorColor,  
32 - List<BoxShadow>? boxShadows,  
33 - Gradient? backgroundGradient,  
34 - Widget? mainButton,  
35 - OnTap? onTap,  
36 - Duration duration = const Duration(seconds: 3),  
37 - bool isDismissible = true,  
38 - SnackDismissDirection dismissDirection = SnackDismissDirection.VERTICAL,  
39 - bool showProgressIndicator = false,  
40 - AnimationController? progressIndicatorController,  
41 - Color? progressIndicatorBackgroundColor,  
42 - Animation<Color>? progressIndicatorValueColor,  
43 - SnackPosition snackPosition = SnackPosition.BOTTOM,  
44 - SnackStyle snackStyle = SnackStyle.FLOATING,  
45 - Curve forwardAnimationCurve = Curves.easeOutCirc,  
46 - Curve reverseAnimationCurve = Curves.easeOutCirc,  
47 - Duration animationDuration = const Duration(seconds: 1),  
48 - SnackbarStatusCallback? snackbarStatus,  
49 - double? barBlur = 0.0,  
50 - double overlayBlur = 0.0,  
51 - Color? overlayColor,  
52 - Form? userInputForm,  
53 - }) async {  
54 - final getBar = GetBar(  
55 - snackbarStatus: snackbarStatus,  
56 - title: title,  
57 - message: message,  
58 - titleText: titleText,  
59 - messageText: messageText,  
60 - snackPosition: snackPosition,  
61 - borderRadius: borderRadius,  
62 - margin: margin,  
63 - duration: duration,  
64 - barBlur: barBlur,  
65 - backgroundColor: backgroundColor,  
66 - icon: icon,  
67 - shouldIconPulse: shouldIconPulse,  
68 - maxWidth: maxWidth,  
69 - padding: padding,  
70 - borderColor: borderColor,  
71 - borderWidth: borderWidth,  
72 - leftBarIndicatorColor: leftBarIndicatorColor,  
73 - boxShadows: boxShadows,  
74 - backgroundGradient: backgroundGradient,  
75 - mainButton: mainButton,  
76 - onTap: onTap,  
77 - isDismissible: isDismissible,  
78 - dismissDirection: dismissDirection,  
79 - showProgressIndicator: showProgressIndicator,  
80 - progressIndicatorController: progressIndicatorController,  
81 - progressIndicatorBackgroundColor: progressIndicatorBackgroundColor,  
82 - progressIndicatorValueColor: progressIndicatorValueColor,  
83 - snackStyle: snackStyle,  
84 - forwardAnimationCurve: forwardAnimationCurve,  
85 - reverseAnimationCurve: reverseAnimationCurve,  
86 - animationDuration: animationDuration,  
87 - overlayBlur: overlayBlur,  
88 - overlayColor: overlayColor,  
89 - userInputForm: userInputForm,  
90 - );  
91 -  
92 - if (instantInit) {  
93 - getBar.show();  
94 - } else {  
95 - SchedulerBinding.instance!.addPostFrameCallback((_) {  
96 - getBar.show();  
97 - });  
98 - }  
99 - }  
100 -  
101 - Future<T?>? showSnackbar<T>(GetBar snackbar) {  
102 - return key.currentState?.push(SnackRoute<T>(snack: snackbar));  
103 - }  
104 -  
105 - void snackbar<T>(  
106 - String title,  
107 - String message, {  
108 - Color? colorText,  
109 - Duration? duration, 16 +/// It replaces the Flutter Navigator, but needs no context.
  17 +/// You can to use navigator.push(YourRoute()) rather
  18 +/// Navigator.push(context, YourRoute());
  19 +NavigatorState? get navigator => GetNavigation(Get).key.currentState;
110 20
111 - /// with instantInit = false you can put snackbar on initState  
112 - bool instantInit = true,  
113 - SnackPosition? snackPosition,  
114 - Widget? titleText,  
115 - Widget? messageText,  
116 - Widget? icon,  
117 - bool? shouldIconPulse,  
118 - double? maxWidth,  
119 - EdgeInsets? margin,  
120 - EdgeInsets? padding,  
121 - double? borderRadius,  
122 - Color? borderColor,  
123 - double? borderWidth, 21 +extension ExtensionBottomSheet on GetInterface {
  22 + Future<T?> bottomSheet<T>(
  23 + Widget bottomsheet, {
124 Color? backgroundColor, 24 Color? backgroundColor,
125 - Color? leftBarIndicatorColor,  
126 - List<BoxShadow>? boxShadows,  
127 - Gradient? backgroundGradient,  
128 - TextButton? mainButton,  
129 - OnTap? onTap,  
130 - bool? isDismissible,  
131 - bool? showProgressIndicator,  
132 - SnackDismissDirection? dismissDirection,  
133 - AnimationController? progressIndicatorController,  
134 - Color? progressIndicatorBackgroundColor,  
135 - Animation<Color>? progressIndicatorValueColor,  
136 - SnackStyle? snackStyle,  
137 - Curve? forwardAnimationCurve,  
138 - Curve? reverseAnimationCurve,  
139 - Duration? animationDuration,  
140 - double? barBlur,  
141 - double? overlayBlur,  
142 - SnackbarStatusCallback? snackbarStatus,  
143 - Color? overlayColor,  
144 - Form? userInputForm,  
145 - }) async {  
146 - final getBar = GetBar(  
147 - snackbarStatus: snackbarStatus,  
148 - titleText: titleText ??  
149 - Text(  
150 - title,  
151 - style: TextStyle(  
152 - color: colorText ?? iconColor ?? Colors.black,  
153 - fontWeight: FontWeight.w800,  
154 - fontSize: 16,  
155 - ),  
156 - ),  
157 - messageText: messageText ??  
158 - Text(  
159 - message,  
160 - style: TextStyle(  
161 - color: colorText ?? iconColor ?? Colors.black,  
162 - fontWeight: FontWeight.w300,  
163 - fontSize: 14,  
164 - ),  
165 - ),  
166 - snackPosition: snackPosition ?? SnackPosition.TOP,  
167 - borderRadius: borderRadius ?? 15,  
168 - margin: margin ?? EdgeInsets.symmetric(horizontal: 10),  
169 - duration: duration ?? Duration(seconds: 3),  
170 - barBlur: barBlur ?? 7.0,  
171 - backgroundColor: backgroundColor ?? Colors.grey.withOpacity(0.2),  
172 - icon: icon,  
173 - shouldIconPulse: shouldIconPulse ?? true,  
174 - maxWidth: maxWidth,  
175 - padding: padding ?? EdgeInsets.all(16),  
176 - borderColor: borderColor,  
177 - borderWidth: borderWidth,  
178 - leftBarIndicatorColor: leftBarIndicatorColor,  
179 - boxShadows: boxShadows,  
180 - backgroundGradient: backgroundGradient,  
181 - mainButton: mainButton,  
182 - onTap: onTap,  
183 - isDismissible: isDismissible ?? true,  
184 - dismissDirection: dismissDirection ?? SnackDismissDirection.VERTICAL,  
185 - showProgressIndicator: showProgressIndicator ?? false,  
186 - progressIndicatorController: progressIndicatorController,  
187 - progressIndicatorBackgroundColor: progressIndicatorBackgroundColor,  
188 - progressIndicatorValueColor: progressIndicatorValueColor,  
189 - snackStyle: snackStyle ?? SnackStyle.FLOATING,  
190 - forwardAnimationCurve: forwardAnimationCurve ?? Curves.easeOutCirc,  
191 - reverseAnimationCurve: reverseAnimationCurve ?? Curves.easeOutCirc,  
192 - animationDuration: animationDuration ?? Duration(seconds: 1),  
193 - overlayBlur: overlayBlur ?? 0.0,  
194 - overlayColor: overlayColor ?? Colors.transparent,  
195 - userInputForm: userInputForm);  
196 -  
197 - if (instantInit) {  
198 - showSnackbar<T>(getBar);  
199 - } else {  
200 - routing.isSnackbar = true;  
201 - SchedulerBinding.instance!.addPostFrameCallback((_) {  
202 - showSnackbar<T>(getBar);  
203 - });  
204 - }  
205 - }  
206 -}  
207 -  
208 -extension OverlayExt on GetInterface {  
209 - Future<T> showOverlay<T>({  
210 - required Future<T> Function() asyncFunction,  
211 - Color opacityColor = Colors.black,  
212 - Widget? loadingWidget,  
213 - double opacity = .5,  
214 - }) async {  
215 - final navigatorState =  
216 - Navigator.of(Get.overlayContext!, rootNavigator: false);  
217 - final overlayState = navigatorState.overlay!;  
218 -  
219 - final overlayEntryOpacity = OverlayEntry(builder: (context) {  
220 - return Opacity(  
221 - opacity: opacity,  
222 - child: Container(  
223 - color: opacityColor,  
224 - ));  
225 - });  
226 - final overlayEntryLoader = OverlayEntry(builder: (context) {  
227 - return loadingWidget ??  
228 - Center(  
229 - child: Container(  
230 - height: 90,  
231 - width: 90,  
232 - child: Text('Loading...'),  
233 - ));  
234 - });  
235 - overlayState.insert(overlayEntryOpacity);  
236 - overlayState.insert(overlayEntryLoader);  
237 -  
238 - T data; 25 + double? elevation,
  26 + bool persistent = true,
  27 + ShapeBorder? shape,
  28 + Clip? clipBehavior,
  29 + Color? barrierColor,
  30 + bool? ignoreSafeArea,
  31 + bool isScrollControlled = false,
  32 + bool useRootNavigator = false,
  33 + bool isDismissible = true,
  34 + bool enableDrag = true,
  35 + RouteSettings? settings,
  36 + Duration? enterBottomSheetDuration,
  37 + Duration? exitBottomSheetDuration,
  38 + }) {
  39 + return Navigator.of(overlayContext!, rootNavigator: useRootNavigator)
  40 + .push(GetModalBottomSheetRoute<T>(
  41 + builder: (_) => bottomsheet,
  42 + isPersistent: persistent,
  43 + // theme: Theme.of(key.currentContext, shadowThemeOnly: true),
  44 + theme: Theme.of(key.currentContext!),
  45 + isScrollControlled: isScrollControlled,
239 46
240 - try {  
241 - data = await asyncFunction();  
242 - } on Exception catch (_) {  
243 - overlayEntryLoader.remove();  
244 - overlayEntryOpacity.remove();  
245 - rethrow;  
246 - } 47 + barrierLabel: MaterialLocalizations.of(key.currentContext!)
  48 + .modalBarrierDismissLabel,
247 49
248 - overlayEntryLoader.remove();  
249 - overlayEntryOpacity.remove();  
250 - return data; 50 + backgroundColor: backgroundColor ?? Colors.transparent,
  51 + elevation: elevation,
  52 + shape: shape,
  53 + removeTop: ignoreSafeArea ?? true,
  54 + clipBehavior: clipBehavior,
  55 + isDismissible: isDismissible,
  56 + modalBarrierColor: barrierColor,
  57 + settings: settings,
  58 + enableDrag: enableDrag,
  59 + enterBottomSheetDuration:
  60 + enterBottomSheetDuration ?? const Duration(milliseconds: 250),
  61 + exitBottomSheetDuration:
  62 + exitBottomSheetDuration ?? const Duration(milliseconds: 200),
  63 + ));
251 } 64 }
252 } 65 }
253 66
@@ -378,7 +191,7 @@ extension ExtensionDialog on GetInterface { @@ -378,7 +191,7 @@ extension ExtensionDialog on GetInterface {
378 padding: EdgeInsets.symmetric(horizontal: 10, vertical: 8), 191 padding: EdgeInsets.symmetric(horizontal: 10, vertical: 8),
379 shape: RoundedRectangleBorder( 192 shape: RoundedRectangleBorder(
380 side: BorderSide( 193 side: BorderSide(
381 - color: buttonColor ?? theme.accentColor, 194 + color: buttonColor ?? theme.colorScheme.secondary,
382 width: 2, 195 width: 2,
383 style: BorderStyle.solid), 196 style: BorderStyle.solid),
384 borderRadius: BorderRadius.circular(100)), 197 borderRadius: BorderRadius.circular(100)),
@@ -389,7 +202,8 @@ extension ExtensionDialog on GetInterface { @@ -389,7 +202,8 @@ extension ExtensionDialog on GetInterface {
389 }, 202 },
390 child: Text( 203 child: Text(
391 textCancel ?? "Cancel", 204 textCancel ?? "Cancel",
392 - style: TextStyle(color: cancelTextColor ?? theme.accentColor), 205 + style: TextStyle(
  206 + color: cancelTextColor ?? theme.colorScheme.secondary),
393 ), 207 ),
394 )); 208 ));
395 } 209 }
@@ -401,7 +215,7 @@ extension ExtensionDialog on GetInterface { @@ -401,7 +215,7 @@ extension ExtensionDialog on GetInterface {
401 actions.add(TextButton( 215 actions.add(TextButton(
402 style: TextButton.styleFrom( 216 style: TextButton.styleFrom(
403 tapTargetSize: MaterialTapTargetSize.shrinkWrap, 217 tapTargetSize: MaterialTapTargetSize.shrinkWrap,
404 - backgroundColor: buttonColor ?? theme.accentColor, 218 + backgroundColor: buttonColor ?? theme.colorScheme.secondary,
405 shape: RoundedRectangleBorder( 219 shape: RoundedRectangleBorder(
406 borderRadius: BorderRadius.circular(100)), 220 borderRadius: BorderRadius.circular(100)),
407 ), 221 ),
@@ -416,94 +230,249 @@ extension ExtensionDialog on GetInterface { @@ -416,94 +230,249 @@ extension ExtensionDialog on GetInterface {
416 } 230 }
417 } 231 }
418 232
419 - Widget baseAlertDialog = AlertDialog(  
420 - titlePadding: titlePadding ?? EdgeInsets.all(8),  
421 - contentPadding: contentPadding ?? EdgeInsets.all(8), 233 + Widget baseAlertDialog = AlertDialog(
  234 + titlePadding: titlePadding ?? EdgeInsets.all(8),
  235 + contentPadding: contentPadding ?? EdgeInsets.all(8),
  236 +
  237 + backgroundColor: backgroundColor ?? theme.dialogBackgroundColor,
  238 + shape: RoundedRectangleBorder(
  239 + borderRadius: BorderRadius.all(Radius.circular(radius))),
  240 + title: Text(title, textAlign: TextAlign.center, style: titleStyle),
  241 + content: Column(
  242 + crossAxisAlignment: CrossAxisAlignment.center,
  243 + mainAxisSize: MainAxisSize.min,
  244 + children: [
  245 + content ??
  246 + Text(middleText,
  247 + textAlign: TextAlign.center, style: middleTextStyle),
  248 + SizedBox(height: 16),
  249 + ButtonTheme(
  250 + minWidth: 78.0,
  251 + height: 34.0,
  252 + child: Wrap(
  253 + alignment: WrapAlignment.center,
  254 + spacing: 8,
  255 + runSpacing: 8,
  256 + children: actions,
  257 + ),
  258 + )
  259 + ],
  260 + ),
  261 + // actions: actions, // ?? <Widget>[cancelButton, confirmButton],
  262 + buttonPadding: EdgeInsets.zero,
  263 + );
  264 +
  265 + return dialog<T>(
  266 + onWillPop != null
  267 + ? WillPopScope(
  268 + onWillPop: onWillPop,
  269 + child: baseAlertDialog,
  270 + )
  271 + : baseAlertDialog,
  272 + barrierDismissible: barrierDismissible,
  273 + navigatorKey: navigatorKey,
  274 + );
  275 + }
  276 +}
  277 +
  278 +extension ExtensionSnackbar on GetInterface {
  279 + SnackbarController rawSnackbar({
  280 + String? title,
  281 + String? message,
  282 + Widget? titleText,
  283 + Widget? messageText,
  284 + Widget? icon,
  285 + bool instantInit = true,
  286 + bool shouldIconPulse = true,
  287 + double? maxWidth,
  288 + EdgeInsets margin = const EdgeInsets.all(0.0),
  289 + EdgeInsets padding = const EdgeInsets.all(16),
  290 + double borderRadius = 0.0,
  291 + Color? borderColor,
  292 + double borderWidth = 1.0,
  293 + Color backgroundColor = const Color(0xFF303030),
  294 + Color? leftBarIndicatorColor,
  295 + List<BoxShadow>? boxShadows,
  296 + Gradient? backgroundGradient,
  297 + Widget? mainButton,
  298 + OnTap? onTap,
  299 + Duration? duration = const Duration(seconds: 3),
  300 + bool isDismissible = true,
  301 + DismissDirection? dismissDirection,
  302 + bool showProgressIndicator = false,
  303 + AnimationController? progressIndicatorController,
  304 + Color? progressIndicatorBackgroundColor,
  305 + Animation<Color>? progressIndicatorValueColor,
  306 + SnackPosition snackPosition = SnackPosition.BOTTOM,
  307 + SnackStyle snackStyle = SnackStyle.FLOATING,
  308 + Curve forwardAnimationCurve = Curves.easeOutCirc,
  309 + Curve reverseAnimationCurve = Curves.easeOutCirc,
  310 + Duration animationDuration = const Duration(seconds: 1),
  311 + SnackbarStatusCallback? snackbarStatus,
  312 + double barBlur = 0.0,
  313 + double overlayBlur = 0.0,
  314 + Color? overlayColor,
  315 + Form? userInputForm,
  316 + }) {
  317 + final getSnackBar = GetSnackBar(
  318 + snackbarStatus: snackbarStatus,
  319 + title: title,
  320 + message: message,
  321 + titleText: titleText,
  322 + messageText: messageText,
  323 + snackPosition: snackPosition,
  324 + borderRadius: borderRadius,
  325 + margin: margin,
  326 + duration: duration,
  327 + barBlur: barBlur,
  328 + backgroundColor: backgroundColor,
  329 + icon: icon,
  330 + shouldIconPulse: shouldIconPulse,
  331 + maxWidth: maxWidth,
  332 + padding: padding,
  333 + borderColor: borderColor,
  334 + borderWidth: borderWidth,
  335 + leftBarIndicatorColor: leftBarIndicatorColor,
  336 + boxShadows: boxShadows,
  337 + backgroundGradient: backgroundGradient,
  338 + mainButton: mainButton,
  339 + onTap: onTap,
  340 + isDismissible: isDismissible,
  341 + dismissDirection: dismissDirection,
  342 + showProgressIndicator: showProgressIndicator,
  343 + progressIndicatorController: progressIndicatorController,
  344 + progressIndicatorBackgroundColor: progressIndicatorBackgroundColor,
  345 + progressIndicatorValueColor: progressIndicatorValueColor,
  346 + snackStyle: snackStyle,
  347 + forwardAnimationCurve: forwardAnimationCurve,
  348 + reverseAnimationCurve: reverseAnimationCurve,
  349 + animationDuration: animationDuration,
  350 + overlayBlur: overlayBlur,
  351 + overlayColor: overlayColor,
  352 + userInputForm: userInputForm,
  353 + );
  354 +
  355 + final controller = SnackbarController(getSnackBar);
422 356
423 - backgroundColor: backgroundColor ?? theme.dialogBackgroundColor,  
424 - shape: RoundedRectangleBorder(  
425 - borderRadius: BorderRadius.all(Radius.circular(radius))),  
426 - title: Text(title, textAlign: TextAlign.center, style: titleStyle),  
427 - content: Column(  
428 - crossAxisAlignment: CrossAxisAlignment.center,  
429 - mainAxisSize: MainAxisSize.min,  
430 - children: [  
431 - content ??  
432 - Text(middleText,  
433 - textAlign: TextAlign.center, style: middleTextStyle),  
434 - SizedBox(height: 16),  
435 - ButtonTheme(  
436 - minWidth: 78.0,  
437 - height: 34.0,  
438 - child: Wrap(  
439 - alignment: WrapAlignment.center,  
440 - spacing: 8,  
441 - runSpacing: 8,  
442 - children: actions,  
443 - ),  
444 - )  
445 - ],  
446 - ),  
447 - // actions: actions, // ?? <Widget>[cancelButton, confirmButton],  
448 - buttonPadding: EdgeInsets.zero,  
449 - ); 357 + if (instantInit) {
  358 + controller.show();
  359 + } else {
  360 + SchedulerBinding.instance!.addPostFrameCallback((_) {
  361 + controller.show();
  362 + });
  363 + }
  364 + return controller;
  365 + }
450 366
451 - return dialog<T>(  
452 - onWillPop != null  
453 - ? WillPopScope(  
454 - onWillPop: onWillPop,  
455 - child: baseAlertDialog,  
456 - )  
457 - : baseAlertDialog,  
458 - barrierDismissible: barrierDismissible,  
459 - navigatorKey: navigatorKey,  
460 - ); 367 + SnackbarController showSnackbar(GetSnackBar snackbar) {
  368 + final controller = SnackbarController(snackbar);
  369 + controller.show();
  370 + return controller;
461 } 371 }
462 -}  
463 372
464 -extension ExtensionBottomSheet on GetInterface {  
465 - Future<T?> bottomSheet<T>(  
466 - Widget bottomsheet, { 373 + SnackbarController snackbar(
  374 + String title,
  375 + String message, {
  376 + Color? colorText,
  377 + Duration? duration = const Duration(seconds: 3),
  378 +
  379 + /// with instantInit = false you can put snackbar on initState
  380 + bool instantInit = true,
  381 + SnackPosition? snackPosition,
  382 + Widget? titleText,
  383 + Widget? messageText,
  384 + Widget? icon,
  385 + bool? shouldIconPulse,
  386 + double? maxWidth,
  387 + EdgeInsets? margin,
  388 + EdgeInsets? padding,
  389 + double? borderRadius,
  390 + Color? borderColor,
  391 + double? borderWidth,
467 Color? backgroundColor, 392 Color? backgroundColor,
468 - double? elevation,  
469 - bool persistent = true,  
470 - ShapeBorder? shape,  
471 - Clip? clipBehavior,  
472 - Color? barrierColor,  
473 - bool? ignoreSafeArea,  
474 - bool isScrollControlled = false,  
475 - bool useRootNavigator = false,  
476 - bool isDismissible = true,  
477 - bool enableDrag = true,  
478 - RouteSettings? settings,  
479 - Duration? enterBottomSheetDuration,  
480 - Duration? exitBottomSheetDuration, 393 + Color? leftBarIndicatorColor,
  394 + List<BoxShadow>? boxShadows,
  395 + Gradient? backgroundGradient,
  396 + TextButton? mainButton,
  397 + OnTap? onTap,
  398 + bool? isDismissible,
  399 + bool? showProgressIndicator,
  400 + DismissDirection? dismissDirection,
  401 + AnimationController? progressIndicatorController,
  402 + Color? progressIndicatorBackgroundColor,
  403 + Animation<Color>? progressIndicatorValueColor,
  404 + SnackStyle? snackStyle,
  405 + Curve? forwardAnimationCurve,
  406 + Curve? reverseAnimationCurve,
  407 + Duration? animationDuration,
  408 + double? barBlur,
  409 + double? overlayBlur,
  410 + SnackbarStatusCallback? snackbarStatus,
  411 + Color? overlayColor,
  412 + Form? userInputForm,
481 }) { 413 }) {
482 - return Navigator.of(overlayContext!, rootNavigator: useRootNavigator)  
483 - .push(GetModalBottomSheetRoute<T>(  
484 - builder: (_) => bottomsheet,  
485 - isPersistent: persistent,  
486 - // theme: Theme.of(key.currentContext, shadowThemeOnly: true),  
487 - theme: Theme.of(key.currentContext!),  
488 - isScrollControlled: isScrollControlled, 414 + final getSnackBar = GetSnackBar(
  415 + snackbarStatus: snackbarStatus,
  416 + titleText: titleText ??
  417 + Text(
  418 + title,
  419 + style: TextStyle(
  420 + color: colorText ?? iconColor ?? Colors.black,
  421 + fontWeight: FontWeight.w800,
  422 + fontSize: 16,
  423 + ),
  424 + ),
  425 + messageText: messageText ??
  426 + Text(
  427 + message,
  428 + style: TextStyle(
  429 + color: colorText ?? iconColor ?? Colors.black,
  430 + fontWeight: FontWeight.w300,
  431 + fontSize: 14,
  432 + ),
  433 + ),
  434 + snackPosition: snackPosition ?? SnackPosition.TOP,
  435 + borderRadius: borderRadius ?? 15,
  436 + margin: margin ?? EdgeInsets.symmetric(horizontal: 10),
  437 + duration: duration,
  438 + barBlur: barBlur ?? 7.0,
  439 + backgroundColor: backgroundColor ?? Colors.grey.withOpacity(0.2),
  440 + icon: icon,
  441 + shouldIconPulse: shouldIconPulse ?? true,
  442 + maxWidth: maxWidth,
  443 + padding: padding ?? EdgeInsets.all(16),
  444 + borderColor: borderColor,
  445 + borderWidth: borderWidth,
  446 + leftBarIndicatorColor: leftBarIndicatorColor,
  447 + boxShadows: boxShadows,
  448 + backgroundGradient: backgroundGradient,
  449 + mainButton: mainButton,
  450 + onTap: onTap,
  451 + isDismissible: isDismissible ?? true,
  452 + dismissDirection: dismissDirection,
  453 + showProgressIndicator: showProgressIndicator ?? false,
  454 + progressIndicatorController: progressIndicatorController,
  455 + progressIndicatorBackgroundColor: progressIndicatorBackgroundColor,
  456 + progressIndicatorValueColor: progressIndicatorValueColor,
  457 + snackStyle: snackStyle ?? SnackStyle.FLOATING,
  458 + forwardAnimationCurve: forwardAnimationCurve ?? Curves.easeOutCirc,
  459 + reverseAnimationCurve: reverseAnimationCurve ?? Curves.easeOutCirc,
  460 + animationDuration: animationDuration ?? Duration(seconds: 1),
  461 + overlayBlur: overlayBlur ?? 0.0,
  462 + overlayColor: overlayColor ?? Colors.transparent,
  463 + userInputForm: userInputForm);
489 464
490 - barrierLabel: MaterialLocalizations.of(key.currentContext!)  
491 - .modalBarrierDismissLabel, 465 + final controller = SnackbarController(getSnackBar);
492 466
493 - backgroundColor: backgroundColor ?? Colors.transparent,  
494 - elevation: elevation,  
495 - shape: shape,  
496 - removeTop: ignoreSafeArea ?? true,  
497 - clipBehavior: clipBehavior,  
498 - isDismissible: isDismissible,  
499 - modalBarrierColor: barrierColor,  
500 - settings: settings,  
501 - enableDrag: enableDrag,  
502 - enterBottomSheetDuration:  
503 - enterBottomSheetDuration ?? const Duration(milliseconds: 250),  
504 - exitBottomSheetDuration:  
505 - exitBottomSheetDuration ?? const Duration(milliseconds: 200),  
506 - )); 467 + if (instantInit) {
  468 + controller.show();
  469 + } else {
  470 + //routing.isSnackbar = true;
  471 + SchedulerBinding.instance!.addPostFrameCallback((_) {
  472 + controller.show();
  473 + });
  474 + }
  475 + return controller;
507 } 476 }
508 } 477 }
509 478
@@ -826,11 +795,11 @@ you can only use widgets and widget functions here'''; @@ -826,11 +795,11 @@ you can only use widgets and widget functions here''';
826 795
827 /// Returns true if a Snackbar, Dialog or BottomSheet is currently OPEN 796 /// Returns true if a Snackbar, Dialog or BottomSheet is currently OPEN
828 bool get isOverlaysOpen => 797 bool get isOverlaysOpen =>
829 - (isSnackbarOpen! || isDialogOpen! || isBottomSheetOpen!); 798 + (isSnackbarOpen || isDialogOpen! || isBottomSheetOpen!);
830 799
831 /// Returns true if there is no Snackbar, Dialog or BottomSheet open 800 /// Returns true if there is no Snackbar, Dialog or BottomSheet open
832 bool get isOverlaysClosed => 801 bool get isOverlaysClosed =>
833 - (!isSnackbarOpen! && !isDialogOpen! && !isBottomSheetOpen!); 802 + (!isSnackbarOpen && !isDialogOpen! && !isBottomSheetOpen!);
834 803
835 /// **Navigation.popUntil()** shortcut.<br><br> 804 /// **Navigation.popUntil()** shortcut.<br><br>
836 /// 805 ///
@@ -850,9 +819,21 @@ you can only use widgets and widget functions here'''; @@ -850,9 +819,21 @@ you can only use widgets and widget functions here''';
850 bool canPop = true, 819 bool canPop = true,
851 int? id, 820 int? id,
852 }) { 821 }) {
  822 + //TODO: This code brings compatibility of the new snackbar with GetX 4,
  823 + // remove this code in version 5
  824 + if (isSnackbarOpen && !closeOverlays) {
  825 + closeCurrentSnackbar();
  826 + return;
  827 + }
  828 +
853 if (closeOverlays && isOverlaysOpen) { 829 if (closeOverlays && isOverlaysOpen) {
  830 + //TODO: This code brings compatibility of the new snackbar with GetX 4,
  831 + // remove this code in version 5
  832 + if (isSnackbarOpen) {
  833 + closeAllSnackbars();
  834 + }
854 navigator?.popUntil((route) { 835 navigator?.popUntil((route) {
855 - return (isOverlaysClosed); 836 + return (!isDialogOpen! && !isBottomSheetOpen!);
856 }); 837 });
857 } 838 }
858 if (canPop) { 839 if (canPop) {
@@ -1135,7 +1116,16 @@ you can only use widgets and widget functions here'''; @@ -1135,7 +1116,16 @@ you can only use widgets and widget functions here''';
1135 String get previousRoute => routing.previous; 1116 String get previousRoute => routing.previous;
1136 1117
1137 /// check if snackbar is open 1118 /// check if snackbar is open
1138 - bool? get isSnackbarOpen => routing.isSnackbar; 1119 + bool get isSnackbarOpen =>
  1120 + SnackbarController.isSnackbarBeingShown; //routing.isSnackbar;
  1121 +
  1122 + void closeAllSnackbars() {
  1123 + SnackbarController.cancelAllSnackbars();
  1124 + }
  1125 +
  1126 + Future<void> closeCurrentSnackbar() async {
  1127 + await SnackbarController.closeCurrentSnackbar();
  1128 + }
1139 1129
1140 /// check if dialog is open 1130 /// check if dialog is open
1141 bool? get isDialogOpen => routing.isDialog; 1131 bool? get isDialogOpen => routing.isDialog;
@@ -1341,7 +1331,48 @@ extension NavTwoExt on GetInterface { @@ -1341,7 +1331,48 @@ extension NavTwoExt on GetInterface {
1341 } 1331 }
1342 } 1332 }
1343 1333
1344 -/// It replaces the Flutter Navigator, but needs no context.  
1345 -/// You can to use navigator.push(YourRoute()) rather  
1346 -/// Navigator.push(context, YourRoute());  
1347 -NavigatorState? get navigator => GetNavigation(Get).key.currentState; 1334 +extension OverlayExt on GetInterface {
  1335 + Future<T> showOverlay<T>({
  1336 + required Future<T> Function() asyncFunction,
  1337 + Color opacityColor = Colors.black,
  1338 + Widget? loadingWidget,
  1339 + double opacity = .5,
  1340 + }) async {
  1341 + final navigatorState =
  1342 + Navigator.of(Get.overlayContext!, rootNavigator: false);
  1343 + final overlayState = navigatorState.overlay!;
  1344 +
  1345 + final overlayEntryOpacity = OverlayEntry(builder: (context) {
  1346 + return Opacity(
  1347 + opacity: opacity,
  1348 + child: Container(
  1349 + color: opacityColor,
  1350 + ));
  1351 + });
  1352 + final overlayEntryLoader = OverlayEntry(builder: (context) {
  1353 + return loadingWidget ??
  1354 + Center(
  1355 + child: Container(
  1356 + height: 90,
  1357 + width: 90,
  1358 + child: Text('Loading...'),
  1359 + ));
  1360 + });
  1361 + overlayState.insert(overlayEntryOpacity);
  1362 + overlayState.insert(overlayEntryLoader);
  1363 +
  1364 + T data;
  1365 +
  1366 + try {
  1367 + data = await asyncFunction();
  1368 + } on Exception catch (_) {
  1369 + overlayEntryLoader.remove();
  1370 + overlayEntryOpacity.remove();
  1371 + rethrow;
  1372 + }
  1373 +
  1374 + overlayEntryLoader.remove();
  1375 + overlayEntryOpacity.remove();
  1376 + return data;
  1377 + }
  1378 +}
1 import 'package:flutter/foundation.dart'; 1 import 'package:flutter/foundation.dart';
2 import 'package:flutter/widgets.dart'; 2 import 'package:flutter/widgets.dart';
  3 +
3 import '../../../get.dart'; 4 import '../../../get.dart';
4 5
5 class GetInformationParser extends RouteInformationParser<GetNavConfig> { 6 class GetInformationParser extends RouteInformationParser<GetNavConfig> {
@@ -14,7 +15,6 @@ class GetInformationParser extends RouteInformationParser<GetNavConfig> { @@ -14,7 +15,6 @@ class GetInformationParser extends RouteInformationParser<GetNavConfig> {
14 SynchronousFuture<GetNavConfig> parseRouteInformation( 15 SynchronousFuture<GetNavConfig> parseRouteInformation(
15 RouteInformation routeInformation, 16 RouteInformation routeInformation,
16 ) { 17 ) {
17 - Get.log('GetInformationParser: route location: ${routeInformation.location}');  
18 var location = routeInformation.location; 18 var location = routeInformation.location;
19 if (location == '/') { 19 if (location == '/') {
20 //check if there is a corresponding page 20 //check if there is a corresponding page
@@ -24,6 +24,8 @@ class GetInformationParser extends RouteInformationParser<GetNavConfig> { @@ -24,6 +24,8 @@ class GetInformationParser extends RouteInformationParser<GetNavConfig> {
24 } 24 }
25 } 25 }
26 26
  27 + Get.log('GetInformationParser: route location: $location');
  28 +
27 final matchResult = Get.routeTree.matchRoute(location ?? initialRoute); 29 final matchResult = Get.routeTree.matchRoute(location ?? initialRoute);
28 30
29 return SynchronousFuture( 31 return SynchronousFuture(
@@ -10,6 +10,63 @@ import '../../get_navigation.dart'; @@ -10,6 +10,63 @@ import '../../get_navigation.dart';
10 import 'root_controller.dart'; 10 import 'root_controller.dart';
11 11
12 class GetMaterialApp extends StatelessWidget { 12 class GetMaterialApp extends StatelessWidget {
  13 + final GlobalKey<NavigatorState>? navigatorKey;
  14 +
  15 + final GlobalKey<ScaffoldMessengerState>? scaffoldMessengerKey;
  16 + final Widget? home;
  17 + final Map<String, WidgetBuilder>? routes;
  18 + final String? initialRoute;
  19 + final RouteFactory? onGenerateRoute;
  20 + final InitialRouteListFactory? onGenerateInitialRoutes;
  21 + final RouteFactory? onUnknownRoute;
  22 + final List<NavigatorObserver>? navigatorObservers;
  23 + final TransitionBuilder? builder;
  24 + final String title;
  25 + final GenerateAppTitle? onGenerateTitle;
  26 + final ThemeData? theme;
  27 + final ThemeData? darkTheme;
  28 + final ThemeMode themeMode;
  29 + final CustomTransition? customTransition;
  30 + final Color? color;
  31 + final Map<String, Map<String, String>>? translationsKeys;
  32 + final Translations? translations;
  33 + final TextDirection? textDirection;
  34 + final Locale? locale;
  35 + final Locale? fallbackLocale;
  36 + final Iterable<LocalizationsDelegate<dynamic>>? localizationsDelegates;
  37 + final LocaleListResolutionCallback? localeListResolutionCallback;
  38 + final LocaleResolutionCallback? localeResolutionCallback;
  39 + final Iterable<Locale> supportedLocales;
  40 + final bool showPerformanceOverlay;
  41 + final bool checkerboardRasterCacheImages;
  42 + final bool checkerboardOffscreenLayers;
  43 + final bool showSemanticsDebugger;
  44 + final bool debugShowCheckedModeBanner;
  45 + final Map<LogicalKeySet, Intent>? shortcuts;
  46 + final ScrollBehavior? scrollBehavior;
  47 + final ThemeData? highContrastTheme;
  48 + final ThemeData? highContrastDarkTheme;
  49 + final Map<Type, Action<Intent>>? actions;
  50 + final bool debugShowMaterialGrid;
  51 + final ValueChanged<Routing?>? routingCallback;
  52 + final Transition? defaultTransition;
  53 + final bool? opaqueRoute;
  54 + final VoidCallback? onInit;
  55 + final VoidCallback? onReady;
  56 + final VoidCallback? onDispose;
  57 + final bool? enableLog;
  58 + final LogWriterCallback? logWriterCallback;
  59 + final bool? popGesture;
  60 + final SmartManagement smartManagement;
  61 + final Bindings? initialBinding;
  62 + final Duration? transitionDuration;
  63 + final bool? defaultGlobalState;
  64 + final List<GetPage>? getPages;
  65 + final GetPage? unknownRoute;
  66 + final RouteInformationProvider? routeInformationProvider;
  67 + final RouteInformationParser<Object>? routeInformationParser;
  68 + final RouterDelegate<Object>? routerDelegate;
  69 + final BackButtonDispatcher? backButtonDispatcher;
13 const GetMaterialApp({ 70 const GetMaterialApp({
14 Key? key, 71 Key? key,
15 this.navigatorKey, 72 this.navigatorKey,
@@ -72,63 +129,6 @@ class GetMaterialApp extends StatelessWidget { @@ -72,63 +129,6 @@ class GetMaterialApp extends StatelessWidget {
72 backButtonDispatcher = null, 129 backButtonDispatcher = null,
73 super(key: key); 130 super(key: key);
74 131
75 - final GlobalKey<NavigatorState>? navigatorKey;  
76 - final GlobalKey<ScaffoldMessengerState>? scaffoldMessengerKey;  
77 - final Widget? home;  
78 - final Map<String, WidgetBuilder>? routes;  
79 - final String? initialRoute;  
80 - final RouteFactory? onGenerateRoute;  
81 - final InitialRouteListFactory? onGenerateInitialRoutes;  
82 - final RouteFactory? onUnknownRoute;  
83 - final List<NavigatorObserver>? navigatorObservers;  
84 - final TransitionBuilder? builder;  
85 - final String title;  
86 - final GenerateAppTitle? onGenerateTitle;  
87 - final ThemeData? theme;  
88 - final ThemeData? darkTheme;  
89 - final ThemeMode themeMode;  
90 - final CustomTransition? customTransition;  
91 - final Color? color;  
92 - final Map<String, Map<String, String>>? translationsKeys;  
93 - final Translations? translations;  
94 - final TextDirection? textDirection;  
95 - final Locale? locale;  
96 - final Locale? fallbackLocale;  
97 - final Iterable<LocalizationsDelegate<dynamic>>? localizationsDelegates;  
98 - final LocaleListResolutionCallback? localeListResolutionCallback;  
99 - final LocaleResolutionCallback? localeResolutionCallback;  
100 - final Iterable<Locale> supportedLocales;  
101 - final bool showPerformanceOverlay;  
102 - final bool checkerboardRasterCacheImages;  
103 - final bool checkerboardOffscreenLayers;  
104 - final bool showSemanticsDebugger;  
105 - final bool debugShowCheckedModeBanner;  
106 - final Map<LogicalKeySet, Intent>? shortcuts;  
107 - final ScrollBehavior? scrollBehavior;  
108 - final ThemeData? highContrastTheme;  
109 - final ThemeData? highContrastDarkTheme;  
110 - final Map<Type, Action<Intent>>? actions;  
111 - final bool debugShowMaterialGrid;  
112 - final ValueChanged<Routing?>? routingCallback;  
113 - final Transition? defaultTransition;  
114 - final bool? opaqueRoute;  
115 - final VoidCallback? onInit;  
116 - final VoidCallback? onReady;  
117 - final VoidCallback? onDispose;  
118 - final bool? enableLog;  
119 - final LogWriterCallback? logWriterCallback;  
120 - final bool? popGesture;  
121 - final SmartManagement smartManagement;  
122 - final Bindings? initialBinding;  
123 - final Duration? transitionDuration;  
124 - final bool? defaultGlobalState;  
125 - final List<GetPage>? getPages;  
126 - final GetPage? unknownRoute;  
127 - final RouteInformationProvider? routeInformationProvider;  
128 - final RouteInformationParser<Object>? routeInformationParser;  
129 - final RouterDelegate<Object>? routerDelegate;  
130 - final BackButtonDispatcher? backButtonDispatcher;  
131 -  
132 GetMaterialApp.router({ 132 GetMaterialApp.router({
133 Key? key, 133 Key? key,
134 this.routeInformationProvider, 134 this.routeInformationProvider,
@@ -200,31 +200,6 @@ class GetMaterialApp extends StatelessWidget { @@ -200,31 +200,6 @@ class GetMaterialApp extends StatelessWidget {
200 Get.routeInformationParser = routeInformationParser; 200 Get.routeInformationParser = routeInformationParser;
201 } 201 }
202 202
203 - Route<dynamic> generator(RouteSettings settings) {  
204 - return PageRedirect(settings: settings, unknownRoute: unknownRoute).page();  
205 - }  
206 -  
207 - List<Route<dynamic>> initialRoutesGenerate(String name) {  
208 - return [  
209 - PageRedirect(  
210 - settings: RouteSettings(name: name),  
211 - unknownRoute: unknownRoute,  
212 - ).page()  
213 - ];  
214 - }  
215 -  
216 - Widget defaultBuilder(BuildContext context, Widget? child) {  
217 - return Directionality(  
218 - textDirection: textDirection ??  
219 - (rtlLanguages.contains(Get.locale?.languageCode)  
220 - ? TextDirection.rtl  
221 - : TextDirection.ltr),  
222 - child: builder == null  
223 - ? (child ?? Material())  
224 - : builder!(context, child ?? Material()),  
225 - );  
226 - }  
227 -  
228 @override 203 @override
229 Widget build(BuildContext context) => GetBuilder<GetMaterialController>( 204 Widget build(BuildContext context) => GetBuilder<GetMaterialController>(
230 init: Get.rootController, 205 init: Get.rootController,
@@ -270,7 +245,6 @@ class GetMaterialApp extends StatelessWidget { @@ -270,7 +245,6 @@ class GetMaterialApp extends StatelessWidget {
270 ? MaterialApp.router( 245 ? MaterialApp.router(
271 routerDelegate: routerDelegate!, 246 routerDelegate: routerDelegate!,
272 routeInformationParser: routeInformationParser!, 247 routeInformationParser: routeInformationParser!,
273 - scaffoldMessengerKey: scaffoldMessengerKey,  
274 backButtonDispatcher: backButtonDispatcher, 248 backButtonDispatcher: backButtonDispatcher,
275 routeInformationProvider: routeInformationProvider, 249 routeInformationProvider: routeInformationProvider,
276 key: _.unikey, 250 key: _.unikey,
@@ -283,6 +257,8 @@ class GetMaterialApp extends StatelessWidget { @@ -283,6 +257,8 @@ class GetMaterialApp extends StatelessWidget {
283 _.darkTheme ?? darkTheme ?? theme ?? ThemeData.fallback(), 257 _.darkTheme ?? darkTheme ?? theme ?? ThemeData.fallback(),
284 themeMode: _.themeMode ?? themeMode, 258 themeMode: _.themeMode ?? themeMode,
285 locale: Get.locale ?? locale, 259 locale: Get.locale ?? locale,
  260 + scaffoldMessengerKey:
  261 + scaffoldMessengerKey ?? _.scaffoldMessengerKey,
286 localizationsDelegates: localizationsDelegates, 262 localizationsDelegates: localizationsDelegates,
287 localeListResolutionCallback: localeListResolutionCallback, 263 localeListResolutionCallback: localeListResolutionCallback,
288 localeResolutionCallback: localeResolutionCallback, 264 localeResolutionCallback: localeResolutionCallback,
@@ -301,7 +277,8 @@ class GetMaterialApp extends StatelessWidget { @@ -301,7 +277,8 @@ class GetMaterialApp extends StatelessWidget {
301 navigatorKey: (navigatorKey == null 277 navigatorKey: (navigatorKey == null
302 ? Get.key 278 ? Get.key
303 : Get.addKey(navigatorKey!)), 279 : Get.addKey(navigatorKey!)),
304 - scaffoldMessengerKey: scaffoldMessengerKey, 280 + scaffoldMessengerKey:
  281 + scaffoldMessengerKey ?? _.scaffoldMessengerKey,
305 home: home, 282 home: home,
306 routes: routes ?? const <String, WidgetBuilder>{}, 283 routes: routes ?? const <String, WidgetBuilder>{},
307 initialRoute: initialRoute, 284 initialRoute: initialRoute,
@@ -343,4 +320,29 @@ class GetMaterialApp extends StatelessWidget { @@ -343,4 +320,29 @@ class GetMaterialApp extends StatelessWidget {
343 // actions: actions, 320 // actions: actions,
344 ), 321 ),
345 ); 322 );
  323 +
  324 + Widget defaultBuilder(BuildContext context, Widget? child) {
  325 + return Directionality(
  326 + textDirection: textDirection ??
  327 + (rtlLanguages.contains(Get.locale?.languageCode)
  328 + ? TextDirection.rtl
  329 + : TextDirection.ltr),
  330 + child: builder == null
  331 + ? (child ?? Material())
  332 + : builder!(context, child ?? Material()),
  333 + );
  334 + }
  335 +
  336 + Route<dynamic> generator(RouteSettings settings) {
  337 + return PageRedirect(settings: settings, unknownRoute: unknownRoute).page();
  338 + }
  339 +
  340 + List<Route<dynamic>> initialRoutesGenerate(String name) {
  341 + return [
  342 + PageRedirect(
  343 + settings: RouteSettings(name: name),
  344 + unknownRoute: unknownRoute,
  345 + ).page()
  346 + ];
  347 + }
346 } 348 }
1 import 'package:flutter/material.dart'; 1 import 'package:flutter/material.dart';
  2 +
  3 +import '../../../get.dart';
2 import '../../../get_state_manager/get_state_manager.dart'; 4 import '../../../get_state_manager/get_state_manager.dart';
3 import '../../../get_utils/get_utils.dart'; 5 import '../../../get_utils/get_utils.dart';
4 import '../routes/custom_transition.dart'; 6 import '../routes/custom_transition.dart';
5 import '../routes/observers/route_observer.dart'; 7 import '../routes/observers/route_observer.dart';
6 import '../routes/transitions_type.dart'; 8 import '../routes/transitions_type.dart';
7 9
8 -class GetMaterialController extends GetxController { 10 +class GetMaterialController extends SuperController {
9 bool testMode = false; 11 bool testMode = false;
10 Key? unikey; 12 Key? unikey;
11 ThemeData? theme; 13 ThemeData? theme;
12 ThemeData? darkTheme; 14 ThemeData? darkTheme;
13 ThemeMode? themeMode; 15 ThemeMode? themeMode;
14 16
  17 + final scaffoldMessengerKey = GlobalKey<ScaffoldMessengerState>();
  18 +
15 bool defaultPopGesture = GetPlatform.isIOS; 19 bool defaultPopGesture = GetPlatform.isIOS;
16 bool defaultOpaqueRoute = true; 20 bool defaultOpaqueRoute = true;
17 21
@@ -31,6 +35,8 @@ class GetMaterialController extends GetxController { @@ -31,6 +35,8 @@ class GetMaterialController extends GetxController {
31 35
32 var _key = GlobalKey<NavigatorState>(debugLabel: 'Key Created by default'); 36 var _key = GlobalKey<NavigatorState>(debugLabel: 'Key Created by default');
33 37
  38 + Map<dynamic, GlobalKey<NavigatorState>> keys = {};
  39 +
34 GlobalKey<NavigatorState> get key => _key; 40 GlobalKey<NavigatorState> get key => _key;
35 41
36 GlobalKey<NavigatorState>? addKey(GlobalKey<NavigatorState> newKey) { 42 GlobalKey<NavigatorState>? addKey(GlobalKey<NavigatorState> newKey) {
@@ -38,7 +44,32 @@ class GetMaterialController extends GetxController { @@ -38,7 +44,32 @@ class GetMaterialController extends GetxController {
38 return key; 44 return key;
39 } 45 }
40 46
41 - Map<dynamic, GlobalKey<NavigatorState>> keys = {}; 47 + @override
  48 + void didChangeLocales(List<Locale>? locales) {
  49 + Get.asap(() {
  50 + final locale = Get.deviceLocale;
  51 + if (locale != null) {
  52 + Get.updateLocale(locale);
  53 + }
  54 + });
  55 + }
  56 +
  57 + @override
  58 + void onDetached() {}
  59 +
  60 + @override
  61 + void onInactive() {}
  62 +
  63 + @override
  64 + void onPaused() {}
  65 +
  66 + @override
  67 + void onResumed() {}
  68 +
  69 + void restartApp() {
  70 + unikey = UniqueKey();
  71 + update();
  72 + }
42 73
43 void setTheme(ThemeData value) { 74 void setTheme(ThemeData value) {
44 if (darkTheme == null) { 75 if (darkTheme == null) {
@@ -57,9 +88,4 @@ class GetMaterialController extends GetxController { @@ -57,9 +88,4 @@ class GetMaterialController extends GetxController {
57 themeMode = value; 88 themeMode = value;
58 update(); 89 update();
59 } 90 }
60 -  
61 - void restartApp() {  
62 - unikey = UniqueKey();  
63 - update();  
64 - }  
65 } 91 }
@@ -9,24 +9,6 @@ import '../../get_navigation.dart'; @@ -9,24 +9,6 @@ import '../../get_navigation.dart';
9 import 'custom_transition.dart'; 9 import 'custom_transition.dart';
10 import 'transitions_type.dart'; 10 import 'transitions_type.dart';
11 11
12 -@immutable  
13 -class PathDecoded {  
14 - const PathDecoded(this.regex, this.keys);  
15 - final RegExp regex;  
16 - final List<String?> keys;  
17 -  
18 - @override  
19 - bool operator ==(Object other) {  
20 - if (identical(this, other)) return true;  
21 -  
22 - return other is PathDecoded &&  
23 - other.regex == regex; // && listEquals(other.keys, keys);  
24 - }  
25 -  
26 - @override  
27 - int get hashCode => regex.hashCode;  
28 -}  
29 -  
30 class GetPage<T> extends Page<T> { 12 class GetPage<T> extends Page<T> {
31 final GetPageBuilder page; 13 final GetPageBuilder page;
32 final bool? popGesture; 14 final bool? popGesture;
@@ -98,27 +80,6 @@ class GetPage<T> extends Page<T> { @@ -98,27 +80,6 @@ class GetPage<T> extends Page<T> {
98 ); 80 );
99 // settings = RouteSettings(name: name, arguments: Get.arguments); 81 // settings = RouteSettings(name: name, arguments: Get.arguments);
100 82
101 - static PathDecoded _nameToRegex(String path) {  
102 - var keys = <String?>[];  
103 -  
104 - String _replace(Match pattern) {  
105 - var buffer = StringBuffer('(?:');  
106 -  
107 - if (pattern[1] != null) buffer.write('\.');  
108 - buffer.write('([\\w%+-._~!\$&\'()*,;=:@]+))');  
109 - if (pattern[3] != null) buffer.write('?');  
110 -  
111 - keys.add(pattern[2]);  
112 - return "$buffer";  
113 - }  
114 -  
115 - var stringPath = '$path/?'  
116 - .replaceAllMapped(RegExp(r'(\.)?:(\w+)(\?)?'), _replace)  
117 - .replaceAll('//', '/');  
118 -  
119 - return PathDecoded(RegExp('^$stringPath\$'), keys);  
120 - }  
121 -  
122 GetPage<T> copy({ 83 GetPage<T> copy({
123 String? name, 84 String? name,
124 GetPageBuilder? page, 85 GetPageBuilder? page,
@@ -174,8 +135,6 @@ class GetPage<T> extends Page<T> { @@ -174,8 +135,6 @@ class GetPage<T> extends Page<T> {
174 ); 135 );
175 } 136 }
176 137
177 - late Future<T?> popped;  
178 -  
179 @override 138 @override
180 Route<T> createRoute(BuildContext context) { 139 Route<T> createRoute(BuildContext context) {
181 // return GetPageRoute<T>(settings: this, page: page); 140 // return GetPageRoute<T>(settings: this, page: page);
@@ -185,7 +144,45 @@ class GetPage<T> extends Page<T> { @@ -185,7 +144,45 @@ class GetPage<T> extends Page<T> {
185 unknownRoute: unknownRoute, 144 unknownRoute: unknownRoute,
186 ).getPageToRoute<T>(this, unknownRoute); 145 ).getPageToRoute<T>(this, unknownRoute);
187 146
188 - popped = _page.popped;  
189 return _page; 147 return _page;
190 } 148 }
  149 +
  150 + static PathDecoded _nameToRegex(String path) {
  151 + var keys = <String?>[];
  152 +
  153 + String _replace(Match pattern) {
  154 + var buffer = StringBuffer('(?:');
  155 +
  156 + if (pattern[1] != null) buffer.write('\.');
  157 + buffer.write('([\\w%+-._~!\$&\'()*,;=:@]+))');
  158 + if (pattern[3] != null) buffer.write('?');
  159 +
  160 + keys.add(pattern[2]);
  161 + return "$buffer";
  162 + }
  163 +
  164 + var stringPath = '$path/?'
  165 + .replaceAllMapped(RegExp(r'(\.)?:(\w+)(\?)?'), _replace)
  166 + .replaceAll('//', '/');
  167 +
  168 + return PathDecoded(RegExp('^$stringPath\$'), keys);
  169 + }
  170 +}
  171 +
  172 +@immutable
  173 +class PathDecoded {
  174 + final RegExp regex;
  175 + final List<String?> keys;
  176 + const PathDecoded(this.regex, this.keys);
  177 +
  178 + @override
  179 + int get hashCode => regex.hashCode;
  180 +
  181 + @override
  182 + bool operator ==(Object other) {
  183 + if (identical(this, other)) return true;
  184 +
  185 + return other is PathDecoded &&
  186 + other.regex == regex; // && listEquals(other.keys, keys);
  187 + }
191 } 188 }
@@ -5,111 +5,247 @@ import 'package:flutter/cupertino.dart'; @@ -5,111 +5,247 @@ import 'package:flutter/cupertino.dart';
5 import 'package:flutter/foundation.dart'; 5 import 'package:flutter/foundation.dart';
6 import 'package:flutter/gestures.dart'; 6 import 'package:flutter/gestures.dart';
7 import 'package:flutter/material.dart'; 7 import 'package:flutter/material.dart';
8 -import '../../../get.dart';  
9 8
  9 +import '../../../get.dart';
10 import 'default_transitions.dart'; 10 import 'default_transitions.dart';
11 import 'transitions_type.dart'; 11 import 'transitions_type.dart';
12 12
13 const double _kBackGestureWidth = 20.0; 13 const double _kBackGestureWidth = 20.0;
14 -const double _kMinFlingVelocity = 1.0; // Screen widths per second. 14 +const int _kMaxDroppedSwipePageForwardAnimationTime =
  15 + 800; // Screen widths per second.
15 16
16 // An eyeballed value for the maximum time it takes 17 // An eyeballed value for the maximum time it takes
17 //for a page to animate forward 18 //for a page to animate forward
18 // if the user releases a page mid swipe. 19 // if the user releases a page mid swipe.
19 -const int _kMaxDroppedSwipePageForwardAnimationTime = 800; // Milliseconds. 20 +const int _kMaxPageBackAnimationTime = 300; // Milliseconds.
20 21
21 // The maximum time for a page to get reset to it's original position if the 22 // The maximum time for a page to get reset to it's original position if the
22 // user releases a page mid swipe. 23 // user releases a page mid swipe.
23 -const int _kMaxPageBackAnimationTime = 300; // Milliseconds. 24 +const double _kMinFlingVelocity = 1.0; // Milliseconds.
24 25
25 -mixin GetPageRouteTransitionMixin<T> on PageRoute<T> {  
26 - /// Builds the primary contents of the route.  
27 - @protected  
28 - Widget buildContent(BuildContext context); 26 +class CupertinoBackGestureController<T> {
  27 + final AnimationController controller;
29 28
30 - /// {@template flutter.cupertino.CupertinoRouteTransitionMixin.title}  
31 - /// A title string for this route. 29 + final NavigatorState navigator;
  30 +
  31 + /// Creates a controller for an iOS-style back gesture.
32 /// 32 ///
33 - /// Used to auto-populate [CupertinoNavigationBar] and  
34 - /// [CupertinoSliverNavigationBar]'s `middle`/`largeTitle` widgets when  
35 - /// one is not manually supplied.  
36 - /// {@endtemplate}  
37 - String? get title; 33 + /// The [navigator] and [controller] arguments must not be null.
  34 + CupertinoBackGestureController({
  35 + required this.navigator,
  36 + required this.controller,
  37 + }) {
  38 + navigator.didStartUserGesture();
  39 + }
38 40
39 - double Function(BuildContext context)? get gestureWidth; 41 + /// The drag gesture has ended with a horizontal motion of
  42 + /// [fractionalVelocity] as a fraction of screen width per second.
  43 + void dragEnd(double velocity) {
  44 + // Fling in the appropriate direction.
  45 + // AnimationController.fling is guaranteed to
  46 + // take at least one frame.
  47 + //
  48 + // This curve has been determined through rigorously eyeballing native iOS
  49 + // animations.
  50 + const Curve animationCurve = Curves.fastLinearToSlowEaseIn;
  51 + final bool animateForward;
40 52
41 - ValueNotifier<String?>? _previousTitle; 53 + // If the user releases the page before mid screen with sufficient velocity,
  54 + // or after mid screen, we should animate the page out. Otherwise, the page
  55 + // should be animated back in.
  56 + if (velocity.abs() >= _kMinFlingVelocity) {
  57 + animateForward = velocity <= 0;
  58 + } else {
  59 + animateForward = controller.value > 0.5;
  60 + }
42 61
43 - /// The title string of the previous [CupertinoPageRoute].  
44 - ///  
45 - /// The [ValueListenable]'s value is readable after the route is installed  
46 - /// onto a [Navigator]. The [ValueListenable] will also notify its listeners  
47 - /// if the value changes (such as by replacing the previous route).  
48 - ///  
49 - /// The [ValueListenable] itself will be null before the route is installed.  
50 - /// Its content value will be null if the previous route has no title or  
51 - /// is not a [CupertinoPageRoute].  
52 - ///  
53 - /// See also:  
54 - ///  
55 - /// * [ValueListenableBuilder], which can be used to listen and rebuild  
56 - /// widgets based on a ValueListenable.  
57 - ValueListenable<String?> get previousTitle {  
58 - assert(  
59 - _previousTitle != null,  
60 - '''  
61 -Cannot read the previousTitle for a route that has not yet been installed''',  
62 - );  
63 - return _previousTitle!;  
64 - } 62 + if (animateForward) {
  63 + // The closer the panel is to dismissing, the shorter the animation is.
  64 + // We want to cap the animation time, but we want to use a linear curve
  65 + // to determine it.
  66 + final droppedPageForwardAnimationTime = min(
  67 + lerpDouble(
  68 + _kMaxDroppedSwipePageForwardAnimationTime, 0, controller.value)!
  69 + .floor(),
  70 + _kMaxPageBackAnimationTime,
  71 + );
  72 + controller.animateTo(1.0,
  73 + duration: Duration(milliseconds: droppedPageForwardAnimationTime),
  74 + curve: animationCurve);
  75 + } else {
  76 + // This route is destined to pop at this point. Reuse navigator's pop.
  77 + navigator.pop();
65 78
66 - @override  
67 - void didChangePrevious(Route<dynamic>? previousRoute) {  
68 - final previousTitleString = previousRoute is CupertinoRouteTransitionMixin  
69 - ? previousRoute.title  
70 - : null;  
71 - if (_previousTitle == null) {  
72 - _previousTitle = ValueNotifier<String?>(previousTitleString); 79 + // The popping may have finished inline if already at the
  80 + // target destination.
  81 + if (controller.isAnimating) {
  82 + // Otherwise, use a custom popping animation duration and curve.
  83 + final droppedPageBackAnimationTime = lerpDouble(
  84 + 0, _kMaxDroppedSwipePageForwardAnimationTime, controller.value)!
  85 + .floor();
  86 + controller.animateBack(0.0,
  87 + duration: Duration(milliseconds: droppedPageBackAnimationTime),
  88 + curve: animationCurve);
  89 + }
  90 + }
  91 +
  92 + if (controller.isAnimating) {
  93 + // Keep the userGestureInProgress in true state so we don't change the
  94 + // curve of the page transition mid-flight since CupertinoPageTransition
  95 + // depends on userGestureInProgress.
  96 + late AnimationStatusListener animationStatusCallback;
  97 + animationStatusCallback = (status) {
  98 + navigator.didStopUserGesture();
  99 + controller.removeStatusListener(animationStatusCallback);
  100 + };
  101 + controller.addStatusListener(animationStatusCallback);
73 } else { 102 } else {
74 - _previousTitle!.value = previousTitleString; 103 + navigator.didStopUserGesture();
75 } 104 }
76 - super.didChangePrevious(previousRoute);  
77 } 105 }
78 106
79 - @override  
80 - // A relatively rigorous eyeball estimation.  
81 - Duration get transitionDuration => const Duration(milliseconds: 400); 107 + /// The drag gesture has changed by [fractionalDelta]. The total range of the
  108 + /// drag should be 0.0 to 1.0.
  109 + void dragUpdate(double delta) {
  110 + controller.value -= delta;
  111 + }
  112 +}
  113 +
  114 +class CupertinoBackGestureDetector<T> extends StatefulWidget {
  115 + final Widget child;
  116 +
  117 + final double gestureWidth;
  118 + final ValueGetter<bool> enabledCallback;
  119 +
  120 + final ValueGetter<CupertinoBackGestureController<T>> onStartPopGesture;
  121 +
  122 + const CupertinoBackGestureDetector({
  123 + Key? key,
  124 + required this.enabledCallback,
  125 + required this.onStartPopGesture,
  126 + required this.child,
  127 + required this.gestureWidth,
  128 + }) : super(key: key);
82 129
83 @override 130 @override
84 - Color? get barrierColor => null; 131 + CupertinoBackGestureDetectorState<T> createState() =>
  132 + CupertinoBackGestureDetectorState<T>();
  133 +}
  134 +
  135 +class CupertinoBackGestureDetectorState<T>
  136 + extends State<CupertinoBackGestureDetector<T>> {
  137 + CupertinoBackGestureController<T>? _backGestureController;
  138 +
  139 + late HorizontalDragGestureRecognizer _recognizer;
85 140
86 @override 141 @override
87 - String? get barrierLabel => null; 142 + Widget build(BuildContext context) {
  143 + assert(debugCheckHasDirectionality(context));
  144 + // For devices with notches, the drag area needs to be larger on the side
  145 + // that has the notch.
  146 + var dragAreaWidth = Directionality.of(context) == TextDirection.ltr
  147 + ? MediaQuery.of(context).padding.left
  148 + : MediaQuery.of(context).padding.right;
  149 + dragAreaWidth = max(dragAreaWidth, widget.gestureWidth);
  150 + return Stack(
  151 + fit: StackFit.passthrough,
  152 + children: <Widget>[
  153 + widget.child,
  154 + PositionedDirectional(
  155 + start: 0.0,
  156 + width: dragAreaWidth,
  157 + top: 0.0,
  158 + bottom: 0.0,
  159 + child: Listener(
  160 + onPointerDown: _handlePointerDown,
  161 + behavior: HitTestBehavior.translucent,
  162 + ),
  163 + ),
  164 + ],
  165 + );
  166 + }
88 167
89 - bool get showCupertinoParallax; 168 + @override
  169 + void dispose() {
  170 + _recognizer.dispose();
  171 + super.dispose();
  172 + }
90 173
91 @override 174 @override
92 - bool canTransitionTo(TransitionRoute<dynamic> nextRoute) {  
93 - // Don't perform outgoing animation if the next route is a  
94 - // fullscreen dialog. 175 + void initState() {
  176 + super.initState();
  177 + _recognizer = HorizontalDragGestureRecognizer(debugOwner: this)
  178 + ..onStart = _handleDragStart
  179 + ..onUpdate = _handleDragUpdate
  180 + ..onEnd = _handleDragEnd
  181 + ..onCancel = _handleDragCancel;
  182 + }
95 183
96 - return nextRoute is GetPageRouteTransitionMixin &&  
97 - !nextRoute.fullscreenDialog &&  
98 - nextRoute.showCupertinoParallax; 184 + double _convertToLogical(double value) {
  185 + switch (Directionality.of(context)) {
  186 + case TextDirection.rtl:
  187 + return -value;
  188 + case TextDirection.ltr:
  189 + return value;
  190 + }
99 } 191 }
100 192
101 - /// True if an iOS-style back swipe pop gesture is currently  
102 - /// underway for [route]. 193 + void _handleDragCancel() {
  194 + assert(mounted);
  195 + // This can be called even if start is not called, paired with
  196 + // the "down" event
  197 + // that we don't consider here.
  198 + _backGestureController?.dragEnd(0.0);
  199 + _backGestureController = null;
  200 + }
  201 +
  202 + void _handleDragEnd(DragEndDetails details) {
  203 + assert(mounted);
  204 + assert(_backGestureController != null);
  205 + _backGestureController!.dragEnd(_convertToLogical(
  206 + details.velocity.pixelsPerSecond.dx / context.size!.width));
  207 + _backGestureController = null;
  208 + }
  209 +
  210 + void _handleDragStart(DragStartDetails details) {
  211 + assert(mounted);
  212 + assert(_backGestureController == null);
  213 + _backGestureController = widget.onStartPopGesture();
  214 + }
  215 +
  216 + void _handleDragUpdate(DragUpdateDetails details) {
  217 + assert(mounted);
  218 + assert(_backGestureController != null);
  219 + _backGestureController!.dragUpdate(
  220 + _convertToLogical(details.primaryDelta! / context.size!.width));
  221 + }
  222 +
  223 + void _handlePointerDown(PointerDownEvent event) {
  224 + if (widget.enabledCallback()) _recognizer.addPointer(event);
  225 + }
  226 +}
  227 +
  228 +mixin GetPageRouteTransitionMixin<T> on PageRoute<T> {
  229 + ValueNotifier<String?>? _previousTitle;
  230 +
  231 + @override
  232 + Color? get barrierColor => null;
  233 +
  234 + @override
  235 + String? get barrierLabel => null;
  236 +
  237 + double Function(BuildContext context)? get gestureWidth;
  238 +
  239 + /// Whether a pop gesture can be started by the user.
103 /// 240 ///
104 - /// This just check the route's [NavigatorState.userGestureInProgress]. 241 + /// Returns true if the user can edge-swipe to a previous route.
105 /// 242 ///
106 - /// See also: 243 + /// Returns false once [isPopGestureInProgress] is true, but
  244 + /// [isPopGestureInProgress] can only become true if [popGestureEnabled] was
  245 + /// true first.
107 /// 246 ///
108 - /// * [popGestureEnabled], which returns true if a user-triggered pop gesture  
109 - /// would be allowed.  
110 - static bool isPopGestureInProgress(PageRoute<dynamic> route) {  
111 - return route.navigator!.userGestureInProgress;  
112 - } 247 + /// This should only be used between frames, not during build.
  248 + bool get popGestureEnabled => _isPopGestureEnabled(this);
113 249
114 /// True if an iOS-style back swipe pop gesture is currently 250 /// True if an iOS-style back swipe pop gesture is currently
115 /// underway for this route. 251 /// underway for this route.
@@ -122,44 +258,47 @@ Cannot read the previousTitle for a route that has not yet been installed''', @@ -122,44 +258,47 @@ Cannot read the previousTitle for a route that has not yet been installed''',
122 /// would be allowed. 258 /// would be allowed.
123 bool get popGestureInProgress => isPopGestureInProgress(this); 259 bool get popGestureInProgress => isPopGestureInProgress(this);
124 260
125 - /// Whether a pop gesture can be started by the user. 261 + /// The title string of the previous [CupertinoPageRoute].
126 /// 262 ///
127 - /// Returns true if the user can edge-swipe to a previous route. 263 + /// The [ValueListenable]'s value is readable after the route is installed
  264 + /// onto a [Navigator]. The [ValueListenable] will also notify its listeners
  265 + /// if the value changes (such as by replacing the previous route).
128 /// 266 ///
129 - /// Returns false once [isPopGestureInProgress] is true, but  
130 - /// [isPopGestureInProgress] can only become true if [popGestureEnabled] was  
131 - /// true first. 267 + /// The [ValueListenable] itself will be null before the route is installed.
  268 + /// Its content value will be null if the previous route has no title or
  269 + /// is not a [CupertinoPageRoute].
132 /// 270 ///
133 - /// This should only be used between frames, not during build.  
134 - bool get popGestureEnabled => _isPopGestureEnabled(this); 271 + /// See also:
  272 + ///
  273 + /// * [ValueListenableBuilder], which can be used to listen and rebuild
  274 + /// widgets based on a ValueListenable.
  275 + ValueListenable<String?> get previousTitle {
  276 + assert(
  277 + _previousTitle != null,
  278 + '''
  279 +Cannot read the previousTitle for a route that has not yet been installed''',
  280 + );
  281 + return _previousTitle!;
  282 + }
135 283
136 - static bool _isPopGestureEnabled<T>(PageRoute<T> route) {  
137 - // If there's nothing to go back to, then obviously we don't support  
138 - // the back gesture.  
139 - if (route.isFirst) return false;  
140 - // If the route wouldn't actually pop if we popped it, then the gesture  
141 - // would be really confusing (or would skip internal routes),  
142 - //so disallow it.  
143 - if (route.willHandlePopInternally) return false;  
144 - // If attempts to dismiss this route might be vetoed such as in a page  
145 - // with forms, then do not allow the user to dismiss the route with a swipe.  
146 - if (route.hasScopedWillPopCallback) return false;  
147 - // Fullscreen dialogs aren't dismissible by back swipe.  
148 - if (route.fullscreenDialog) return false;  
149 - // If we're in an animation already, we cannot be manually swiped.  
150 - if (route.animation!.status != AnimationStatus.completed) return false;  
151 - // If we're being popped into, we also cannot be swiped until the pop above  
152 - // it completes. This translates to our secondary animation being  
153 - // dismissed.  
154 - if (route.secondaryAnimation!.status != AnimationStatus.dismissed) {  
155 - return false;  
156 - }  
157 - // If we're in a gesture already, we cannot start another.  
158 - if (isPopGestureInProgress(route)) return false; 284 + bool get showCupertinoParallax;
159 285
160 - // Looks like a back gesture would be welcome!  
161 - return true;  
162 - } 286 + /// {@template flutter.cupertino.CupertinoRouteTransitionMixin.title}
  287 + /// A title string for this route.
  288 + ///
  289 + /// Used to auto-populate [CupertinoNavigationBar] and
  290 + /// [CupertinoSliverNavigationBar]'s `middle`/`largeTitle` widgets when
  291 + /// one is not manually supplied.
  292 + /// {@endtemplate}
  293 + String? get title;
  294 +
  295 + @override
  296 + // A relatively rigorous eyeball estimation.
  297 + Duration get transitionDuration => const Duration(milliseconds: 400);
  298 +
  299 + /// Builds the primary contents of the route.
  300 + @protected
  301 + Widget buildContent(BuildContext context);
163 302
164 @override 303 @override
165 Widget buildPage(BuildContext context, Animation<double> animation, 304 Widget buildPage(BuildContext context, Animation<double> animation,
@@ -173,17 +312,36 @@ Cannot read the previousTitle for a route that has not yet been installed''', @@ -173,17 +312,36 @@ Cannot read the previousTitle for a route that has not yet been installed''',
173 return result; 312 return result;
174 } 313 }
175 314
176 - // Called by CupertinoBackGestureDetector when a pop ("back") drag start  
177 - // gesture is detected. The returned controller handles all of the subsequent  
178 - // drag events.  
179 - static CupertinoBackGestureController<T> _startPopGesture<T>(  
180 - PageRoute<T> route) {  
181 - assert(_isPopGestureEnabled(route)); 315 + @override
  316 + Widget buildTransitions(BuildContext context, Animation<double> animation,
  317 + Animation<double> secondaryAnimation, Widget child) {
  318 + return buildPageTransitions<T>(
  319 + this, context, animation, secondaryAnimation, child);
  320 + }
182 321
183 - return CupertinoBackGestureController<T>(  
184 - navigator: route.navigator!,  
185 - controller: route.controller!, // protected access  
186 - ); 322 + @override
  323 + bool canTransitionTo(TransitionRoute<dynamic> nextRoute) {
  324 + // Don't perform outgoing animation if the next route is a
  325 + // fullscreen dialog.
  326 +
  327 + return (nextRoute is GetPageRouteTransitionMixin &&
  328 + !nextRoute.fullscreenDialog &&
  329 + nextRoute.showCupertinoParallax) ||
  330 + (nextRoute is CupertinoRouteTransitionMixin &&
  331 + !nextRoute.fullscreenDialog);
  332 + }
  333 +
  334 + @override
  335 + void didChangePrevious(Route<dynamic>? previousRoute) {
  336 + final previousTitleString = previousRoute is CupertinoRouteTransitionMixin
  337 + ? previousRoute.title
  338 + : null;
  339 + if (_previousTitle == null) {
  340 + _previousTitle = ValueNotifier<String?>(previousTitleString);
  341 + } else {
  342 + _previousTitle!.value = previousTitleString;
  343 + }
  344 + super.didChangePrevious(previousRoute);
187 } 345 }
188 346
189 /// Returns a [CupertinoFullscreenDialogTransition] if [route] is a full 347 /// Returns a [CupertinoFullscreenDialogTransition] if [route] is a full
@@ -485,211 +643,57 @@ Cannot read the previousTitle for a route that has not yet been installed''', @@ -485,211 +643,57 @@ Cannot read the previousTitle for a route that has not yet been installed''',
485 } 643 }
486 } 644 }
487 645
488 - @override  
489 - Widget buildTransitions(BuildContext context, Animation<double> animation,  
490 - Animation<double> secondaryAnimation, Widget child) {  
491 - return buildPageTransitions<T>(  
492 - this, context, animation, secondaryAnimation, child);  
493 - }  
494 -}  
495 -  
496 -class CupertinoBackGestureDetector<T> extends StatefulWidget {  
497 - const CupertinoBackGestureDetector({  
498 - Key? key,  
499 - required this.enabledCallback,  
500 - required this.onStartPopGesture,  
501 - required this.child,  
502 - required this.gestureWidth,  
503 - }) : super(key: key);  
504 -  
505 - final Widget child;  
506 - final double gestureWidth;  
507 -  
508 - final ValueGetter<bool> enabledCallback;  
509 -  
510 - final ValueGetter<CupertinoBackGestureController<T>> onStartPopGesture;  
511 -  
512 - @override  
513 - CupertinoBackGestureDetectorState<T> createState() =>  
514 - CupertinoBackGestureDetectorState<T>();  
515 -}  
516 -  
517 -class CupertinoBackGestureDetectorState<T>  
518 - extends State<CupertinoBackGestureDetector<T>> {  
519 - CupertinoBackGestureController<T>? _backGestureController;  
520 -  
521 - late HorizontalDragGestureRecognizer _recognizer;  
522 -  
523 - @override  
524 - void initState() {  
525 - super.initState();  
526 - _recognizer = HorizontalDragGestureRecognizer(debugOwner: this)  
527 - ..onStart = _handleDragStart  
528 - ..onUpdate = _handleDragUpdate  
529 - ..onEnd = _handleDragEnd  
530 - ..onCancel = _handleDragCancel;  
531 - }  
532 -  
533 - @override  
534 - void dispose() {  
535 - _recognizer.dispose();  
536 - super.dispose();  
537 - }  
538 -  
539 - void _handleDragStart(DragStartDetails details) {  
540 - assert(mounted);  
541 - assert(_backGestureController == null);  
542 - _backGestureController = widget.onStartPopGesture();  
543 - }  
544 -  
545 - void _handleDragUpdate(DragUpdateDetails details) {  
546 - assert(mounted);  
547 - assert(_backGestureController != null);  
548 - _backGestureController!.dragUpdate(  
549 - _convertToLogical(details.primaryDelta! / context.size!.width));  
550 - }  
551 -  
552 - void _handleDragEnd(DragEndDetails details) {  
553 - assert(mounted);  
554 - assert(_backGestureController != null);  
555 - _backGestureController!.dragEnd(_convertToLogical(  
556 - details.velocity.pixelsPerSecond.dx / context.size!.width));  
557 - _backGestureController = null;  
558 - }  
559 -  
560 - void _handleDragCancel() {  
561 - assert(mounted);  
562 - // This can be called even if start is not called, paired with  
563 - // the "down" event  
564 - // that we don't consider here.  
565 - _backGestureController?.dragEnd(0.0);  
566 - _backGestureController = null;  
567 - }  
568 -  
569 - void _handlePointerDown(PointerDownEvent event) {  
570 - if (widget.enabledCallback()) _recognizer.addPointer(event);  
571 - }  
572 -  
573 - double _convertToLogical(double value) {  
574 - switch (Directionality.of(context)) {  
575 - case TextDirection.rtl:  
576 - return -value;  
577 - case TextDirection.ltr:  
578 - return value;  
579 - }  
580 - }  
581 -  
582 - @override  
583 - Widget build(BuildContext context) {  
584 - assert(debugCheckHasDirectionality(context));  
585 - // For devices with notches, the drag area needs to be larger on the side  
586 - // that has the notch.  
587 - var dragAreaWidth = Directionality.of(context) == TextDirection.ltr  
588 - ? MediaQuery.of(context).padding.left  
589 - : MediaQuery.of(context).padding.right;  
590 - dragAreaWidth = max(dragAreaWidth, widget.gestureWidth);  
591 - return Stack(  
592 - fit: StackFit.passthrough,  
593 - children: <Widget>[  
594 - widget.child,  
595 - PositionedDirectional(  
596 - start: 0.0,  
597 - width: dragAreaWidth,  
598 - top: 0.0,  
599 - bottom: 0.0,  
600 - child: Listener(  
601 - onPointerDown: _handlePointerDown,  
602 - behavior: HitTestBehavior.translucent,  
603 - ),  
604 - ),  
605 - ],  
606 - );  
607 - }  
608 -}  
609 -  
610 -class CupertinoBackGestureController<T> {  
611 - /// Creates a controller for an iOS-style back gesture. 646 + // Called by CupertinoBackGestureDetector when a pop ("back") drag start
  647 + // gesture is detected. The returned controller handles all of the subsequent
  648 + // drag events.
  649 + /// True if an iOS-style back swipe pop gesture is currently
  650 + /// underway for [route].
612 /// 651 ///
613 - /// The [navigator] and [controller] arguments must not be null.  
614 - CupertinoBackGestureController({  
615 - required this.navigator,  
616 - required this.controller,  
617 - }) {  
618 - navigator.didStartUserGesture();  
619 - }  
620 -  
621 - final AnimationController controller;  
622 - final NavigatorState navigator;  
623 -  
624 - /// The drag gesture has changed by [fractionalDelta]. The total range of the  
625 - /// drag should be 0.0 to 1.0.  
626 - void dragUpdate(double delta) {  
627 - controller.value -= delta; 652 + /// This just check the route's [NavigatorState.userGestureInProgress].
  653 + ///
  654 + /// See also:
  655 + ///
  656 + /// * [popGestureEnabled], which returns true if a user-triggered pop gesture
  657 + /// would be allowed.
  658 + static bool isPopGestureInProgress(PageRoute<dynamic> route) {
  659 + return route.navigator!.userGestureInProgress;
628 } 660 }
629 661
630 - /// The drag gesture has ended with a horizontal motion of  
631 - /// [fractionalVelocity] as a fraction of screen width per second.  
632 - void dragEnd(double velocity) {  
633 - // Fling in the appropriate direction.  
634 - // AnimationController.fling is guaranteed to  
635 - // take at least one frame.  
636 - //  
637 - // This curve has been determined through rigorously eyeballing native iOS  
638 - // animations.  
639 - const Curve animationCurve = Curves.fastLinearToSlowEaseIn;  
640 - final bool animateForward;  
641 -  
642 - // If the user releases the page before mid screen with sufficient velocity,  
643 - // or after mid screen, we should animate the page out. Otherwise, the page  
644 - // should be animated back in.  
645 - if (velocity.abs() >= _kMinFlingVelocity) {  
646 - animateForward = velocity <= 0;  
647 - } else {  
648 - animateForward = controller.value > 0.5; 662 + static bool _isPopGestureEnabled<T>(PageRoute<T> route) {
  663 + // If there's nothing to go back to, then obviously we don't support
  664 + // the back gesture.
  665 + if (route.isFirst) return false;
  666 + // If the route wouldn't actually pop if we popped it, then the gesture
  667 + // would be really confusing (or would skip internal routes),
  668 + //so disallow it.
  669 + if (route.willHandlePopInternally) return false;
  670 + // If attempts to dismiss this route might be vetoed such as in a page
  671 + // with forms, then do not allow the user to dismiss the route with a swipe.
  672 + if (route.hasScopedWillPopCallback) return false;
  673 + // Fullscreen dialogs aren't dismissible by back swipe.
  674 + if (route.fullscreenDialog) return false;
  675 + // If we're in an animation already, we cannot be manually swiped.
  676 + if (route.animation!.status != AnimationStatus.completed) return false;
  677 + // If we're being popped into, we also cannot be swiped until the pop above
  678 + // it completes. This translates to our secondary animation being
  679 + // dismissed.
  680 + if (route.secondaryAnimation!.status != AnimationStatus.dismissed) {
  681 + return false;
649 } 682 }
  683 + // If we're in a gesture already, we cannot start another.
  684 + if (isPopGestureInProgress(route)) return false;
650 685
651 - if (animateForward) {  
652 - // The closer the panel is to dismissing, the shorter the animation is.  
653 - // We want to cap the animation time, but we want to use a linear curve  
654 - // to determine it.  
655 - final droppedPageForwardAnimationTime = min(  
656 - lerpDouble(  
657 - _kMaxDroppedSwipePageForwardAnimationTime, 0, controller.value)!  
658 - .floor(),  
659 - _kMaxPageBackAnimationTime,  
660 - );  
661 - controller.animateTo(1.0,  
662 - duration: Duration(milliseconds: droppedPageForwardAnimationTime),  
663 - curve: animationCurve);  
664 - } else {  
665 - // This route is destined to pop at this point. Reuse navigator's pop.  
666 - navigator.pop(); 686 + // Looks like a back gesture would be welcome!
  687 + return true;
  688 + }
667 689
668 - // The popping may have finished inline if already at the  
669 - // target destination.  
670 - if (controller.isAnimating) {  
671 - // Otherwise, use a custom popping animation duration and curve.  
672 - final droppedPageBackAnimationTime = lerpDouble(  
673 - 0, _kMaxDroppedSwipePageForwardAnimationTime, controller.value)!  
674 - .floor();  
675 - controller.animateBack(0.0,  
676 - duration: Duration(milliseconds: droppedPageBackAnimationTime),  
677 - curve: animationCurve);  
678 - }  
679 - } 690 + static CupertinoBackGestureController<T> _startPopGesture<T>(
  691 + PageRoute<T> route) {
  692 + assert(_isPopGestureEnabled(route));
680 693
681 - if (controller.isAnimating) {  
682 - // Keep the userGestureInProgress in true state so we don't change the  
683 - // curve of the page transition mid-flight since CupertinoPageTransition  
684 - // depends on userGestureInProgress.  
685 - late AnimationStatusListener animationStatusCallback;  
686 - animationStatusCallback = (status) {  
687 - navigator.didStopUserGesture();  
688 - controller.removeStatusListener(animationStatusCallback);  
689 - };  
690 - controller.addStatusListener(animationStatusCallback);  
691 - } else {  
692 - navigator.didStopUserGesture();  
693 - } 694 + return CupertinoBackGestureController<T>(
  695 + navigator: route.navigator!,
  696 + controller: route.controller!, // protected access
  697 + );
694 } 698 }
695 } 699 }
@@ -5,37 +5,8 @@ import '../../../../instance_manager.dart'; @@ -5,37 +5,8 @@ import '../../../../instance_manager.dart';
5 import '../../../get_navigation.dart'; 5 import '../../../get_navigation.dart';
6 import '../../dialog/dialog_route.dart'; 6 import '../../dialog/dialog_route.dart';
7 import '../../router_report.dart'; 7 import '../../router_report.dart';
8 -import '../../snackbar/snack_route.dart';  
9 import '../default_route.dart'; 8 import '../default_route.dart';
10 9
11 -class Routing {  
12 - String current;  
13 - String previous;  
14 - dynamic args;  
15 - String removed;  
16 - Route<dynamic>? route;  
17 - bool? isBack;  
18 - bool? isSnackbar;  
19 - bool? isBottomSheet;  
20 - bool? isDialog;  
21 -  
22 - Routing({  
23 - this.current = '',  
24 - this.previous = '',  
25 - this.args,  
26 - this.removed = '',  
27 - this.route,  
28 - this.isBack,  
29 - this.isSnackbar,  
30 - this.isBottomSheet,  
31 - this.isDialog,  
32 - });  
33 -  
34 - void update(void fn(Routing value)) {  
35 - fn(this);  
36 - }  
37 -}  
38 -  
39 /// Extracts the name of a route based on it's instance type 10 /// Extracts the name of a route based on it's instance type
40 /// or null if not possible. 11 /// or null if not possible.
41 String? _extractRouteName(Route? route) { 12 String? _extractRouteName(Route? route) {
@@ -58,49 +29,70 @@ String? _extractRouteName(Route? route) { @@ -58,49 +29,70 @@ String? _extractRouteName(Route? route) {
58 return null; 29 return null;
59 } 30 }
60 31
61 -/// This is basically a util for rules about 'what a route is'  
62 -class _RouteData {  
63 - final bool isGetPageRoute;  
64 - final bool isSnackbar;  
65 - final bool isBottomSheet;  
66 - final bool isDialog;  
67 - final String? name;  
68 -  
69 - _RouteData({  
70 - required this.name,  
71 - required this.isGetPageRoute,  
72 - required this.isSnackbar,  
73 - required this.isBottomSheet,  
74 - required this.isDialog,  
75 - });  
76 -  
77 - factory _RouteData.ofRoute(Route? route) {  
78 - return _RouteData(  
79 - name: _extractRouteName(route),  
80 - isGetPageRoute: route is GetPageRoute,  
81 - isSnackbar: route is SnackRoute,  
82 - isDialog: route is GetDialogRoute,  
83 - isBottomSheet: route is GetModalBottomSheetRoute,  
84 - );  
85 - }  
86 -}  
87 -  
88 class GetObserver extends NavigatorObserver { 32 class GetObserver extends NavigatorObserver {
89 final Function(Routing?)? routing; 33 final Function(Routing?)? routing;
90 34
  35 + final Routing? _routeSend;
  36 +
91 GetObserver([this.routing, this._routeSend]); 37 GetObserver([this.routing, this._routeSend]);
92 38
93 - final Routing? _routeSend; 39 + @override
  40 + void didPop(Route route, Route? previousRoute) {
  41 + super.didPop(route, previousRoute);
  42 + final currentRoute = _RouteData.ofRoute(route);
  43 + final newRoute = _RouteData.ofRoute(previousRoute);
  44 +
  45 + // if (currentRoute.isSnackbar) {
  46 + // // Get.log("CLOSE SNACKBAR ${currentRoute.name}");
  47 + // Get.log("CLOSE SNACKBAR");
  48 + // } else
  49 +
  50 + if (currentRoute.isBottomSheet || currentRoute.isDialog) {
  51 + Get.log("CLOSE ${currentRoute.name}");
  52 + } else if (currentRoute.isGetPageRoute) {
  53 + Get.log("CLOSE TO ROUTE ${currentRoute.name}");
  54 + }
  55 + if (previousRoute != null) {
  56 + RouterReportManager.reportCurrentRoute(previousRoute);
  57 + }
  58 +
  59 + // Here we use a 'inverse didPush set', meaning that we use
  60 + // previous route instead of 'route' because this is
  61 + // a 'inverse push'
  62 + _routeSend?.update((value) {
  63 + // Only PageRoute is allowed to change current value
  64 + if (previousRoute is PageRoute) {
  65 + value.current = _extractRouteName(previousRoute) ?? '';
  66 + value.previous = newRoute.name ?? '';
  67 + } else if (value.previous.isNotEmpty) {
  68 + value.current = value.previous;
  69 + }
  70 +
  71 + value.args = previousRoute?.settings.arguments;
  72 + value.route = previousRoute;
  73 + value.isBack = true;
  74 + value.removed = '';
  75 + // value.isSnackbar = newRoute.isSnackbar;
  76 + value.isBottomSheet = newRoute.isBottomSheet;
  77 + value.isDialog = newRoute.isDialog;
  78 + });
  79 +
  80 + // print('currentRoute.isDialog ${currentRoute.isDialog}');
  81 +
  82 + routing?.call(_routeSend);
  83 + }
94 84
95 @override 85 @override
96 void didPush(Route route, Route? previousRoute) { 86 void didPush(Route route, Route? previousRoute) {
97 super.didPush(route, previousRoute); 87 super.didPush(route, previousRoute);
98 final newRoute = _RouteData.ofRoute(route); 88 final newRoute = _RouteData.ofRoute(route);
99 89
100 - if (newRoute.isSnackbar) {  
101 - // Get.log("OPEN SNACKBAR ${newRoute.name}");  
102 - Get.log("OPEN SNACKBAR");  
103 - } else if (newRoute.isBottomSheet || newRoute.isDialog) { 90 + // if (newRoute.isSnackbar) {
  91 + // // Get.log("OPEN SNACKBAR ${newRoute.name}");
  92 + // Get.log("OPEN SNACKBAR");
  93 + // } else
  94 +
  95 + if (newRoute.isBottomSheet || newRoute.isDialog) {
104 Get.log("OPEN ${newRoute.name}"); 96 Get.log("OPEN ${newRoute.name}");
105 } else if (newRoute.isGetPageRoute) { 97 } else if (newRoute.isGetPageRoute) {
106 Get.log("GOING TO ROUTE ${newRoute.name}"); 98 Get.log("GOING TO ROUTE ${newRoute.name}");
@@ -121,7 +113,6 @@ class GetObserver extends NavigatorObserver { @@ -121,7 +113,6 @@ class GetObserver extends NavigatorObserver {
121 value.route = route; 113 value.route = route;
122 value.isBack = false; 114 value.isBack = false;
123 value.removed = ''; 115 value.removed = '';
124 - value.isSnackbar = newRoute.isSnackbar ? true : value.isSnackbar ?? false;  
125 value.isBottomSheet = 116 value.isBottomSheet =
126 newRoute.isBottomSheet ? true : value.isBottomSheet ?? false; 117 newRoute.isBottomSheet ? true : value.isBottomSheet ?? false;
127 value.isDialog = newRoute.isDialog ? true : value.isDialog ?? false; 118 value.isDialog = newRoute.isDialog ? true : value.isDialog ?? false;
@@ -133,46 +124,27 @@ class GetObserver extends NavigatorObserver { @@ -133,46 +124,27 @@ class GetObserver extends NavigatorObserver {
133 } 124 }
134 125
135 @override 126 @override
136 - void didPop(Route route, Route? previousRoute) {  
137 - super.didPop(route, previousRoute); 127 + void didRemove(Route route, Route? previousRoute) {
  128 + super.didRemove(route, previousRoute);
  129 + final routeName = _extractRouteName(route);
138 final currentRoute = _RouteData.ofRoute(route); 130 final currentRoute = _RouteData.ofRoute(route);
139 - final newRoute = _RouteData.ofRoute(previousRoute);  
140 131
141 - if (currentRoute.isSnackbar) {  
142 - // Get.log("CLOSE SNACKBAR ${currentRoute.name}");  
143 - Get.log("CLOSE SNACKBAR");  
144 - } else if (currentRoute.isBottomSheet || currentRoute.isDialog) {  
145 - Get.log("CLOSE ${currentRoute.name}");  
146 - } else if (currentRoute.isGetPageRoute) {  
147 - Get.log("CLOSE TO ROUTE ${currentRoute.name}");  
148 - }  
149 - if (previousRoute != null) {  
150 - RouterReportManager.reportCurrentRoute(previousRoute);  
151 - } 132 + Get.log("REMOVING ROUTE $routeName");
152 133
153 - // Here we use a 'inverse didPush set', meaning that we use  
154 - // previous route instead of 'route' because this is  
155 - // a 'inverse push'  
156 _routeSend?.update((value) { 134 _routeSend?.update((value) {
157 - // Only PageRoute is allowed to change current value  
158 - if (previousRoute is PageRoute) {  
159 - value.current = _extractRouteName(previousRoute) ?? '';  
160 - value.previous = newRoute.name ?? '';  
161 - } else if (value.previous.isNotEmpty) {  
162 - value.current = value.previous;  
163 - }  
164 -  
165 - value.args = previousRoute?.settings.arguments;  
166 value.route = previousRoute; 135 value.route = previousRoute;
167 - value.isBack = true;  
168 - value.removed = '';  
169 - value.isSnackbar = newRoute.isSnackbar;  
170 - value.isBottomSheet = newRoute.isBottomSheet;  
171 - value.isDialog = newRoute.isDialog; 136 + value.isBack = false;
  137 + value.removed = routeName ?? '';
  138 + value.previous = routeName ?? '';
  139 + // value.isSnackbar = currentRoute.isSnackbar ? false : value.isSnackbar;
  140 + value.isBottomSheet =
  141 + currentRoute.isBottomSheet ? false : value.isBottomSheet;
  142 + value.isDialog = currentRoute.isDialog ? false : value.isDialog;
172 }); 143 });
173 144
174 - // print('currentRoute.isDialog ${currentRoute.isDialog}');  
175 - 145 + if (route is GetPageRoute) {
  146 + RouterReportManager.reportRouteWillDispose(route);
  147 + }
176 routing?.call(_routeSend); 148 routing?.call(_routeSend);
177 } 149 }
178 150
@@ -201,7 +173,7 @@ class GetObserver extends NavigatorObserver { @@ -201,7 +173,7 @@ class GetObserver extends NavigatorObserver {
201 value.isBack = false; 173 value.isBack = false;
202 value.removed = ''; 174 value.removed = '';
203 value.previous = '$oldName'; 175 value.previous = '$oldName';
204 - value.isSnackbar = currentRoute.isSnackbar ? false : value.isSnackbar; 176 + // value.isSnackbar = currentRoute.isSnackbar ? false : value.isSnackbar;
205 value.isBottomSheet = 177 value.isBottomSheet =
206 currentRoute.isBottomSheet ? false : value.isBottomSheet; 178 currentRoute.isBottomSheet ? false : value.isBottomSheet;
207 value.isDialog = currentRoute.isDialog ? false : value.isDialog; 179 value.isDialog = currentRoute.isDialog ? false : value.isDialog;
@@ -212,29 +184,59 @@ class GetObserver extends NavigatorObserver { @@ -212,29 +184,59 @@ class GetObserver extends NavigatorObserver {
212 184
213 routing?.call(_routeSend); 185 routing?.call(_routeSend);
214 } 186 }
  187 +}
215 188
216 - @override  
217 - void didRemove(Route route, Route? previousRoute) {  
218 - super.didRemove(route, previousRoute);  
219 - final routeName = _extractRouteName(route);  
220 - final currentRoute = _RouteData.ofRoute(route); 189 +class Routing {
  190 + String current;
  191 + String previous;
  192 + dynamic args;
  193 + String removed;
  194 + Route<dynamic>? route;
  195 + bool? isBack;
  196 + // bool? isSnackbar;
  197 + bool? isBottomSheet;
  198 + bool? isDialog;
221 199
222 - Get.log("REMOVING ROUTE $routeName"); 200 + Routing({
  201 + this.current = '',
  202 + this.previous = '',
  203 + this.args,
  204 + this.removed = '',
  205 + this.route,
  206 + this.isBack,
  207 + // this.isSnackbar,
  208 + this.isBottomSheet,
  209 + this.isDialog,
  210 + });
223 211
224 - _routeSend?.update((value) {  
225 - value.route = previousRoute;  
226 - value.isBack = false;  
227 - value.removed = routeName ?? '';  
228 - value.previous = routeName ?? '';  
229 - value.isSnackbar = currentRoute.isSnackbar ? false : value.isSnackbar;  
230 - value.isBottomSheet =  
231 - currentRoute.isBottomSheet ? false : value.isBottomSheet;  
232 - value.isDialog = currentRoute.isDialog ? false : value.isDialog;  
233 - }); 212 + void update(void fn(Routing value)) {
  213 + fn(this);
  214 + }
  215 +}
234 216
235 - if (route is GetPageRoute) {  
236 - RouterReportManager.reportRouteWillDispose(route);  
237 - }  
238 - routing?.call(_routeSend); 217 +/// This is basically a util for rules about 'what a route is'
  218 +class _RouteData {
  219 + final bool isGetPageRoute;
  220 + //final bool isSnackbar;
  221 + final bool isBottomSheet;
  222 + final bool isDialog;
  223 + final String? name;
  224 +
  225 + _RouteData({
  226 + required this.name,
  227 + required this.isGetPageRoute,
  228 + // required this.isSnackbar,
  229 + required this.isBottomSheet,
  230 + required this.isDialog,
  231 + });
  232 +
  233 + factory _RouteData.ofRoute(Route? route) {
  234 + return _RouteData(
  235 + name: _extractRouteName(route),
  236 + isGetPageRoute: route is GetPageRoute,
  237 + // isSnackbar: route is SnackRoute,
  238 + isDialog: route is GetDialogRoute,
  239 + isBottomSheet: route is GetModalBottomSheetRoute,
  240 + );
239 } 241 }
240 } 242 }
1 -import 'dart:async';  
2 -import 'dart:ui';  
3 -import 'package:flutter/widgets.dart';  
4 -import '../../../get_core/get_core.dart';  
5 -import '../../get_navigation.dart';  
6 -import 'snack.dart';  
7 -  
8 -class SnackRoute<T> extends OverlayRoute<T> {  
9 - late Animation<double> _filterBlurAnimation;  
10 - late Animation<Color?> _filterColorAnimation;  
11 -  
12 - SnackRoute({  
13 - required this.snack,  
14 - RouteSettings? settings,  
15 - }) : super(settings: settings) {  
16 - _builder = Builder(builder: (_) {  
17 - return GestureDetector(  
18 - child: snack,  
19 - onTap: snack.onTap != null ? () => snack.onTap!(snack) : null,  
20 - );  
21 - });  
22 -  
23 - _configureAlignment(snack.snackPosition);  
24 - _snackbarStatus = snack.snackbarStatus;  
25 - }  
26 -  
27 - _configureAlignment(SnackPosition snackPosition) {  
28 - switch (snack.snackPosition) {  
29 - case SnackPosition.TOP:  
30 - {  
31 - _initialAlignment = Alignment(-1.0, -2.0);  
32 - _endAlignment = Alignment(-1.0, -1.0);  
33 - break;  
34 - }  
35 - case SnackPosition.BOTTOM:  
36 - {  
37 - _initialAlignment = Alignment(-1.0, 2.0);  
38 - _endAlignment = Alignment(-1.0, 1.0);  
39 - break;  
40 - }  
41 - }  
42 - }  
43 -  
44 - GetBar snack;  
45 - Builder? _builder;  
46 -  
47 - final Completer<T> _transitionCompleter = Completer<T>();  
48 -  
49 - late SnackbarStatusCallback _snackbarStatus;  
50 - Alignment? _initialAlignment;  
51 - Alignment? _endAlignment;  
52 - bool _wasDismissedBySwipe = false;  
53 - bool _onTappedDismiss = false;  
54 -  
55 - Timer? _timer;  
56 -  
57 - bool get opaque => false;  
58 -  
59 - @override  
60 - Iterable<OverlayEntry> createOverlayEntries() {  
61 - return <OverlayEntry>[  
62 - if (snack.overlayBlur > 0.0) ...[  
63 - OverlayEntry(  
64 - builder: (context) {  
65 - return GestureDetector(  
66 - onTap: () {  
67 - if (snack.isDismissible && !_onTappedDismiss) {  
68 - _onTappedDismiss = true;  
69 - Get.back();  
70 - }  
71 - },  
72 - child: AnimatedBuilder(  
73 - animation: _filterBlurAnimation,  
74 - builder: (context, child) {  
75 - return BackdropFilter(  
76 - filter: ImageFilter.blur(  
77 - sigmaX: _filterBlurAnimation.value,  
78 - sigmaY: _filterBlurAnimation.value),  
79 - child: Container(  
80 - constraints: BoxConstraints.expand(),  
81 - color: _filterColorAnimation.value,  
82 - ),  
83 - );  
84 - },  
85 - ),  
86 - );  
87 - },  
88 - maintainState: false,  
89 - opaque: opaque,  
90 - ),  
91 - ],  
92 - OverlayEntry(  
93 - builder: (context) {  
94 - final Widget annotatedChild = Semantics(  
95 - child: AlignTransition(  
96 - alignment: _animation!,  
97 - child: snack.isDismissible  
98 - ? _getDismissibleSnack(_builder)  
99 - : _getSnack(),  
100 - ),  
101 - focused: false,  
102 - container: true,  
103 - explicitChildNodes: true,  
104 - );  
105 - return annotatedChild;  
106 - },  
107 - maintainState: false,  
108 - opaque: opaque,  
109 - ),  
110 - ];  
111 - }  
112 -  
113 - String dismissibleKeyGen = "";  
114 -  
115 - Widget _getDismissibleSnack(Widget? child) {  
116 - return Dismissible(  
117 - direction: _getDismissDirection(),  
118 - resizeDuration: null,  
119 - confirmDismiss: (_) {  
120 - if (currentStatus == SnackbarStatus.OPENING ||  
121 - currentStatus == SnackbarStatus.CLOSING) {  
122 - return Future.value(false);  
123 - }  
124 - return Future.value(true);  
125 - },  
126 - key: Key(dismissibleKeyGen),  
127 - onDismissed: (_) {  
128 - dismissibleKeyGen += "1";  
129 - _cancelTimer();  
130 - _wasDismissedBySwipe = true;  
131 -  
132 - if (isCurrent) {  
133 - navigator!.pop();  
134 - } else {  
135 - navigator!.removeRoute(this);  
136 - }  
137 - },  
138 - child: _getSnack(),  
139 - );  
140 - }  
141 -  
142 - Widget _getSnack() {  
143 - return Container(  
144 - margin: snack.margin,  
145 - child: _builder,  
146 - );  
147 - }  
148 -  
149 - DismissDirection _getDismissDirection() {  
150 - if (snack.dismissDirection == SnackDismissDirection.HORIZONTAL) {  
151 - return DismissDirection.horizontal;  
152 - } else {  
153 - if (snack.snackPosition == SnackPosition.TOP) {  
154 - return DismissDirection.up;  
155 - }  
156 - return DismissDirection.down;  
157 - }  
158 - }  
159 -  
160 - @override  
161 - bool get finishedWhenPopped =>  
162 - _controller!.status == AnimationStatus.dismissed;  
163 -  
164 - /// The animation that drives the route's transition and the previous route's  
165 - /// forward transition.  
166 - Animation<Alignment>? _animation;  
167 -  
168 - /// The animation controller that the route uses to drive the transitions.  
169 - ///  
170 - /// The animation itself is exposed by the [animation] property.  
171 - AnimationController? _controller;  
172 -  
173 - /// Called to create the animation controller that will drive the transitions  
174 - /// to this route from the previous one, and back to the previous route  
175 - /// from this one.  
176 - AnimationController createAnimationController() {  
177 - assert(!_transitionCompleter.isCompleted,  
178 - 'Cannot reuse a $runtimeType after disposing it.');  
179 - assert(snack.animationDuration >= Duration.zero);  
180 - return AnimationController(  
181 - duration: snack.animationDuration,  
182 - debugLabel: debugLabel,  
183 - vsync: navigator!,  
184 - );  
185 - }  
186 -  
187 - /// Called to create the animation that exposes the current progress of  
188 - /// the transition controlled by the animation controller created by  
189 - /// `createAnimationController()`.  
190 - Animation<Alignment> createAnimation() {  
191 - assert(!_transitionCompleter.isCompleted,  
192 - 'Cannot reuse a $runtimeType after disposing it.');  
193 - assert(_controller != null);  
194 - return AlignmentTween(begin: _initialAlignment, end: _endAlignment).animate(  
195 - CurvedAnimation(  
196 - parent: _controller!,  
197 - curve: snack.forwardAnimationCurve,  
198 - reverseCurve: snack.reverseAnimationCurve,  
199 - ),  
200 - );  
201 - }  
202 -  
203 - Animation<double> createBlurFilterAnimation() {  
204 - return Tween(begin: 0.0, end: snack.overlayBlur).animate(  
205 - CurvedAnimation(  
206 - parent: _controller!,  
207 - curve: Interval(  
208 - 0.0,  
209 - 0.35,  
210 - curve: Curves.easeInOutCirc,  
211 - ),  
212 - ),  
213 - );  
214 - }  
215 -  
216 - Animation<Color?> createColorFilterAnimation() {  
217 - return ColorTween(begin: Color(0x00000000), end: snack.overlayColor)  
218 - .animate(  
219 - CurvedAnimation(  
220 - parent: _controller!,  
221 - curve: Interval(  
222 - 0.0,  
223 - 0.35,  
224 - curve: Curves.easeInOutCirc,  
225 - ),  
226 - ),  
227 - );  
228 - }  
229 -  
230 - T? _result;  
231 - SnackbarStatus? currentStatus;  
232 -  
233 - void _handleStatusChanged(AnimationStatus status) {  
234 - switch (status) {  
235 - case AnimationStatus.completed:  
236 - currentStatus = SnackbarStatus.OPEN;  
237 - _snackbarStatus(currentStatus);  
238 - if (overlayEntries.isNotEmpty) overlayEntries.first.opaque = opaque;  
239 -  
240 - break;  
241 - case AnimationStatus.forward:  
242 - currentStatus = SnackbarStatus.OPENING;  
243 - _snackbarStatus(currentStatus);  
244 - break;  
245 - case AnimationStatus.reverse:  
246 - currentStatus = SnackbarStatus.CLOSING;  
247 - _snackbarStatus(currentStatus);  
248 - if (overlayEntries.isNotEmpty) overlayEntries.first.opaque = false;  
249 - break;  
250 - case AnimationStatus.dismissed:  
251 - assert(!overlayEntries.first.opaque);  
252 - // We might still be the current route if a subclass is controlling the  
253 - // the transition and hits the dismissed status. For example, the iOS  
254 - // back gesture drives this animation to the dismissed status before  
255 - // popping the navigator.  
256 - currentStatus = SnackbarStatus.CLOSED;  
257 - _snackbarStatus(currentStatus);  
258 -  
259 - if (!isCurrent) {  
260 - navigator!.finalizeRoute(this);  
261 - // assert(overlayEntries.isEmpty);  
262 - }  
263 - break;  
264 - }  
265 - changedInternalState();  
266 - }  
267 -  
268 - @override  
269 - void install() {  
270 - assert(!_transitionCompleter.isCompleted,  
271 - 'Cannot install a $runtimeType after disposing it.');  
272 - _controller = createAnimationController();  
273 - assert(_controller != null,  
274 - '$runtimeType.createAnimationController() returned null.');  
275 - _filterBlurAnimation = createBlurFilterAnimation();  
276 - _filterColorAnimation = createColorFilterAnimation();  
277 - _animation = createAnimation();  
278 - assert(_animation != null, '$runtimeType.createAnimation() returned null.');  
279 - super.install();  
280 - }  
281 -  
282 - @override  
283 - TickerFuture didPush() {  
284 - super.didPush();  
285 - assert(  
286 - _controller != null,  
287 - // ignore: lines_longer_than_80_chars  
288 - '$runtimeType.didPush called before calling install() or after calling dispose().',  
289 - );  
290 - assert(  
291 - !_transitionCompleter.isCompleted,  
292 - 'Cannot reuse a $runtimeType after disposing it.',  
293 - );  
294 - _animation!.addStatusListener(_handleStatusChanged);  
295 - _configureTimer();  
296 - return _controller!.forward();  
297 - }  
298 -  
299 - @override  
300 - void didReplace(Route<dynamic>? oldRoute) {  
301 - assert(  
302 - _controller != null,  
303 - // ignore: lines_longer_than_80_chars  
304 - '$runtimeType.didReplace called before calling install() or after calling dispose().',  
305 - );  
306 - assert(  
307 - !_transitionCompleter.isCompleted,  
308 - 'Cannot reuse a $runtimeType after disposing it.',  
309 - );  
310 -  
311 - if (oldRoute is SnackRoute) {  
312 - _controller!.value = oldRoute._controller!.value;  
313 - }  
314 - _animation!.addStatusListener(_handleStatusChanged);  
315 - super.didReplace(oldRoute);  
316 - }  
317 -  
318 - @override  
319 - bool didPop(T? result) {  
320 - assert(  
321 - _controller != null,  
322 - // ignore: lines_longer_than_80_chars  
323 - '$runtimeType.didPop called before calling install() or after calling dispose().',  
324 - );  
325 - assert(  
326 - !_transitionCompleter.isCompleted,  
327 - 'Cannot reuse a $runtimeType after disposing it.',  
328 - );  
329 -  
330 - _result = result;  
331 - _cancelTimer();  
332 -  
333 - if (_wasDismissedBySwipe) {  
334 - Timer(Duration(milliseconds: 200), () {  
335 - _controller!.reset();  
336 - });  
337 -  
338 - _wasDismissedBySwipe = false;  
339 - } else {  
340 - _controller!.reverse();  
341 - }  
342 -  
343 - return super.didPop(result);  
344 - }  
345 -  
346 - void _configureTimer() {  
347 - if (snack.duration != null) {  
348 - if (_timer != null && _timer!.isActive) {  
349 - _timer!.cancel();  
350 - }  
351 - _timer = Timer(snack.duration!, () {  
352 - if (isCurrent) {  
353 - navigator!.pop();  
354 - } else if (isActive) {  
355 - navigator!.removeRoute(this);  
356 - }  
357 - });  
358 - } else {  
359 - if (_timer != null) {  
360 - _timer!.cancel();  
361 - }  
362 - }  
363 - }  
364 -  
365 - void _cancelTimer() {  
366 - if (_timer != null && _timer!.isActive) {  
367 - _timer!.cancel();  
368 - }  
369 - }  
370 -  
371 - /// Whether this route can perform a transition to the given route.  
372 - /// Subclasses can override this method to restrict the set of routes they  
373 - /// need to coordinate transitions with.  
374 - bool canTransitionTo(SnackRoute<dynamic> nextRoute) => true;  
375 -  
376 - /// Whether this route can perform a transition from the given route.  
377 - ///  
378 - /// Subclasses can override this method to restrict the set of routes they  
379 - /// need to coordinate transitions with.  
380 - bool canTransitionFrom(SnackRoute<dynamic> previousRoute) => true;  
381 -  
382 - @override  
383 - void dispose() {  
384 - assert(!_transitionCompleter.isCompleted,  
385 - 'Cannot dispose a $runtimeType twice.');  
386 - _controller?.dispose();  
387 - _transitionCompleter.complete(_result);  
388 - super.dispose();  
389 - }  
390 -  
391 - /// A short description of this route useful for debugging.  
392 - String get debugLabel => '$runtimeType';  
393 -}  
1 import 'dart:async'; 1 import 'dart:async';
2 import 'dart:ui'; 2 import 'dart:ui';
  3 +
3 import 'package:flutter/material.dart'; 4 import 'package:flutter/material.dart';
4 import 'package:flutter/scheduler.dart'; 5 import 'package:flutter/scheduler.dart';
  6 +
5 import '../../../get_core/get_core.dart'; 7 import '../../../get_core/get_core.dart';
6 import '../../get_navigation.dart'; 8 import '../../get_navigation.dart';
7 9
  10 +typedef OnTap = void Function(GetSnackBar snack);
  11 +
8 typedef SnackbarStatusCallback = void Function(SnackbarStatus? status); 12 typedef SnackbarStatusCallback = void Function(SnackbarStatus? status);
9 -typedef OnTap = void Function(GetBar snack);  
10 13
11 -class GetBar<T extends Object> extends StatefulWidget { 14 +@Deprecated('use GetSnackBar')
  15 +class GetBar extends GetSnackBar {
12 GetBar({ 16 GetBar({
13 Key? key, 17 Key? key,
14 - this.title,  
15 - this.message,  
16 - this.titleText,  
17 - this.messageText,  
18 - this.icon,  
19 - this.shouldIconPulse = true,  
20 - this.maxWidth,  
21 - this.margin = const EdgeInsets.all(0.0),  
22 - this.padding = const EdgeInsets.all(16),  
23 - this.borderRadius = 0.0,  
24 - this.borderColor,  
25 - this.borderWidth = 1.0,  
26 - this.backgroundColor = const Color(0xFF303030),  
27 - this.leftBarIndicatorColor,  
28 - this.boxShadows,  
29 - this.backgroundGradient,  
30 - this.mainButton,  
31 - this.onTap,  
32 - this.duration,  
33 - this.isDismissible = true,  
34 - this.dismissDirection = SnackDismissDirection.VERTICAL,  
35 - this.showProgressIndicator = false,  
36 - this.progressIndicatorController,  
37 - this.progressIndicatorBackgroundColor,  
38 - this.progressIndicatorValueColor,  
39 - this.snackPosition = SnackPosition.BOTTOM,  
40 - this.snackStyle = SnackStyle.FLOATING,  
41 - this.forwardAnimationCurve = Curves.easeOutCirc,  
42 - this.reverseAnimationCurve = Curves.easeOutCirc,  
43 - this.animationDuration = const Duration(seconds: 1),  
44 - this.barBlur = 0.0,  
45 - this.overlayBlur = 0.0,  
46 - this.overlayColor = Colors.transparent,  
47 - this.userInputForm, 18 + String? title,
  19 + String? message,
  20 + Widget? titleText,
  21 + Widget? messageText,
  22 + Widget? icon,
  23 + bool shouldIconPulse = true,
  24 + double? maxWidth,
  25 + EdgeInsets margin = const EdgeInsets.all(0.0),
  26 + EdgeInsets padding = const EdgeInsets.all(16),
  27 + double borderRadius = 0.0,
  28 + Color? borderColor,
  29 + double borderWidth = 1.0,
  30 + Color backgroundColor = const Color(0xFF303030),
  31 + Color? leftBarIndicatorColor,
  32 + List<BoxShadow>? boxShadows,
  33 + Gradient? backgroundGradient,
  34 + Widget? mainButton,
  35 + OnTap? onTap,
  36 + Duration? duration,
  37 + bool isDismissible = true,
  38 + DismissDirection? dismissDirection,
  39 + bool showProgressIndicator = false,
  40 + AnimationController? progressIndicatorController,
  41 + Color? progressIndicatorBackgroundColor,
  42 + Animation<Color>? progressIndicatorValueColor,
  43 + SnackPosition snackPosition = SnackPosition.BOTTOM,
  44 + SnackStyle snackStyle = SnackStyle.FLOATING,
  45 + Curve forwardAnimationCurve = Curves.easeOutCirc,
  46 + Curve reverseAnimationCurve = Curves.easeOutCirc,
  47 + Duration animationDuration = const Duration(seconds: 1),
  48 + double barBlur = 0.0,
  49 + double overlayBlur = 0.0,
  50 + Color overlayColor = Colors.transparent,
  51 + Form? userInputForm,
48 SnackbarStatusCallback? snackbarStatus, 52 SnackbarStatusCallback? snackbarStatus,
49 - }) : snackbarStatus = (snackbarStatus ?? (status) {}),  
50 - super(key: key); 53 + }) : super(
  54 + key: key,
  55 + title: title,
  56 + message: message,
  57 + titleText: titleText,
  58 + messageText: messageText,
  59 + icon: icon,
  60 + shouldIconPulse: shouldIconPulse,
  61 + maxWidth: maxWidth,
  62 + margin: margin,
  63 + padding: padding,
  64 + borderRadius: borderRadius,
  65 + borderColor: borderColor,
  66 + borderWidth: borderWidth,
  67 + backgroundColor: backgroundColor,
  68 + leftBarIndicatorColor: leftBarIndicatorColor,
  69 + boxShadows: boxShadows,
  70 + backgroundGradient: backgroundGradient,
  71 + mainButton: mainButton,
  72 + onTap: onTap,
  73 + duration: duration,
  74 + isDismissible: isDismissible,
  75 + dismissDirection: dismissDirection,
  76 + showProgressIndicator: showProgressIndicator,
  77 + progressIndicatorController: progressIndicatorController,
  78 + progressIndicatorBackgroundColor: progressIndicatorBackgroundColor,
  79 + progressIndicatorValueColor: progressIndicatorValueColor,
  80 + snackPosition: snackPosition,
  81 + snackStyle: snackStyle,
  82 + forwardAnimationCurve: forwardAnimationCurve,
  83 + reverseAnimationCurve: reverseAnimationCurve,
  84 + animationDuration: animationDuration,
  85 + barBlur: barBlur,
  86 + overlayBlur: overlayBlur,
  87 + overlayColor: overlayColor,
  88 + userInputForm: userInputForm,
  89 + snackbarStatus: snackbarStatus,
  90 + );
  91 +}
51 92
  93 +class GetSnackBar extends StatefulWidget {
52 /// A callback for you to listen to the different Snack status 94 /// A callback for you to listen to the different Snack status
53 - final SnackbarStatusCallback snackbarStatus; 95 + final SnackbarStatusCallback? snackbarStatus;
54 96
55 /// The title displayed to the user 97 /// The title displayed to the user
56 final String? title; 98 final String? title;
57 99
  100 + /// The direction in which the SnackBar can be dismissed.
  101 + ///
  102 + /// Default is [DismissDirection.down] when
  103 + /// [snackPosition] == [SnackPosition.BOTTOM] and [DismissDirection.up]
  104 + /// when [snackPosition] == [SnackPosition.TOP]
  105 + final DismissDirection? dismissDirection;
  106 +
58 /// The message displayed to the user. 107 /// The message displayed to the user.
59 final String? message; 108 final String? message;
60 109
@@ -80,7 +129,8 @@ class GetBar<T extends Object> extends StatefulWidget { @@ -80,7 +129,8 @@ class GetBar<T extends Object> extends StatefulWidget {
80 /// Check (this example)[https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/material/shadows.dart] 129 /// Check (this example)[https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/material/shadows.dart]
81 final List<BoxShadow>? boxShadows; 130 final List<BoxShadow>? boxShadows;
82 131
83 - /// Makes [backgroundColor] be ignored. 132 + /// Give to GetSnackbar a gradient background.
  133 + /// It Makes [backgroundColor] be ignored.
84 final Gradient? backgroundGradient; 134 final Gradient? backgroundGradient;
85 135
86 /// You can use any widget here, but I recommend [Icon] or [Image] as 136 /// You can use any widget here, but I recommend [Icon] or [Image] as
@@ -91,7 +141,10 @@ class GetBar<T extends Object> extends StatefulWidget { @@ -91,7 +141,10 @@ class GetBar<T extends Object> extends StatefulWidget {
91 /// An option to animate the icon (if present). Defaults to true. 141 /// An option to animate the icon (if present). Defaults to true.
92 final bool shouldIconPulse; 142 final bool shouldIconPulse;
93 143
94 - /// A [TextButton] widget if you need an action from the user. 144 + /// (optional) An action that the user can take based on the snack bar.
  145 + ///
  146 + /// For example, the snack bar might let the user undo the operation that
  147 + /// prompted the snackbar.
95 final Widget? mainButton; 148 final Widget? mainButton;
96 149
97 /// A callback that registers the user's click anywhere. 150 /// A callback that registers the user's click anywhere.
@@ -150,11 +203,6 @@ class GetBar<T extends Object> extends StatefulWidget { @@ -150,11 +203,6 @@ class GetBar<T extends Object> extends StatefulWidget {
150 /// [SnackPosition.BOTTOM] is the default. 203 /// [SnackPosition.BOTTOM] is the default.
151 final SnackPosition snackPosition; 204 final SnackPosition snackPosition;
152 205
153 - /// [SnackDismissDirection.VERTICAL] by default.  
154 - /// Can also be [SnackDismissDirection.HORIZONTAL] in which case both left  
155 - /// and right dismiss are allowed.  
156 - final SnackDismissDirection dismissDirection;  
157 -  
158 /// Snack can be floating or be grounded to the edge of the screen. 206 /// Snack can be floating or be grounded to the edge of the screen.
159 /// If grounded, I do not recommend using [margin] or [borderRadius]. 207 /// If grounded, I do not recommend using [margin] or [borderRadius].
160 /// [SnackStyle.FLOATING] is the default 208 /// [SnackStyle.FLOATING] is the default
@@ -176,7 +224,7 @@ class GetBar<T extends Object> extends StatefulWidget { @@ -176,7 +224,7 @@ class GetBar<T extends Object> extends StatefulWidget {
176 /// Default is 0.0. If different than 0.0, blurs only Snack's background. 224 /// Default is 0.0. If different than 0.0, blurs only Snack's background.
177 /// To take effect, make sure your [backgroundColor] has some opacity. 225 /// To take effect, make sure your [backgroundColor] has some opacity.
178 /// The greater the value, the greater the blur. 226 /// The greater the value, the greater the blur.
179 - final double? barBlur; 227 + final double barBlur;
180 228
181 /// Default is 0.0. If different than 0.0, creates a blurred 229 /// Default is 0.0. If different than 0.0, creates a blurred
182 /// overlay that prevents the user from interacting with the screen. 230 /// overlay that prevents the user from interacting with the screen.
@@ -192,22 +240,57 @@ class GetBar<T extends Object> extends StatefulWidget { @@ -192,22 +240,57 @@ class GetBar<T extends Object> extends StatefulWidget {
192 /// Every other widget is ignored if this is not null. 240 /// Every other widget is ignored if this is not null.
193 final Form? userInputForm; 241 final Form? userInputForm;
194 242
  243 + const GetSnackBar({
  244 + Key? key,
  245 + this.title,
  246 + this.message,
  247 + this.titleText,
  248 + this.messageText,
  249 + this.icon,
  250 + this.shouldIconPulse = true,
  251 + this.maxWidth,
  252 + this.margin = const EdgeInsets.all(0.0),
  253 + this.padding = const EdgeInsets.all(16),
  254 + this.borderRadius = 0.0,
  255 + this.borderColor,
  256 + this.borderWidth = 1.0,
  257 + this.backgroundColor = const Color(0xFF303030),
  258 + this.leftBarIndicatorColor,
  259 + this.boxShadows,
  260 + this.backgroundGradient,
  261 + this.mainButton,
  262 + this.onTap,
  263 + this.duration,
  264 + this.isDismissible = true,
  265 + this.dismissDirection,
  266 + this.showProgressIndicator = false,
  267 + this.progressIndicatorController,
  268 + this.progressIndicatorBackgroundColor,
  269 + this.progressIndicatorValueColor,
  270 + this.snackPosition = SnackPosition.BOTTOM,
  271 + this.snackStyle = SnackStyle.FLOATING,
  272 + this.forwardAnimationCurve = Curves.easeOutCirc,
  273 + this.reverseAnimationCurve = Curves.easeOutCirc,
  274 + this.animationDuration = const Duration(seconds: 1),
  275 + this.barBlur = 0.0,
  276 + this.overlayBlur = 0.0,
  277 + this.overlayColor = Colors.transparent,
  278 + this.userInputForm,
  279 + this.snackbarStatus,
  280 + }) : super(key: key);
  281 +
  282 + @override
  283 + State createState() => GetSnackBarState();
  284 +
195 /// Show the snack. It's call [SnackbarStatus.OPENING] state 285 /// Show the snack. It's call [SnackbarStatus.OPENING] state
196 /// followed by [SnackbarStatus.OPEN] 286 /// followed by [SnackbarStatus.OPEN]
197 - Future<T?>? show<T>() async { 287 + SnackbarController show() {
198 return Get.showSnackbar(this); 288 return Get.showSnackbar(this);
199 } 289 }
200 -  
201 - @override  
202 - State createState() {  
203 - return _GetBarState<T>();  
204 - }  
205 } 290 }
206 291
207 -class _GetBarState<K extends Object> extends State<GetBar> 292 +class GetSnackBarState extends State<GetSnackBar>
208 with TickerProviderStateMixin { 293 with TickerProviderStateMixin {
209 - SnackbarStatus? currentStatus;  
210 -  
211 AnimationController? _fadeController; 294 AnimationController? _fadeController;
212 late Animation<double> _fadeAnimation; 295 late Animation<double> _fadeAnimation;
213 296
@@ -223,6 +306,101 @@ class _GetBarState<K extends Object> extends State<GetBar> @@ -223,6 +306,101 @@ class _GetBarState<K extends Object> extends State<GetBar>
223 FocusScopeNode? _focusNode; 306 FocusScopeNode? _focusNode;
224 late FocusAttachment _focusAttachment; 307 late FocusAttachment _focusAttachment;
225 308
  309 + final Completer<Size> _boxHeightCompleter = Completer<Size>();
  310 +
  311 + late CurvedAnimation _progressAnimation;
  312 +
  313 + final _backgroundBoxKey = GlobalKey();
  314 +
  315 + double get buttonPadding {
  316 + if (widget.padding.right - 12 < 0) {
  317 + return 4;
  318 + } else {
  319 + return widget.padding.right - 12;
  320 + }
  321 + }
  322 +
  323 + RowStyle get _rowStyle {
  324 + if (widget.mainButton != null && widget.icon == null) {
  325 + return RowStyle.action;
  326 + } else if (widget.mainButton == null && widget.icon != null) {
  327 + return RowStyle.icon;
  328 + } else if (widget.mainButton != null && widget.icon != null) {
  329 + return RowStyle.all;
  330 + } else {
  331 + return RowStyle.none;
  332 + }
  333 + }
  334 +
  335 + @override
  336 + Widget build(BuildContext context) {
  337 + return Align(
  338 + heightFactor: 1.0,
  339 + child: Material(
  340 + color: widget.snackStyle == SnackStyle.FLOATING
  341 + ? Colors.transparent
  342 + : widget.backgroundColor,
  343 + child: SafeArea(
  344 + minimum: widget.snackPosition == SnackPosition.BOTTOM
  345 + ? EdgeInsets.only(
  346 + bottom: MediaQuery.of(context).viewInsets.bottom)
  347 + : EdgeInsets.only(top: MediaQuery.of(context).padding.top),
  348 + bottom: widget.snackPosition == SnackPosition.BOTTOM,
  349 + top: widget.snackPosition == SnackPosition.TOP,
  350 + left: false,
  351 + right: false,
  352 + child: Stack(
  353 + children: [
  354 + FutureBuilder<Size>(
  355 + future: _boxHeightCompleter.future,
  356 + builder: (context, snapshot) {
  357 + if (snapshot.hasData) {
  358 + if (widget.barBlur == 0) {
  359 + return _emptyWidget;
  360 + }
  361 + return ClipRRect(
  362 + borderRadius: BorderRadius.circular(widget.borderRadius),
  363 + child: BackdropFilter(
  364 + filter: ImageFilter.blur(
  365 + sigmaX: widget.barBlur, sigmaY: widget.barBlur),
  366 + child: Container(
  367 + height: snapshot.data!.height,
  368 + width: snapshot.data!.width,
  369 + decoration: BoxDecoration(
  370 + color: Colors.transparent,
  371 + borderRadius:
  372 + BorderRadius.circular(widget.borderRadius),
  373 + ),
  374 + ),
  375 + ),
  376 + );
  377 + } else {
  378 + return _emptyWidget;
  379 + }
  380 + },
  381 + ),
  382 + if (widget.userInputForm != null)
  383 + _containerWithForm()
  384 + else
  385 + _containerWithoutForm()
  386 + ],
  387 + ),
  388 + ),
  389 + ),
  390 + );
  391 + }
  392 +
  393 + @override
  394 + void dispose() {
  395 + _fadeController?.dispose();
  396 + widget.progressIndicatorController?.removeListener(_updateProgress);
  397 + widget.progressIndicatorController?.dispose();
  398 +
  399 + _focusAttachment.detach();
  400 + _focusNode!.dispose();
  401 + super.dispose();
  402 + }
  403 +
226 @override 404 @override
227 void initState() { 405 void initState() {
228 super.initState(); 406 super.initState();
@@ -231,9 +409,8 @@ class _GetBarState<K extends Object> extends State<GetBar> @@ -231,9 +409,8 @@ class _GetBarState<K extends Object> extends State<GetBar>
231 widget.userInputForm != null || 409 widget.userInputForm != null ||
232 ((widget.message != null && widget.message!.isNotEmpty) || 410 ((widget.message != null && widget.message!.isNotEmpty) ||
233 widget.messageText != null), 411 widget.messageText != null),
234 - """  
235 -A message is mandatory if you are not using userInputForm.  
236 -Set either a message or messageText"""); 412 + '''
  413 +You need to either use message[String], or messageText[Widget] or define a userInputForm[Form] in GetSnackbar''');
237 414
238 _isTitlePresent = (widget.title != null || widget.titleText != null); 415 _isTitlePresent = (widget.title != null || widget.titleText != null);
239 _messageTopMargin = _isTitlePresent ? 6.0 : widget.padding.top; 416 _messageTopMargin = _isTitlePresent ? 6.0 : widget.padding.top;
@@ -250,25 +427,31 @@ Set either a message or messageText"""); @@ -250,25 +427,31 @@ Set either a message or messageText""");
250 _focusAttachment = _focusNode!.attach(context); 427 _focusAttachment = _focusNode!.attach(context);
251 } 428 }
252 429
253 - @override  
254 - void dispose() {  
255 - _fadeController?.dispose();  
256 -  
257 - widget.progressIndicatorController?.removeListener(_progressListener);  
258 - widget.progressIndicatorController?.dispose();  
259 -  
260 - _focusAttachment.detach();  
261 - _focusNode!.dispose();  
262 - super.dispose(); 430 + Widget _buildLeftBarIndicator() {
  431 + if (widget.leftBarIndicatorColor != null) {
  432 + return FutureBuilder<Size>(
  433 + future: _boxHeightCompleter.future,
  434 + builder: (buildContext, snapshot) {
  435 + if (snapshot.hasData) {
  436 + return Container(
  437 + color: widget.leftBarIndicatorColor,
  438 + width: 5.0,
  439 + height: snapshot.data!.height,
  440 + );
  441 + } else {
  442 + return _emptyWidget;
  443 + }
  444 + },
  445 + );
  446 + } else {
  447 + return _emptyWidget;
  448 + }
263 } 449 }
264 450
265 - final Completer<Size> _boxHeightCompleter = Completer<Size>();  
266 -  
267 void _configureLeftBarFuture() { 451 void _configureLeftBarFuture() {
268 SchedulerBinding.instance!.addPostFrameCallback( 452 SchedulerBinding.instance!.addPostFrameCallback(
269 (_) { 453 (_) {
270 - final keyContext = backgroundBoxKey.currentContext;  
271 - 454 + final keyContext = _backgroundBoxKey.currentContext;
272 if (keyContext != null) { 455 if (keyContext != null) {
273 final box = keyContext.findRenderObject() as RenderBox; 456 final box = keyContext.findRenderObject() as RenderBox;
274 _boxHeightCompleter.complete(box.size); 457 _boxHeightCompleter.complete(box.size);
@@ -277,6 +460,16 @@ Set either a message or messageText"""); @@ -277,6 +460,16 @@ Set either a message or messageText""");
277 ); 460 );
278 } 461 }
279 462
  463 + void _configureProgressIndicatorAnimation() {
  464 + if (widget.showProgressIndicator &&
  465 + widget.progressIndicatorController != null) {
  466 + widget.progressIndicatorController!.addListener(_updateProgress);
  467 +
  468 + _progressAnimation = CurvedAnimation(
  469 + curve: Curves.linear, parent: widget.progressIndicatorController!);
  470 + }
  471 + }
  472 +
280 void _configurePulseAnimation() { 473 void _configurePulseAnimation() {
281 _fadeController = 474 _fadeController =
282 AnimationController(vsync: this, duration: _pulseAnimationDuration); 475 AnimationController(vsync: this, duration: _pulseAnimationDuration);
@@ -299,95 +492,9 @@ Set either a message or messageText"""); @@ -299,95 +492,9 @@ Set either a message or messageText""");
299 _fadeController!.forward(); 492 _fadeController!.forward();
300 } 493 }
301 494
302 - late VoidCallback _progressListener;  
303 -  
304 - void _configureProgressIndicatorAnimation() {  
305 - if (widget.showProgressIndicator &&  
306 - widget.progressIndicatorController != null) {  
307 - _progressListener = () {  
308 - setState(() {});  
309 - };  
310 - widget.progressIndicatorController!.addListener(_progressListener);  
311 -  
312 - _progressAnimation = CurvedAnimation(  
313 - curve: Curves.linear, parent: widget.progressIndicatorController!);  
314 - }  
315 - }  
316 -  
317 - @override  
318 - Widget build(BuildContext context) {  
319 - return Align(  
320 - heightFactor: 1.0,  
321 - child: Material(  
322 - color: widget.snackStyle == SnackStyle.FLOATING  
323 - ? Colors.transparent  
324 - : widget.backgroundColor,  
325 - child: SafeArea(  
326 - minimum: widget.snackPosition == SnackPosition.BOTTOM  
327 - ? EdgeInsets.only(  
328 - // bottom: (GetUtils.isGreaterThan(  
329 - // MediaQuery.of(context).viewInsets.bottom,  
330 - // MediaQuery.of(context).padding.bottom)  
331 - // ? MediaQuery.of(context).viewInsets.bottom  
332 - // : MediaQuery.of(context).padding.bottom))  
333 - bottom: MediaQuery.of(context).viewInsets.bottom)  
334 - : EdgeInsets.only(top: MediaQuery.of(context).padding.top),  
335 - bottom: widget.snackPosition == SnackPosition.BOTTOM,  
336 - top: widget.snackPosition == SnackPosition.TOP,  
337 - left: false,  
338 - right: false,  
339 - child: _getSnack(),  
340 - ),  
341 - ),  
342 - );  
343 - }  
344 -  
345 - Widget _getSnack() {  
346 - Widget snack;  
347 -  
348 - if (widget.userInputForm != null) {  
349 - snack = _generateInputSnack();  
350 - } else {  
351 - snack = _generateSnack();  
352 - }  
353 -  
354 - return Stack(  
355 - children: [  
356 - FutureBuilder<Size>(  
357 - future: _boxHeightCompleter.future,  
358 - builder: (context, snapshot) {  
359 - if (snapshot.hasData) {  
360 - if (widget.barBlur == 0) {  
361 - return _emptyWidget;  
362 - }  
363 - return ClipRRect(  
364 - borderRadius: BorderRadius.circular(widget.borderRadius),  
365 - child: BackdropFilter(  
366 - filter: ImageFilter.blur(  
367 - sigmaX: widget.barBlur!, sigmaY: widget.barBlur!),  
368 - child: Container(  
369 - height: snapshot.data!.height,  
370 - width: snapshot.data!.width,  
371 - decoration: BoxDecoration(  
372 - color: Colors.transparent,  
373 - borderRadius: BorderRadius.circular(widget.borderRadius),  
374 - ),  
375 - ),  
376 - ),  
377 - );  
378 - } else {  
379 - return _emptyWidget;  
380 - }  
381 - },  
382 - ),  
383 - snack,  
384 - ],  
385 - );  
386 - }  
387 -  
388 - Widget _generateInputSnack() { 495 + Widget _containerWithForm() {
389 return Container( 496 return Container(
390 - key: backgroundBoxKey, 497 + key: _backgroundBoxKey,
391 constraints: widget.maxWidth != null 498 constraints: widget.maxWidth != null
392 ? BoxConstraints(maxWidth: widget.maxWidth!) 499 ? BoxConstraints(maxWidth: widget.maxWidth!)
393 : null, 500 : null,
@@ -397,7 +504,10 @@ Set either a message or messageText"""); @@ -397,7 +504,10 @@ Set either a message or messageText""");
397 boxShadow: widget.boxShadows, 504 boxShadow: widget.boxShadows,
398 borderRadius: BorderRadius.circular(widget.borderRadius), 505 borderRadius: BorderRadius.circular(widget.borderRadius),
399 border: widget.borderColor != null 506 border: widget.borderColor != null
400 - ? Border.all(color: widget.borderColor!, width: widget.borderWidth!) 507 + ? Border.all(
  508 + color: widget.borderColor!,
  509 + width: widget.borderWidth!,
  510 + )
401 : null, 511 : null,
402 ), 512 ),
403 child: Padding( 513 child: Padding(
@@ -412,12 +522,16 @@ Set either a message or messageText"""); @@ -412,12 +522,16 @@ Set either a message or messageText""");
412 ); 522 );
413 } 523 }
414 524
415 - late CurvedAnimation _progressAnimation;  
416 - GlobalKey backgroundBoxKey = GlobalKey();  
417 -  
418 - Widget _generateSnack() { 525 + Widget _containerWithoutForm() {
  526 + final iconPadding = widget.padding.left > 16.0 ? widget.padding.left : 0.0;
  527 + final left = _rowStyle == RowStyle.icon || _rowStyle == RowStyle.all
  528 + ? 4.0
  529 + : widget.padding.left;
  530 + final right = _rowStyle == RowStyle.action || _rowStyle == RowStyle.all
  531 + ? 8.0
  532 + : widget.padding.right;
419 return Container( 533 return Container(
420 - key: backgroundBoxKey, 534 + key: _backgroundBoxKey,
421 constraints: widget.maxWidth != null 535 constraints: widget.maxWidth != null
422 ? BoxConstraints(maxWidth: widget.maxWidth!) 536 ? BoxConstraints(maxWidth: widget.maxWidth!)
423 : null, 537 : null,
@@ -444,192 +558,66 @@ Set either a message or messageText"""); @@ -444,192 +558,66 @@ Set either a message or messageText""");
444 : _emptyWidget, 558 : _emptyWidget,
445 Row( 559 Row(
446 mainAxisSize: MainAxisSize.max, 560 mainAxisSize: MainAxisSize.max,
447 - children: _getAppropriateRowLayout(),  
448 - ),  
449 - ],  
450 - ),  
451 - );  
452 - }  
453 -  
454 - List<Widget> _getAppropriateRowLayout() {  
455 - double buttonRightPadding;  
456 - var iconPadding = 0.0;  
457 - if (widget.padding.right - 12 < 0) {  
458 - buttonRightPadding = 4;  
459 - } else {  
460 - buttonRightPadding = widget.padding.right - 12;  
461 - }  
462 -  
463 - if (widget.padding.left > 16.0) {  
464 - iconPadding = widget.padding.left;  
465 - }  
466 -  
467 - if (widget.icon == null && widget.mainButton == null) {  
468 - return [  
469 - _buildLeftBarIndicator(),  
470 - Expanded(  
471 - flex: 1,  
472 - child: Column(  
473 - crossAxisAlignment: CrossAxisAlignment.stretch,  
474 - mainAxisSize: MainAxisSize.min,  
475 - children: <Widget>[  
476 - (_isTitlePresent)  
477 - ? Padding(  
478 - padding: EdgeInsets.only(  
479 - top: widget.padding.top,  
480 - left: widget.padding.left,  
481 - right: widget.padding.right,  
482 - ),  
483 - child: _getTitleText(),  
484 - )  
485 - : _emptyWidget,  
486 - Padding(  
487 - padding: EdgeInsets.only(  
488 - top: _messageTopMargin,  
489 - left: widget.padding.left,  
490 - right: widget.padding.right,  
491 - bottom: widget.padding.bottom, 561 + children: [
  562 + _buildLeftBarIndicator(),
  563 + if (_rowStyle == RowStyle.icon || _rowStyle == RowStyle.all)
  564 + ConstrainedBox(
  565 + constraints:
  566 + BoxConstraints.tightFor(width: 42.0 + iconPadding),
  567 + child: _getIcon(),
492 ), 568 ),
493 - child: widget.messageText ?? _getDefaultNotificationText(),  
494 - ),  
495 - ],  
496 - ),  
497 - ),  
498 - ];  
499 - } else if (widget.icon != null && widget.mainButton == null) {  
500 - return <Widget>[  
501 - _buildLeftBarIndicator(),  
502 - ConstrainedBox(  
503 - constraints: BoxConstraints.tightFor(width: 42.0 + iconPadding),  
504 - child: _getIcon(),  
505 - ),  
506 - Expanded(  
507 - flex: 1,  
508 - child: Column(  
509 - crossAxisAlignment: CrossAxisAlignment.stretch,  
510 - mainAxisSize: MainAxisSize.min,  
511 - children: <Widget>[  
512 - (_isTitlePresent)  
513 - ? Padding( 569 + Expanded(
  570 + flex: 1,
  571 + child: Column(
  572 + crossAxisAlignment: CrossAxisAlignment.stretch,
  573 + mainAxisSize: MainAxisSize.min,
  574 + children: <Widget>[
  575 + if (_isTitlePresent)
  576 + Padding(
  577 + padding: EdgeInsets.only(
  578 + top: widget.padding.top,
  579 + left: left,
  580 + right: right,
  581 + ),
  582 + child: widget.titleText ??
  583 + Text(
  584 + widget.title ?? "",
  585 + style: TextStyle(
  586 + fontSize: 16.0,
  587 + color: Colors.white,
  588 + fontWeight: FontWeight.bold,
  589 + ),
  590 + ),
  591 + )
  592 + else
  593 + _emptyWidget,
  594 + Padding(
514 padding: EdgeInsets.only( 595 padding: EdgeInsets.only(
515 - top: widget.padding.top,  
516 - left: 4.0,  
517 - right: widget.padding.left, 596 + top: _messageTopMargin,
  597 + left: left,
  598 + right: right,
  599 + bottom: widget.padding.bottom,
518 ), 600 ),
519 - child: _getTitleText(),  
520 - )  
521 - : _emptyWidget,  
522 - Padding(  
523 - padding: EdgeInsets.only(  
524 - top: _messageTopMargin,  
525 - left: 4.0,  
526 - right: widget.padding.right,  
527 - bottom: widget.padding.bottom,  
528 - ),  
529 - child: widget.messageText ?? _getDefaultNotificationText(),  
530 - ),  
531 - ],  
532 - ),  
533 - ),  
534 - ];  
535 - } else if (widget.icon == null && widget.mainButton != null) {  
536 - return <Widget>[  
537 - _buildLeftBarIndicator(),  
538 - Expanded(  
539 - flex: 1,  
540 - child: Column(  
541 - crossAxisAlignment: CrossAxisAlignment.stretch,  
542 - mainAxisSize: MainAxisSize.min,  
543 - children: <Widget>[  
544 - (_isTitlePresent)  
545 - ? Padding(  
546 - padding: EdgeInsets.only(  
547 - top: widget.padding.top,  
548 - left: widget.padding.left,  
549 - right: widget.padding.right,  
550 - ),  
551 - child: _getTitleText(),  
552 - )  
553 - : _emptyWidget,  
554 - Padding(  
555 - padding: EdgeInsets.only(  
556 - top: _messageTopMargin,  
557 - left: widget.padding.left,  
558 - right: 8.0,  
559 - bottom: widget.padding.bottom, 601 + child: widget.messageText ??
  602 + Text(
  603 + widget.message ?? "",
  604 + style:
  605 + TextStyle(fontSize: 14.0, color: Colors.white),
  606 + ),
  607 + ),
  608 + ],
560 ), 609 ),
561 - child: widget.messageText ?? _getDefaultNotificationText(),  
562 ), 610 ),
563 - ],  
564 - ),  
565 - ),  
566 - Padding(  
567 - padding: EdgeInsets.only(right: buttonRightPadding),  
568 - child: _getMainActionButton(),  
569 - ),  
570 - ];  
571 - } else {  
572 - return <Widget>[  
573 - _buildLeftBarIndicator(),  
574 - ConstrainedBox(  
575 - constraints: BoxConstraints.tightFor(width: 42.0 + iconPadding),  
576 - child: _getIcon(),  
577 - ),  
578 - Expanded(  
579 - flex: 1,  
580 - child: Column(  
581 - crossAxisAlignment: CrossAxisAlignment.stretch,  
582 - mainAxisSize: MainAxisSize.min,  
583 - children: <Widget>[  
584 - (_isTitlePresent)  
585 - ? Padding(  
586 - padding: EdgeInsets.only(  
587 - top: widget.padding.top,  
588 - left: 4.0,  
589 - right: 8.0,  
590 - ),  
591 - child: _getTitleText(),  
592 - )  
593 - : _emptyWidget,  
594 - Padding(  
595 - padding: EdgeInsets.only(  
596 - top: _messageTopMargin,  
597 - left: 4.0,  
598 - right: 8.0,  
599 - bottom: widget.padding.bottom, 611 + if (_rowStyle == RowStyle.action || _rowStyle == RowStyle.all)
  612 + Padding(
  613 + padding: EdgeInsets.only(right: buttonPadding),
  614 + child: widget.mainButton,
600 ), 615 ),
601 - child: widget.messageText ?? _getDefaultNotificationText(),  
602 - ),  
603 ], 616 ],
604 ), 617 ),
605 - ),  
606 - Padding(  
607 - padding: EdgeInsets.only(right: buttonRightPadding),  
608 - child: _getMainActionButton(),  
609 - ),  
610 - ];  
611 - }  
612 - }  
613 -  
614 - Widget _buildLeftBarIndicator() {  
615 - if (widget.leftBarIndicatorColor != null) {  
616 - return FutureBuilder<Size>(  
617 - future: _boxHeightCompleter.future,  
618 - builder: (buildContext, snapshot) {  
619 - if (snapshot.hasData) {  
620 - return Container(  
621 - color: widget.leftBarIndicatorColor,  
622 - width: 5.0,  
623 - height: snapshot.data!.height,  
624 - );  
625 - } else {  
626 - return _emptyWidget;  
627 - }  
628 - },  
629 - );  
630 - } else {  
631 - return _emptyWidget;  
632 - } 618 + ],
  619 + ),
  620 + );
633 } 621 }
634 622
635 Widget? _getIcon() { 623 Widget? _getIcon() {
@@ -645,37 +633,15 @@ Set either a message or messageText"""); @@ -645,37 +633,15 @@ Set either a message or messageText""");
645 } 633 }
646 } 634 }
647 635
648 - Widget _getTitleText() {  
649 - return widget.titleText ??  
650 - Text(  
651 - widget.title ?? "",  
652 - style: TextStyle(  
653 - fontSize: 16.0, color: Colors.white, fontWeight: FontWeight.bold),  
654 - );  
655 - }  
656 -  
657 - Text _getDefaultNotificationText() {  
658 - return Text(  
659 - widget.message ?? "",  
660 - style: TextStyle(fontSize: 14.0, color: Colors.white),  
661 - );  
662 - }  
663 -  
664 - Widget? _getMainActionButton() {  
665 - return widget.mainButton;  
666 - } 636 + void _updateProgress() => setState(() {});
667 } 637 }
668 638
669 -/// Indicates if snack is going to start at the [TOP] or at the [BOTTOM]  
670 -enum SnackPosition { TOP, BOTTOM }  
671 -  
672 -/// Indicates if snack will be attached to the edge of the screen or not  
673 -enum SnackStyle { FLOATING, GROUNDED }  
674 -  
675 -/// Indicates the direction in which it is possible to dismiss  
676 -/// If vertical, dismiss up will be allowed if [SnackPosition.TOP]  
677 -/// If vertical, dismiss down will be allowed if [SnackPosition.BOTTOM]  
678 -enum SnackDismissDirection { HORIZONTAL, VERTICAL } 639 +enum RowStyle {
  640 + icon,
  641 + action,
  642 + all,
  643 + none,
  644 +}
679 645
680 /// Indicates Status of snackbar 646 /// Indicates Status of snackbar
681 /// [SnackbarStatus.OPEN] Snack is fully open, [SnackbarStatus.CLOSED] Snackbar 647 /// [SnackbarStatus.OPEN] Snack is fully open, [SnackbarStatus.CLOSED] Snackbar
@@ -686,3 +652,9 @@ enum SnackDismissDirection { HORIZONTAL, VERTICAL } @@ -686,3 +652,9 @@ enum SnackDismissDirection { HORIZONTAL, VERTICAL }
686 /// and ends 652 /// and ends
687 /// with the full snackbar dispose 653 /// with the full snackbar dispose
688 enum SnackbarStatus { OPEN, CLOSED, OPENING, CLOSING } 654 enum SnackbarStatus { OPEN, CLOSED, OPENING, CLOSING }
  655 +
  656 +/// Indicates if snack is going to start at the [TOP] or at the [BOTTOM]
  657 +enum SnackPosition { TOP, BOTTOM }
  658 +
  659 +/// Indicates if snack will be attached to the edge of the screen or not
  660 +enum SnackStyle { FLOATING, GROUNDED }
  1 +import 'dart:async';
  2 +import 'dart:math';
  3 +import 'dart:ui';
  4 +
  5 +import 'package:flutter/material.dart';
  6 +
  7 +import '../../../get.dart';
  8 +
  9 +class SnackbarController {
  10 + static final _snackBarQueue = _SnackBarQueue();
  11 + static bool get isSnackbarBeingShown => _snackBarQueue._isJobInProgress;
  12 + final key = GlobalKey<GetSnackBarState>();
  13 +
  14 + late Animation<double> _filterBlurAnimation;
  15 + late Animation<Color?> _filterColorAnimation;
  16 +
  17 + final GetSnackBar snackbar;
  18 + final _transitionCompleter = Completer();
  19 +
  20 + late SnackbarStatusCallback? _snackbarStatus;
  21 + late final Alignment? _initialAlignment;
  22 + late final Alignment? _endAlignment;
  23 +
  24 + bool _wasDismissedBySwipe = false;
  25 +
  26 + bool _onTappedDismiss = false;
  27 +
  28 + Timer? _timer;
  29 +
  30 + /// The animation that drives the route's transition and the previous route's
  31 + /// forward transition.
  32 + late final Animation<Alignment> _animation;
  33 +
  34 + /// The animation controller that the route uses to drive the transitions.
  35 + ///
  36 + /// The animation itself is exposed by the [animation] property.
  37 + late final AnimationController _controller;
  38 +
  39 + SnackbarStatus? _currentStatus;
  40 +
  41 + final _overlayEntries = <OverlayEntry>[];
  42 +
  43 + OverlayState? _overlayState;
  44 +
  45 + SnackbarController(this.snackbar);
  46 +
  47 + Future<void> get future => _transitionCompleter.future;
  48 +
  49 + /// Close the snackbar with animation
  50 + Future<void> close({bool withAnimations = true}) async {
  51 + if (!withAnimations) {
  52 + _removeOverlay();
  53 + return;
  54 + }
  55 + _removeEntry();
  56 + await future;
  57 + }
  58 +
  59 + /// Adds GetSnackbar to a view queue.
  60 + /// Only one GetSnackbar will be displayed at a time, and this method returns
  61 + /// a future to when the snackbar disappears.
  62 + Future<void> show() {
  63 + return _snackBarQueue._addJob(this);
  64 + }
  65 +
  66 + void _cancelTimer() {
  67 + if (_timer != null && _timer!.isActive) {
  68 + _timer!.cancel();
  69 + }
  70 + }
  71 +
  72 + // ignore: avoid_returning_this
  73 + void _configureAlignment(SnackPosition snackPosition) {
  74 + switch (snackbar.snackPosition) {
  75 + case SnackPosition.TOP:
  76 + {
  77 + _initialAlignment = const Alignment(-1.0, -2.0);
  78 + _endAlignment = const Alignment(-1.0, -1.0);
  79 + break;
  80 + }
  81 + case SnackPosition.BOTTOM:
  82 + {
  83 + _initialAlignment = const Alignment(-1.0, 2.0);
  84 + _endAlignment = const Alignment(-1.0, 1.0);
  85 + break;
  86 + }
  87 + }
  88 + }
  89 +
  90 + void _configureOverlay() {
  91 + _overlayState = Overlay.of(Get.overlayContext!);
  92 + _overlayEntries.clear();
  93 + _overlayEntries.addAll(_createOverlayEntries(_getBodyWidget()));
  94 + _overlayState!.insertAll(_overlayEntries);
  95 + _configureSnackBarDisplay();
  96 + }
  97 +
  98 + void _configureSnackBarDisplay() {
  99 + assert(!_transitionCompleter.isCompleted,
  100 + 'Cannot configure a snackbar after disposing it.');
  101 + _controller = _createAnimationController();
  102 + _configureAlignment(snackbar.snackPosition);
  103 + _snackbarStatus = snackbar.snackbarStatus;
  104 + _filterBlurAnimation = _createBlurFilterAnimation();
  105 + _filterColorAnimation = _createColorOverlayColor();
  106 + _animation = _createAnimation();
  107 + _animation.addStatusListener(_handleStatusChanged);
  108 + _configureTimer();
  109 + _controller.forward();
  110 + }
  111 +
  112 + void _configureTimer() {
  113 + if (snackbar.duration != null) {
  114 + if (_timer != null && _timer!.isActive) {
  115 + _timer!.cancel();
  116 + }
  117 + _timer = Timer(snackbar.duration!, _removeEntry);
  118 + } else {
  119 + if (_timer != null) {
  120 + _timer!.cancel();
  121 + }
  122 + }
  123 + }
  124 +
  125 + /// Called to create the animation that exposes the current progress of
  126 + /// the transition controlled by the animation controller created by
  127 + /// `createAnimationController()`.
  128 + Animation<Alignment> _createAnimation() {
  129 + assert(!_transitionCompleter.isCompleted,
  130 + 'Cannot create a animation from a disposed snackbar');
  131 + return AlignmentTween(begin: _initialAlignment, end: _endAlignment).animate(
  132 + CurvedAnimation(
  133 + parent: _controller,
  134 + curve: snackbar.forwardAnimationCurve,
  135 + reverseCurve: snackbar.reverseAnimationCurve,
  136 + ),
  137 + );
  138 + }
  139 +
  140 + /// Called to create the animation controller that will drive the transitions
  141 + /// to this route from the previous one, and back to the previous route
  142 + /// from this one.
  143 + AnimationController _createAnimationController() {
  144 + assert(!_transitionCompleter.isCompleted,
  145 + 'Cannot create a animationController from a disposed snackbar');
  146 + assert(snackbar.animationDuration >= Duration.zero);
  147 + return AnimationController(
  148 + duration: snackbar.animationDuration,
  149 + debugLabel: '$runtimeType',
  150 + vsync: _overlayState!,
  151 + );
  152 + }
  153 +
  154 + Animation<double> _createBlurFilterAnimation() {
  155 + return Tween(begin: 0.0, end: snackbar.overlayBlur).animate(
  156 + CurvedAnimation(
  157 + parent: _controller,
  158 + curve: const Interval(
  159 + 0.0,
  160 + 0.35,
  161 + curve: Curves.easeInOutCirc,
  162 + ),
  163 + ),
  164 + );
  165 + }
  166 +
  167 + Animation<Color?> _createColorOverlayColor() {
  168 + return ColorTween(
  169 + begin: const Color(0x00000000), end: snackbar.overlayColor)
  170 + .animate(
  171 + CurvedAnimation(
  172 + parent: _controller,
  173 + curve: const Interval(
  174 + 0.0,
  175 + 0.35,
  176 + curve: Curves.easeInOutCirc,
  177 + ),
  178 + ),
  179 + );
  180 + }
  181 +
  182 + Iterable<OverlayEntry> _createOverlayEntries(Widget child) {
  183 + return <OverlayEntry>[
  184 + if (snackbar.overlayBlur > 0.0) ...[
  185 + OverlayEntry(
  186 + builder: (context) => GestureDetector(
  187 + onTap: () {
  188 + if (snackbar.isDismissible && !_onTappedDismiss) {
  189 + _onTappedDismiss = true;
  190 + close();
  191 + }
  192 + },
  193 + child: AnimatedBuilder(
  194 + animation: _filterBlurAnimation,
  195 + builder: (context, child) {
  196 + return BackdropFilter(
  197 + filter: ImageFilter.blur(
  198 + sigmaX: max(0.001, _filterBlurAnimation.value),
  199 + sigmaY: max(0.001, _filterBlurAnimation.value),
  200 + ),
  201 + child: Container(
  202 + constraints: const BoxConstraints.expand(),
  203 + color: _filterColorAnimation.value,
  204 + ),
  205 + );
  206 + },
  207 + ),
  208 + ),
  209 + maintainState: false,
  210 + opaque: false,
  211 + ),
  212 + ],
  213 + OverlayEntry(
  214 + builder: (context) => Semantics(
  215 + child: AlignTransition(
  216 + alignment: _animation,
  217 + child: snackbar.isDismissible
  218 + ? _getDismissibleSnack(child)
  219 + : _getSnackbarContainer(child),
  220 + ),
  221 + focused: false,
  222 + container: true,
  223 + explicitChildNodes: true,
  224 + ),
  225 + maintainState: false,
  226 + opaque: false,
  227 + ),
  228 + ];
  229 + }
  230 +
  231 + Widget _getBodyWidget() {
  232 + return Builder(builder: (_) {
  233 + return GestureDetector(
  234 + child: snackbar,
  235 + onTap: snackbar.onTap != null
  236 + ? () => snackbar.onTap?.call(snackbar)
  237 + : null,
  238 + );
  239 + });
  240 + }
  241 +
  242 + DismissDirection _getDefaultDismissDirection() {
  243 + if (snackbar.snackPosition == SnackPosition.TOP) {
  244 + return DismissDirection.up;
  245 + }
  246 + return DismissDirection.down;
  247 + }
  248 +
  249 + Widget _getDismissibleSnack(Widget child) {
  250 + return Dismissible(
  251 + direction: snackbar.dismissDirection ?? _getDefaultDismissDirection(),
  252 + resizeDuration: null,
  253 + confirmDismiss: (_) {
  254 + if (_currentStatus == SnackbarStatus.OPENING ||
  255 + _currentStatus == SnackbarStatus.CLOSING) {
  256 + return Future.value(false);
  257 + }
  258 + return Future.value(true);
  259 + },
  260 + key: const Key('dismissible'),
  261 + onDismissed: (_) {
  262 + _wasDismissedBySwipe = true;
  263 + _removeEntry();
  264 + },
  265 + child: _getSnackbarContainer(child),
  266 + );
  267 + }
  268 +
  269 + Widget _getSnackbarContainer(Widget child) {
  270 + return Container(
  271 + margin: snackbar.margin,
  272 + child: child,
  273 + );
  274 + }
  275 +
  276 + void _handleStatusChanged(AnimationStatus status) {
  277 + switch (status) {
  278 + case AnimationStatus.completed:
  279 + _currentStatus = SnackbarStatus.OPEN;
  280 + _snackbarStatus?.call(_currentStatus);
  281 + if (_overlayEntries.isNotEmpty) _overlayEntries.first.opaque = false;
  282 +
  283 + break;
  284 + case AnimationStatus.forward:
  285 + _currentStatus = SnackbarStatus.OPENING;
  286 + _snackbarStatus?.call(_currentStatus);
  287 + break;
  288 + case AnimationStatus.reverse:
  289 + _currentStatus = SnackbarStatus.CLOSING;
  290 + _snackbarStatus?.call(_currentStatus);
  291 + if (_overlayEntries.isNotEmpty) _overlayEntries.first.opaque = false;
  292 + break;
  293 + case AnimationStatus.dismissed:
  294 + assert(!_overlayEntries.first.opaque);
  295 + _currentStatus = SnackbarStatus.CLOSED;
  296 + _snackbarStatus?.call(_currentStatus);
  297 + _removeOverlay();
  298 + break;
  299 + }
  300 + }
  301 +
  302 + void _removeEntry() {
  303 + assert(
  304 + !_transitionCompleter.isCompleted,
  305 + 'Cannot remove entry from a disposed snackbar',
  306 + );
  307 +
  308 + _cancelTimer();
  309 +
  310 + if (_wasDismissedBySwipe) {
  311 + Timer(const Duration(milliseconds: 200), _controller.reset);
  312 + _wasDismissedBySwipe = false;
  313 + } else {
  314 + _controller.reverse();
  315 + }
  316 + }
  317 +
  318 + void _removeOverlay() {
  319 + for (var element in _overlayEntries) {
  320 + element.remove();
  321 + }
  322 +
  323 + assert(!_transitionCompleter.isCompleted,
  324 + 'Cannot remove overlay from a disposed snackbar');
  325 + _controller.dispose();
  326 + _overlayEntries.clear();
  327 + _transitionCompleter.complete();
  328 + }
  329 +
  330 + Future<void> _show() {
  331 + _configureOverlay();
  332 + return future;
  333 + }
  334 +
  335 + static void cancelAllSnackbars() {
  336 + _snackBarQueue._cancelAllJobs();
  337 + }
  338 +
  339 + static Future<void> closeCurrentSnackbar() async {
  340 + await _snackBarQueue._closeCurrentJob();
  341 + }
  342 +}
  343 +
  344 +class _SnackBarQueue {
  345 + final _queue = GetQueue();
  346 + final _snackbarList = <SnackbarController>[];
  347 +
  348 + SnackbarController? get _currentSnackbar {
  349 + if (_snackbarList.isEmpty) return null;
  350 + return _snackbarList.first;
  351 + }
  352 +
  353 + bool get _isJobInProgress => _snackbarList.isNotEmpty;
  354 +
  355 + Future<void> _addJob(SnackbarController job) async {
  356 + _snackbarList.add(job);
  357 + final data = await _queue.add(job._show);
  358 + _snackbarList.remove(job);
  359 + return data;
  360 + }
  361 +
  362 + Future<void> _cancelAllJobs() async {
  363 + await _currentSnackbar?.close();
  364 + _queue.cancelAllJobs();
  365 + _snackbarList.clear();
  366 + }
  367 +
  368 + Future<void> _closeCurrentJob() async {
  369 + if (_currentSnackbar == null) return;
  370 + await _currentSnackbar!.close();
  371 + }
  372 +}
@@ -5,6 +5,8 @@ part of rx_types; @@ -5,6 +5,8 @@ part of rx_types;
5 /// This interface is the contract that _RxImpl]<T> uses in all it's 5 /// This interface is the contract that _RxImpl]<T> uses in all it's
6 /// subclass. 6 /// subclass.
7 abstract class RxInterface<T> { 7 abstract class RxInterface<T> {
  8 + static RxInterface? proxy;
  9 +
8 bool get canUpdate; 10 bool get canUpdate;
9 11
10 /// Adds a listener to stream 12 /// Adds a listener to stream
@@ -13,8 +15,6 @@ abstract class RxInterface<T> { @@ -13,8 +15,6 @@ abstract class RxInterface<T> {
13 /// Close the Rx Variable 15 /// Close the Rx Variable
14 void close(); 16 void close();
15 17
16 - static RxInterface? proxy;  
17 -  
18 /// Calls `callback` with current value, when the value changes. 18 /// Calls `callback` with current value, when the value changes.
19 StreamSubscription<T> listen(void Function(T event) onData, 19 StreamSubscription<T> listen(void Function(T event) onData,
20 {Function? onError, void Function()? onDone, bool? cancelOnError}); 20 {Function? onError, void Function()? onDone, bool? cancelOnError});
  1 +// ignore_for_file: lines_longer_than_80_chars
  2 +
  3 +import 'package:flutter/foundation.dart';
  4 +import 'package:flutter/material.dart';
1 import 'package:flutter/scheduler.dart'; 5 import 'package:flutter/scheduler.dart';
  6 +
2 import '../../get_state_manager.dart'; 7 import '../../get_state_manager.dart';
3 8
4 /// Used like `SingleTickerProviderMixin` but only with Get Controllers. 9 /// Used like `SingleTickerProviderMixin` but only with Get Controllers.
@@ -7,6 +12,84 @@ import '../../get_state_manager.dart'; @@ -7,6 +12,84 @@ import '../../get_state_manager.dart';
7 /// Example: 12 /// Example:
8 ///``` 13 ///```
9 ///class SplashController extends GetxController with 14 ///class SplashController extends GetxController with
  15 +/// GetSingleTickerProviderStateMixin {
  16 +/// AnimationController controller;
  17 +///
  18 +/// @override
  19 +/// void onInit() {
  20 +/// final duration = const Duration(seconds: 2);
  21 +/// controller =
  22 +/// AnimationController.unbounded(duration: duration, vsync: this);
  23 +/// controller.repeat();
  24 +/// controller.addListener(() =>
  25 +/// print("Animation Controller value: ${controller.value}"));
  26 +/// }
  27 +/// ...
  28 +/// ```
  29 +mixin GetSingleTickerProviderStateMixin on GetxController
  30 + implements TickerProvider {
  31 + Ticker? _ticker;
  32 +
  33 + @override
  34 + Ticker createTicker(TickerCallback onTick) {
  35 + assert(() {
  36 + if (_ticker == null) return true;
  37 + throw FlutterError.fromParts(<DiagnosticsNode>[
  38 + ErrorSummary(
  39 + '$runtimeType is a SingleTickerProviderStateMixin but multiple tickers were created.'),
  40 + ErrorDescription(
  41 + 'A SingleTickerProviderStateMixin can only be used as a TickerProvider once.'),
  42 + ErrorHint(
  43 + 'If a State is used for multiple AnimationController objects, or if it is passed to other '
  44 + 'objects and those objects might use it more than one time in total, then instead of '
  45 + 'mixing in a SingleTickerProviderStateMixin, use a regular TickerProviderStateMixin.',
  46 + ),
  47 + ]);
  48 + }());
  49 + _ticker =
  50 + Ticker(onTick, debugLabel: kDebugMode ? 'created by $this' : null);
  51 + // We assume that this is called from initState, build, or some sort of
  52 + // event handler, and that thus TickerMode.of(context) would return true. We
  53 + // can't actually check that here because if we're in initState then we're
  54 + // not allowed to do inheritance checks yet.
  55 + return _ticker!;
  56 + }
  57 +
  58 + void didChangeDependencies(BuildContext context) {
  59 + if (_ticker != null) _ticker!.muted = !TickerMode.of(context);
  60 + }
  61 +
  62 + @override
  63 + void onClose() {
  64 + assert(() {
  65 + if (_ticker == null || !_ticker!.isActive) return true;
  66 + throw FlutterError.fromParts(<DiagnosticsNode>[
  67 + ErrorSummary('$this was disposed with an active Ticker.'),
  68 + ErrorDescription(
  69 + '$runtimeType created a Ticker via its SingleTickerProviderStateMixin, but at the time '
  70 + 'dispose() was called on the mixin, that Ticker was still active. The Ticker must '
  71 + 'be disposed before calling super.dispose().',
  72 + ),
  73 + ErrorHint(
  74 + 'Tickers used by AnimationControllers '
  75 + 'should be disposed by calling dispose() on the AnimationController itself. '
  76 + 'Otherwise, the ticker will leak.',
  77 + ),
  78 + _ticker!.describeForError('The offending ticker was'),
  79 + ]);
  80 + }());
  81 + super.onClose();
  82 + }
  83 +}
  84 +
  85 +@Deprecated('use GetSingleTickerProviderStateMixin')
  86 +
  87 +/// Used like `SingleTickerProviderMixin` but only with Get Controllers.
  88 +/// Simplifies AnimationController creation inside GetxController.
  89 +///
  90 +/// Example:
  91 +///```
  92 +///class SplashController extends GetxController with
10 /// SingleGetTickerProviderMixin { 93 /// SingleGetTickerProviderMixin {
11 /// AnimationController _ac; 94 /// AnimationController _ac;
12 /// 95 ///
@@ -75,14 +75,14 @@ mixin ScrollMixin on GetLifeCycleBase { @@ -75,14 +75,14 @@ mixin ScrollMixin on GetLifeCycleBase {
75 abstract class RxController extends DisposableInterface {} 75 abstract class RxController extends DisposableInterface {}
76 76
77 abstract class SuperController<T> extends FullLifeCycleController 77 abstract class SuperController<T> extends FullLifeCycleController
78 - with FullLifeCycle, StateMixin<T> {} 78 + with FullLifeCycleMixin, StateMixin<T> {}
79 79
80 abstract class FullLifeCycleController extends GetxController 80 abstract class FullLifeCycleController extends GetxController
81 with 81 with
82 // ignore: prefer_mixin 82 // ignore: prefer_mixin
83 WidgetsBindingObserver {} 83 WidgetsBindingObserver {}
84 84
85 -mixin FullLifeCycle on FullLifeCycleController { 85 +mixin FullLifeCycleMixin on FullLifeCycleController {
86 @mustCallSuper 86 @mustCallSuper
87 @override 87 @override
88 void onInit() { 88 void onInit() {
1 import 'dart:ui'; 1 import 'dart:ui';
  2 +
2 import '../../../get_core/get_core.dart'; 3 import '../../../get_core/get_core.dart';
3 4
  5 +class _IntlHost {
  6 + Locale? locale;
  7 +
  8 + Locale? fallbackLocale;
  9 +
  10 + Map<String, Map<String, String>> translations = {};
  11 +}
  12 +
  13 +extension FirstWhereExt<T> on List<T> {
  14 + /// The first element satisfying [test], or `null` if there are none.
  15 + T? firstWhereOrNull(bool Function(T element) test) {
  16 + for (var element in this) {
  17 + if (test(element)) return element;
  18 + }
  19 + return null;
  20 + }
  21 +}
  22 +
  23 +extension LocalesIntl on GetInterface {
  24 + static final _intlHost = _IntlHost();
  25 +
  26 + Locale? get locale => _intlHost.locale;
  27 +
  28 + Locale? get fallbackLocale => _intlHost.fallbackLocale;
  29 +
  30 + set locale(Locale? newLocale) => _intlHost.locale = newLocale;
  31 +
  32 + set fallbackLocale(Locale? newLocale) => _intlHost.fallbackLocale = newLocale;
  33 +
  34 + Map<String, Map<String, String>> get translations => _intlHost.translations;
  35 +
  36 + void addTranslations(Map<String, Map<String, String>> tr) {
  37 + translations.addAll(tr);
  38 + }
  39 +
  40 + void clearTranslations() {
  41 + translations.clear();
  42 + }
  43 +
  44 + void appendTranslations(Map<String, Map<String, String>> tr) {
  45 + tr.forEach((key, map) {
  46 + if (translations.containsKey(key)) {
  47 + translations[key]!.addAll(map);
  48 + } else {
  49 + translations[key] = map;
  50 + }
  51 + });
  52 + }
  53 +}
  54 +
4 extension Trans on String { 55 extension Trans on String {
  56 + // Checks whether the language code and country code are present, and
  57 + // whether the key is also present.
  58 + bool get _fullLocaleAndKey {
  59 + return Get.translations.containsKey(
  60 + "${Get.locale!.languageCode}_${Get.locale!.countryCode}") &&
  61 + Get.translations[
  62 + "${Get.locale!.languageCode}_${Get.locale!.countryCode}"]!
  63 + .containsKey(this);
  64 + }
  65 +
  66 + // Checks if there is a callback language in the absence of the specific
  67 + // country, and if it contains that key.
  68 + Map<String, String>? get _getSimilarLanguageTranslation {
  69 + final translationsWithNoCountry = Get.translations
  70 + .map((key, value) => MapEntry(key.split("_").first, value));
  71 + final containsKey =
  72 + translationsWithNoCountry.containsKey(Get.locale!.languageCode);
  73 +
  74 + if (!containsKey) {
  75 + return null;
  76 + }
  77 +
  78 + return translationsWithNoCountry[Get.locale!.languageCode];
  79 + }
  80 +
5 String get tr { 81 String get tr {
  82 + // print('language');
  83 + // print(Get.locale!.languageCode);
  84 + // print('contains');
  85 + // print(Get.translations.containsKey(Get.locale!.languageCode));
  86 + // print(Get.translations.keys);
6 // Returns the key if locale is null. 87 // Returns the key if locale is null.
7 if (Get.locale?.languageCode == null) return this; 88 if (Get.locale?.languageCode == null) return this;
8 89
9 - // Checks whether the language code and country code are present, and  
10 - // whether the key is also present.  
11 - if (Get.translations.containsKey(  
12 - "${Get.locale!.languageCode}_${Get.locale!.countryCode}") &&  
13 - Get.translations[  
14 - "${Get.locale!.languageCode}_${Get.locale!.countryCode}"]!  
15 - .containsKey(this)) { 90 + if (_fullLocaleAndKey) {
16 return Get.translations[ 91 return Get.translations[
17 "${Get.locale!.languageCode}_${Get.locale!.countryCode}"]![this]!; 92 "${Get.locale!.languageCode}_${Get.locale!.countryCode}"]![this]!;
18 -  
19 - // Checks if there is a callback language in the absence of the specific  
20 - // country, and if it contains that key.  
21 - } else if (Get.translations.containsKey(Get.locale!.languageCode) &&  
22 - Get.translations[Get.locale!.languageCode]!.containsKey(this)) {  
23 - return Get.translations[Get.locale!.languageCode]![this]!; 93 + }
  94 + final similarTranslation = _getSimilarLanguageTranslation;
  95 + if (similarTranslation != null && similarTranslation.containsKey(this)) {
  96 + return similarTranslation[this]!;
24 // If there is no corresponding language or corresponding key, return 97 // If there is no corresponding language or corresponding key, return
25 // the key. 98 // the key.
26 } else if (Get.fallbackLocale != null) { 99 } else if (Get.fallbackLocale != null) {
@@ -70,43 +143,3 @@ extension Trans on String { @@ -70,43 +143,3 @@ extension Trans on String {
70 return i == 1 ? trParams(params) : pluralKey!.trParams(params); 143 return i == 1 ? trParams(params) : pluralKey!.trParams(params);
71 } 144 }
72 } 145 }
73 -  
74 -class _IntlHost {  
75 - Locale? locale;  
76 -  
77 - Locale? fallbackLocale;  
78 -  
79 - Map<String, Map<String, String>> translations = {};  
80 -}  
81 -  
82 -extension LocalesIntl on GetInterface {  
83 - static final _intlHost = _IntlHost();  
84 -  
85 - Locale? get locale => _intlHost.locale;  
86 -  
87 - Locale? get fallbackLocale => _intlHost.fallbackLocale;  
88 -  
89 - set locale(Locale? newLocale) => _intlHost.locale = newLocale;  
90 -  
91 - set fallbackLocale(Locale? newLocale) => _intlHost.fallbackLocale = newLocale;  
92 -  
93 - Map<String, Map<String, String>> get translations => _intlHost.translations;  
94 -  
95 - void addTranslations(Map<String, Map<String, String>> tr) {  
96 - translations.addAll(tr);  
97 - }  
98 -  
99 - void clearTranslations() {  
100 - translations.clear();  
101 - }  
102 -  
103 - void appendTranslations(Map<String, Map<String, String>> tr) {  
104 - tr.forEach((key, map) {  
105 - if (translations.containsKey(key)) {  
106 - translations[key]!.addAll(map);  
107 - } else {  
108 - translations[key] = map;  
109 - }  
110 - });  
111 - }  
112 -}  
@@ -4,8 +4,8 @@ class GetMicrotask { @@ -4,8 +4,8 @@ class GetMicrotask {
4 int _version = 0; 4 int _version = 0;
5 int _microtask = 0; 5 int _microtask = 0;
6 6
7 - int get version => _version;  
8 int get microtask => _microtask; 7 int get microtask => _microtask;
  8 + int get version => _version;
9 9
10 void exec(Function callback) { 10 void exec(Function callback) {
11 if (_microtask == _version) { 11 if (_microtask == _version) {
@@ -23,6 +23,17 @@ class GetQueue { @@ -23,6 +23,17 @@ class GetQueue {
23 final List<_Item> _queue = []; 23 final List<_Item> _queue = [];
24 bool _active = false; 24 bool _active = false;
25 25
  26 + Future<T> add<T>(Function job) {
  27 + var completer = Completer<T>();
  28 + _queue.add(_Item(completer, job));
  29 + _check();
  30 + return completer.future;
  31 + }
  32 +
  33 + void cancelAllJobs() {
  34 + _queue.clear();
  35 + }
  36 +
26 void _check() async { 37 void _check() async {
27 if (!_active && _queue.isNotEmpty) { 38 if (!_active && _queue.isNotEmpty) {
28 _active = true; 39 _active = true;
@@ -36,13 +47,6 @@ class GetQueue { @@ -36,13 +47,6 @@ class GetQueue {
36 _check(); 47 _check();
37 } 48 }
38 } 49 }
39 -  
40 - Future<T> add<T>(Function job) {  
41 - var completer = Completer<T>();  
42 - _queue.add(_Item(completer, job));  
43 - _check();  
44 - return completer.future;  
45 - }  
46 } 50 }
47 51
48 class _Item { 52 class _Item {
1 name: get 1 name: get
2 description: Open screens/snackbars/dialogs without context, manage states and inject dependencies easily with GetX. 2 description: Open screens/snackbars/dialogs without context, manage states and inject dependencies easily with GetX.
3 -version: 4.3.8 3 +version: 4.5.1
4 homepage: https://github.com/jonataslaw/getx 4 homepage: https://github.com/jonataslaw/getx
5 5
6 environment: 6 environment:
@@ -40,12 +40,16 @@ void main() { @@ -40,12 +40,16 @@ void main() {
40 }); 40 });
41 41
42 test('Get start and delete called just one time', () async { 42 test('Get start and delete called just one time', () async {
43 - Get..put(Controller())..put(Controller()); 43 + Get
  44 + ..put(Controller())
  45 + ..put(Controller());
44 46
45 final controller = Get.find<Controller>(); 47 final controller = Get.find<Controller>();
46 expect(controller.init, 1); 48 expect(controller.init, 1);
47 49
48 - Get..delete<Controller>()..delete<Controller>(); 50 + Get
  51 + ..delete<Controller>()
  52 + ..delete<Controller>();
49 expect(controller.close, 1); 53 expect(controller.close, 1);
50 Get.reset(); 54 Get.reset();
51 }); 55 });
  1 +import 'package:flutter/material.dart';
  2 +import 'package:flutter_test/flutter_test.dart';
  3 +import 'package:get/get.dart';
  4 +
  5 +import '../navigation/utils/wrapper.dart';
  6 +
  7 +void main() {
  8 + testWidgets("Get.defaultDialog smoke test", (tester) async {
  9 + await tester.pumpWidget(
  10 + Wrapper(child: Container()),
  11 + );
  12 +
  13 + await tester.pumpAndSettle();
  14 +
  15 + expect('covid'.tr, 'Corona Virus');
  16 + expect('total_confirmed'.tr, 'Total Confirmed');
  17 + expect('total_deaths'.tr, 'Total Deaths');
  18 +
  19 + Get.updateLocale(Locale('pt', 'BR'));
  20 +
  21 + await tester.pumpAndSettle();
  22 +
  23 + expect('covid'.tr, 'Corona Vírus');
  24 + expect('total_confirmed'.tr, 'Total confirmado');
  25 + expect('total_deaths'.tr, 'Total de mortes');
  26 +
  27 + Get.updateLocale(Locale('en', 'EN'));
  28 +
  29 + await tester.pumpAndSettle();
  30 +
  31 + expect('covid'.tr, 'Corona Virus');
  32 + expect('total_confirmed'.tr, 'Total Confirmed');
  33 + expect('total_deaths'.tr, 'Total Deaths');
  34 + });
  35 +}
@@ -480,59 +480,6 @@ void main() { @@ -480,59 +480,6 @@ void main() {
480 480
481 expect(find.byType(FirstScreen), findsOneWidget); 481 expect(find.byType(FirstScreen), findsOneWidget);
482 }); 482 });
483 -  
484 - testWidgets("Get.snackbar test", (tester) async {  
485 - await tester.pumpWidget(  
486 - GetMaterialApp(  
487 - popGesture: true,  
488 - home: ElevatedButton(  
489 - child: Text('Open Snackbar'),  
490 - onPressed: () {  
491 - Get.snackbar('title', "message", duration: Duration(seconds: 1));  
492 - },  
493 - ),  
494 - ),  
495 - );  
496 -  
497 - expect(Get.isSnackbarOpen, false);  
498 - await tester.tap(find.text('Open Snackbar'));  
499 -  
500 - expect(Get.isSnackbarOpen, true);  
501 - await tester.pump(const Duration(seconds: 1));  
502 - });  
503 -  
504 - testWidgets("Get.rawSnackbar test", (tester) async {  
505 - await tester.pumpWidget(  
506 - Wrapper(  
507 - child: ElevatedButton(  
508 - child: Text('Open Snackbar'),  
509 - onPressed: () {  
510 - Get.rawSnackbar(  
511 - title: 'title',  
512 - message: "message",  
513 - onTap: (_) {  
514 - print('snackbar tapped');  
515 - },  
516 - duration: Duration(seconds: 1),  
517 - shouldIconPulse: true,  
518 - icon: Icon(Icons.alarm),  
519 - showProgressIndicator: true,  
520 - barBlur: null,  
521 - isDismissible: true,  
522 - leftBarIndicatorColor: Colors.amber,  
523 - overlayBlur: 1.0,  
524 - );  
525 - },  
526 - ),  
527 - ),  
528 - );  
529 -  
530 - expect(Get.isSnackbarOpen, false);  
531 - await tester.tap(find.text('Open Snackbar'));  
532 -  
533 - expect(Get.isSnackbarOpen, true);  
534 - await tester.pump(const Duration(seconds: 1));  
535 - });  
536 } 483 }
537 484
538 class FirstScreen extends StatelessWidget { 485 class FirstScreen extends StatelessWidget {