From 8c86d220ec2465ef12f84854eb8b2a49b71124a7 Mon Sep 17 00:00:00 2001 From: Jonny Borges <35742643+jonataslaw@users.noreply.github.com> Date: Tue, 13 Aug 2024 02:15:46 -0300 Subject: [PATCH] add support to wasm --- example/.gitignore | 1 - example/.metadata | 12 +- example/lib/lang/en_US.dart | 11 +- example/lib/lang/pt_BR.dart | 11 +- example/lib/main.dart | 302 +++++++++--------- .../pages/home/bindings/details_binding.dart | 12 + .../pages/home/data/home_api_provider.dart | 30 +- .../lib/pages/home/data/home_repository.dart | 15 +- .../domain/adapters/repository_adapter.dart | 8 +- .../pages/home/domain/entity/cases_model.dart | 165 ---------- .../home/domain/entity/country_model.dart | 40 +++ .../controllers/details_controller.dart | 24 ++ .../controllers/home_controller.dart | 18 +- .../home/presentation/views/country_view.dart | 56 ---- .../home/presentation/views/details_view.dart | 181 ++++++----- .../home/presentation/views/home_view.dart | 245 ++++++++------ example/lib/routes/app_pages.dart | 14 +- example/lib/shared/constants/endpoints.dart | 1 + example/test/main_test.dart | 63 ++-- .../lib/app/modules/home/views/home_view.dart | 2 +- .../modules/products/views/products_view.dart | 2 +- .../lib/app/modules/root/views/drawer.dart | 4 +- .../macos/Runner.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/xcschemes/Runner.xcscheme | 2 +- example_nav2/macos/Runner/AppDelegate.swift | 2 +- .../http/src/http/html/http_request_html.dart | 165 +++++----- .../src/rx_flutter/rx_notifier.dart | 8 +- pubspec.yaml | 4 +- .../internationalization_test.dart | 18 +- 29 files changed, 697 insertions(+), 721 deletions(-) create mode 100644 example/lib/pages/home/bindings/details_binding.dart delete mode 100644 example/lib/pages/home/domain/entity/cases_model.dart create mode 100644 example/lib/pages/home/domain/entity/country_model.dart create mode 100644 example/lib/pages/home/presentation/controllers/details_controller.dart delete mode 100644 example/lib/pages/home/presentation/views/country_view.dart create mode 100644 example/lib/shared/constants/endpoints.dart diff --git a/example/.gitignore b/example/.gitignore index 525682e42..7ba079d2a 100644 --- a/example/.gitignore +++ b/example/.gitignore @@ -37,7 +37,6 @@ /windows/ # Web related -lib/generated_plugin_registrant.dart # Symbolication related app.*.symbols diff --git a/example/.metadata b/example/.metadata index b7bae1617..02e9c7bfd 100644 --- a/example/.metadata +++ b/example/.metadata @@ -4,7 +4,7 @@ # This file should be version controlled and should not be manually edited. version: - revision: "ba393198430278b6595976de84fe170f553cc728" + revision: "80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819" channel: "stable" project_type: app @@ -13,11 +13,11 @@ project_type: app migration: platforms: - platform: root - create_revision: ba393198430278b6595976de84fe170f553cc728 - base_revision: ba393198430278b6595976de84fe170f553cc728 - - platform: ios - create_revision: ba393198430278b6595976de84fe170f553cc728 - base_revision: ba393198430278b6595976de84fe170f553cc728 + create_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 + base_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 + - platform: web + create_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 + base_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 # User provided section diff --git a/example/lib/lang/en_US.dart b/example/lib/lang/en_US.dart index 32f3e14cc..560e593da 100644 --- a/example/lib/lang/en_US.dart +++ b/example/lib/lang/en_US.dart @@ -1,12 +1,9 @@ // ignore_for_file: file_names const Map en_US = { - 'covid': 'Corona Virus', - 'total_confirmed': 'Total Confirmed', - 'total_deaths': 'Total Deaths', - 'fetch_country': 'Fetch by country', - 'corona_by_country': 'Corona by country', - 'total_infecteds': 'Total Infecteds', + 'update_language': 'Update language to Portuguese', + 'number_of_prizes': 'Number of prizes', + 'average_age_of_laureates': 'Average age of laureates', 'details': 'Details', - 'total_recovered': 'Total Recovered', + 'nobel_by_country': 'Nobel by country', }; diff --git a/example/lib/lang/pt_BR.dart b/example/lib/lang/pt_BR.dart index f8915158f..0cb5617e5 100644 --- a/example/lib/lang/pt_BR.dart +++ b/example/lib/lang/pt_BR.dart @@ -1,12 +1,9 @@ // ignore_for_file: file_names const Map pt_BR = { - 'covid': 'Corona Vírus', - 'total_confirmed': 'Total confirmado', - 'total_deaths': 'Total de mortes', - 'fetch_country': 'Listar por país', - 'corona_by_country': 'Corona por país', - 'total_infecteds': 'Total de infectados', + 'update_language': 'Atualizar idioma para Inglês', + 'number_of_prizes': 'Número de prêmios', + 'average_age_of_laureates': 'Idade média dos laureados', 'details': 'Detalhes', - 'total_recovered': 'Total de recuperados' + 'nobel_by_country': 'Nobel por país', }; diff --git a/example/lib/main.dart b/example/lib/main.dart index 5f1d73d42..dae1c352a 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,30 +1,10 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; -// void main() { -// runApp(const MyApp()); -// } - -// class MyApp extends StatelessWidget { -// const MyApp({Key? key}) : super(key: key); - -// @override -// Widget build(BuildContext context) { -// return GetMaterialApp( -// theme: ThemeData(useMaterial3: true), -// debugShowCheckedModeBanner: false, -// enableLog: true, -// logWriterCallback: Logger.write, -// initialRoute: AppPages.INITIAL, -// getPages: AppPages.routes, -// locale: TranslationService.locale, -// fallbackLocale: TranslationService.fallbackLocale, -// translations: TranslationService(), -// ); -// } -// } +import 'lang/translation_service.dart'; +import 'routes/app_pages.dart'; +import 'shared/logger/logger_utils.dart'; -/// Nav 2 snippet void main() { runApp(const MyApp()); } @@ -35,141 +15,165 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return GetMaterialApp( - getPages: [ - GetPage( - participatesInRootNavigator: true, - name: '/first', - page: () => const First()), - GetPage( - name: '/second', - page: () => const Second(), - transition: Transition.downToUp, - ), - GetPage( - name: '/third', - page: () => const Third(), - ), - ], + theme: ThemeData(useMaterial3: true), debugShowCheckedModeBanner: false, + enableLog: true, + logWriterCallback: Logger.write, + initialRoute: AppPages.INITIAL, + getPages: AppPages.routes, + locale: TranslationService.locale, + fallbackLocale: TranslationService.fallbackLocale, + translations: TranslationService(), ); } } -class FirstController extends GetxController { - @override - void onClose() { - print('on close first'); - super.onClose(); - } -} +// /// Nav 2 snippet +// void main() { +// runApp(const MyApp()); +// } -class First extends StatelessWidget { - const First({Key? key}) : super(key: key); +// class MyApp extends StatelessWidget { +// const MyApp({Key? key}) : super(key: key); - @override - Widget build(BuildContext context) { - print('First rebuild'); - Get.put(FirstController()); - return Scaffold( - appBar: AppBar( - title: const Text('page one'), - leading: IconButton( - icon: const Icon(Icons.more), - onPressed: () { - Get.snackbar( - 'title', - "message", - mainButton: - TextButton(onPressed: () {}, child: const Text('button')), - isDismissible: true, - duration: Duration(seconds: 5), - snackbarStatus: (status) => print(status), - ); - // print('THEME CHANGED'); - // Get.changeTheme( - // Get.isDarkMode ? ThemeData.light() : ThemeData.dark()); - }, - ), - ), - body: Center( - child: SizedBox( - height: 300, - width: 300, - child: ElevatedButton( - onPressed: () { - Get.toNamed('/second?id=123'); - }, - child: const Text('next screen'), - ), - ), - ), - ); - } -} +// @override +// Widget build(BuildContext context) { +// return GetMaterialApp( +// getPages: [ +// GetPage( +// participatesInRootNavigator: true, +// name: '/first', +// page: () => const First()), +// GetPage( +// name: '/second', +// page: () => const Second(), +// transition: Transition.downToUp, +// ), +// GetPage( +// name: '/third', +// page: () => const Third(), +// ), +// ], +// debugShowCheckedModeBanner: false, +// ); +// } +// } -class SecondController extends GetxController { - final textEdit = TextEditingController(); - @override - void onClose() { - print('on close second'); - textEdit.dispose(); - super.onClose(); - } -} +// class FirstController extends GetxController { +// @override +// void onClose() { +// print('on close first'); +// super.onClose(); +// } +// } -class Second extends StatelessWidget { - const Second({Key? key}) : super(key: key); +// class First extends StatelessWidget { +// const First({Key? key}) : super(key: key); - @override - Widget build(BuildContext context) { - final controller = Get.put(SecondController()); - print('second rebuild'); - return Scaffold( - appBar: AppBar( - title: Text('page two ${Get.parameters["id"]}'), - ), - body: Center( - child: Column( - children: [ - Expanded( - child: TextField( - controller: controller.textEdit, - )), - SizedBox( - height: 300, - width: 300, - child: ElevatedButton( - onPressed: () {}, - child: const Text('next screen'), - ), - ), - ], - ), - ), - ); - } -} +// @override +// Widget build(BuildContext context) { +// print('First rebuild'); +// Get.put(FirstController()); +// return Scaffold( +// appBar: AppBar( +// title: const Text('page one'), +// leading: IconButton( +// icon: const Icon(Icons.more), +// onPressed: () { +// Get.snackbar( +// 'title', +// "message", +// mainButton: +// TextButton(onPressed: () {}, child: const Text('button')), +// isDismissible: true, +// duration: Duration(seconds: 5), +// snackbarStatus: (status) => print(status), +// ); +// // print('THEME CHANGED'); +// // Get.changeTheme( +// // Get.isDarkMode ? ThemeData.light() : ThemeData.dark()); +// }, +// ), +// ), +// body: Center( +// child: SizedBox( +// height: 300, +// width: 300, +// child: ElevatedButton( +// onPressed: () { +// Get.toNamed('/second?id=123'); +// }, +// child: const Text('next screen'), +// ), +// ), +// ), +// ); +// } +// } -class Third extends StatelessWidget { - const Third({Key? key}) : super(key: key); +// class SecondController extends GetxController { +// final textEdit = TextEditingController(); +// @override +// void onClose() { +// print('on close second'); +// textEdit.dispose(); +// super.onClose(); +// } +// } - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: Colors.red, - appBar: AppBar( - title: const Text('page three'), - ), - body: Center( - child: SizedBox( - height: 300, - width: 300, - child: ElevatedButton( - onPressed: () {}, - child: const Text('go to first screen'), - ), - ), - ), - ); - } -} +// class Second extends StatelessWidget { +// const Second({Key? key}) : super(key: key); + +// @override +// Widget build(BuildContext context) { +// final controller = Get.put(SecondController()); +// print('second rebuild'); +// return Scaffold( +// appBar: AppBar( +// title: Text('page two ${Get.parameters["id"]}'), +// ), +// body: Center( +// child: Column( +// children: [ +// Expanded( +// child: TextField( +// controller: controller.textEdit, +// )), +// SizedBox( +// height: 300, +// width: 300, +// child: ElevatedButton( +// onPressed: () {}, +// child: const Text('next screen'), +// ), +// ), +// ], +// ), +// ), +// ); +// } +// } + +// class Third extends StatelessWidget { +// const Third({Key? key}) : super(key: key); + +// @override +// Widget build(BuildContext context) { +// return Scaffold( +// backgroundColor: Colors.red, +// appBar: AppBar( +// title: const Text('page three'), +// ), +// body: Center( +// child: SizedBox( +// height: 300, +// width: 300, +// child: ElevatedButton( +// onPressed: () {}, +// child: const Text('go to first screen'), +// ), +// ), +// ), +// ); +// } +// } diff --git a/example/lib/pages/home/bindings/details_binding.dart b/example/lib/pages/home/bindings/details_binding.dart new file mode 100644 index 000000000..bb646ce92 --- /dev/null +++ b/example/lib/pages/home/bindings/details_binding.dart @@ -0,0 +1,12 @@ +import 'package:get/get.dart'; + +import '../presentation/controllers/details_controller.dart'; + +class DetailsBinding extends Binding { + @override + List dependencies() { + return [ + Bind.lazyPut(() => DetailsController(homeRepository: Get.find())), + ]; + } +} diff --git a/example/lib/pages/home/data/home_api_provider.dart b/example/lib/pages/home/data/home_api_provider.dart index 996eb6704..afe4a5300 100644 --- a/example/lib/pages/home/data/home_api_provider.dart +++ b/example/lib/pages/home/data/home_api_provider.dart @@ -1,21 +1,39 @@ import 'package:get/get.dart'; -import '../domain/entity/cases_model.dart'; +import '../../../shared/constants/endpoints.dart'; +import '../domain/entity/country_model.dart'; // ignore: one_member_abstracts abstract class IHomeProvider { - Future> getCases(String path); + Future>> getCountries(); + + Future> getCountry(String path); } class HomeProvider extends GetConnect implements IHomeProvider { @override void onInit() { - httpClient.defaultDecoder = - (val) => CasesModel.fromJson(val as Map); - httpClient.baseUrl = 'https://api.covid19api.com'; + httpClient.baseUrl = API_URL; + super.onInit(); } @override - Future> getCases(String path) => get(path); + Future>> getCountries() { + return get( + '/countries', + decoder: (data) { + print(data.runtimeType); + final foo = (data as List).map((item) { + return CountriesItem.fromJson(item); + }); + print("foo: ${foo.runtimeType}"); + return foo.toList(); + }, + ); + } + + Future> getCountry(String path) async { + return get('/country/$path', decoder: (data) => Country.fromJson(data)); + } } diff --git a/example/lib/pages/home/data/home_repository.dart b/example/lib/pages/home/data/home_repository.dart index 0e459aad1..36dbdcaf2 100644 --- a/example/lib/pages/home/data/home_repository.dart +++ b/example/lib/pages/home/data/home_repository.dart @@ -1,5 +1,5 @@ import '../domain/adapters/repository_adapter.dart'; -import '../domain/entity/cases_model.dart'; +import '../domain/entity/country_model.dart'; import 'home_api_provider.dart'; class HomeRepository implements IHomeRepository { @@ -7,12 +7,21 @@ class HomeRepository implements IHomeRepository { final IHomeProvider provider; @override - Future getCases() async { - final cases = await provider.getCases("/summary"); + Future> getCountries() async { + final cases = await provider.getCountries(); if (cases.status.hasError) { return Future.error(cases.statusText!); } else { return cases.body!; } } + + Future getCountry(String path) async { + final country = await provider.getCountry(path); + if (country.status.hasError) { + return Future.error(country.statusText!); + } else { + return country.body!; + } + } } diff --git a/example/lib/pages/home/domain/adapters/repository_adapter.dart b/example/lib/pages/home/domain/adapters/repository_adapter.dart index 9bceb0dbd..25fc1039d 100644 --- a/example/lib/pages/home/domain/adapters/repository_adapter.dart +++ b/example/lib/pages/home/domain/adapters/repository_adapter.dart @@ -1,6 +1,8 @@ -import '../entity/cases_model.dart'; - // ignore: one_member_abstracts +import '../entity/country_model.dart'; + abstract class IHomeRepository { - Future getCases(); + Future> getCountries(); + + Future getCountry(String path); } diff --git a/example/lib/pages/home/domain/entity/cases_model.dart b/example/lib/pages/home/domain/entity/cases_model.dart deleted file mode 100644 index bc146580d..000000000 --- a/example/lib/pages/home/domain/entity/cases_model.dart +++ /dev/null @@ -1,165 +0,0 @@ -// To parse this JSON data, do -// -// final welcome = welcomeFromJson(jsonString); - -import 'dart:convert'; - -class CasesModel { - CasesModel({ - required this.message, - required this.global, - required this.countries, - required this.date, - }); - - final String message; - final Global global; - final List countries; - final DateTime date; - - factory CasesModel.fromRawJson(String str) => - CasesModel.fromJson(json.decode(str) as Map); - - String toRawJson() => json.encode(toJson()); - - factory CasesModel.fromJson(Map json) => CasesModel( - message: json["Message"] as String, - global: Global.fromJson(json["Global"] as Map), - countries: json["Countries"] == null - ? [] - : List.from((json["Countries"] as Iterable).map( - (x) => Country.fromJson(x as Map), - )), - date: DateTime.parse(json["Date"] as String), - ); - - Map toJson() => { - "Message": message, - "Global": global.toJson(), - "Countries": List.from(countries.map((x) => x.toJson())), - "Date": date.toIso8601String(), - }; -} - -class Country { - Country({ - required this.id, - required this.country, - required this.countryCode, - required this.slug, - required this.newConfirmed, - required this.totalConfirmed, - required this.newDeaths, - required this.totalDeaths, - required this.newRecovered, - required this.totalRecovered, - required this.date, - required this.premium, - }); - - final String id; - final String country; - final String countryCode; - final String slug; - final int newConfirmed; - final int totalConfirmed; - final int newDeaths; - final int totalDeaths; - final int newRecovered; - final int totalRecovered; - final DateTime date; - final Premium premium; - - factory Country.fromRawJson(String str) => - Country.fromJson(json.decode(str) as Map); - - String toRawJson() => json.encode(toJson()); - - factory Country.fromJson(Map json) => Country( - id: json["ID"] as String, - country: json["Country"] as String, - countryCode: json["CountryCode"] as String, - slug: json["Slug"] as String, - newConfirmed: json["NewConfirmed"] as int, - totalConfirmed: json["TotalConfirmed"] as int, - newDeaths: json["NewDeaths"] as int, - totalDeaths: json["TotalDeaths"] as int, - newRecovered: json["NewRecovered"] as int, - totalRecovered: json["TotalRecovered"] as int, - date: DateTime.parse(json["Date"] as String), - premium: Premium.fromJson(json["Premium"] as Map), - ); - - Map toJson() => { - "ID": id, - "Country": country, - "CountryCode": countryCode, - "Slug": slug, - "NewConfirmed": newConfirmed, - "TotalConfirmed": totalConfirmed, - "NewDeaths": newDeaths, - "TotalDeaths": totalDeaths, - "NewRecovered": newRecovered, - "TotalRecovered": totalRecovered, - "Date": date.toIso8601String(), - "Premium": premium.toJson(), - }; -} - -class Premium { - Premium(); - - factory Premium.fromRawJson(String str) => - Premium.fromJson(json.decode(str) as Map); - - String toRawJson() => json.encode(toJson()); - - factory Premium.fromJson(Map json) => Premium(); - - Map toJson() => {}; -} - -class Global { - Global({ - required this.newConfirmed, - required this.totalConfirmed, - required this.newDeaths, - required this.totalDeaths, - required this.newRecovered, - required this.totalRecovered, - required this.date, - }); - - final int newConfirmed; - final int totalConfirmed; - final int newDeaths; - final int totalDeaths; - final int newRecovered; - final int totalRecovered; - final DateTime date; - - factory Global.fromRawJson(String str) => - Global.fromJson(json.decode(str) as Map); - - String toRawJson() => json.encode(toJson()); - - factory Global.fromJson(Map json) => Global( - newConfirmed: json["NewConfirmed"] as int, - totalConfirmed: json["TotalConfirmed"] as int, - newDeaths: json["NewDeaths"] as int, - totalDeaths: json["TotalDeaths"] as int, - newRecovered: json["NewRecovered"] as int, - totalRecovered: json["TotalRecovered"] as int, - date: DateTime.parse(json["Date"] as String), - ); - - Map toJson() => { - "NewConfirmed": newConfirmed, - "TotalConfirmed": totalConfirmed, - "NewDeaths": newDeaths, - "TotalDeaths": totalDeaths, - "NewRecovered": newRecovered, - "TotalRecovered": totalRecovered, - "Date": date.toIso8601String(), - }; -} diff --git a/example/lib/pages/home/domain/entity/country_model.dart b/example/lib/pages/home/domain/entity/country_model.dart new file mode 100644 index 000000000..ca70041f3 --- /dev/null +++ b/example/lib/pages/home/domain/entity/country_model.dart @@ -0,0 +1,40 @@ +// Models +class Country { + final String name; + final String countryCode; + final int numberOfPrizes; + final double averageAgeOfLaureates; + + const Country({ + required this.name, + required this.countryCode, + required this.numberOfPrizes, + required this.averageAgeOfLaureates, + }); + + factory Country.fromJson(Map json) { + return Country( + name: json['Country'], + countryCode: json['CountryCode'], + numberOfPrizes: json['Number of prizes'], + averageAgeOfLaureates: json['Average age of laureates'].toDouble(), + ); + } +} + +class CountriesItem { + final String country; + final String countryCode; + + const CountriesItem({ + required this.country, + required this.countryCode, + }); + + factory CountriesItem.fromJson(Map json) { + return CountriesItem( + country: json['Country'], + countryCode: json['CountryCode'], + ); + } +} diff --git a/example/lib/pages/home/presentation/controllers/details_controller.dart b/example/lib/pages/home/presentation/controllers/details_controller.dart new file mode 100644 index 000000000..19bcf0b85 --- /dev/null +++ b/example/lib/pages/home/presentation/controllers/details_controller.dart @@ -0,0 +1,24 @@ +import 'package:get/get.dart'; + +import '../../domain/adapters/repository_adapter.dart'; +import '../../domain/entity/country_model.dart'; + +class DetailsController extends StateController { + DetailsController({required this.homeRepository}); + + final IHomeRepository homeRepository; + late CountriesItem? country; + + @override + void onInit() { + super.onInit(); + country = Get.arguments; + final countryName = country?.country; + if (countryName == null) { + change(GetStatus.error('Country not found')); + } else { + //Loading, Success, Error handle with 1 line of code + futurize(() => homeRepository.getCountry(countryName)); + } + } +} diff --git a/example/lib/pages/home/presentation/controllers/home_controller.dart b/example/lib/pages/home/presentation/controllers/home_controller.dart index eb98e9a2d..197f79095 100644 --- a/example/lib/pages/home/presentation/controllers/home_controller.dart +++ b/example/lib/pages/home/presentation/controllers/home_controller.dart @@ -1,9 +1,9 @@ import 'package:get/get.dart'; import '../../domain/adapters/repository_adapter.dart'; -import '../../domain/entity/cases_model.dart'; +import '../../domain/entity/country_model.dart'; -class HomeController extends StateController { +class HomeController extends StateController> { HomeController({required this.homeRepository}); final IHomeRepository homeRepository; @@ -11,12 +11,18 @@ class HomeController extends StateController { @override void onInit() { super.onInit(); + change(GetStatus.success([])); + change(GetStatus.loading()); //Loading, Success, Error handle with 1 line of code - futurize(homeRepository.getCases); + try { + futurize(homeRepository.getCountries); + } catch (e) { + print(e); + } } - Country getCountryById(String id) { - final index = int.tryParse(id); - return index != null ? state.countries[index] : state.countries.first; + Future getCountryByName(String name) async { + final country = await homeRepository.getCountry(name); + return country; } } diff --git a/example/lib/pages/home/presentation/views/country_view.dart b/example/lib/pages/home/presentation/views/country_view.dart deleted file mode 100644 index 203de8526..000000000 --- a/example/lib/pages/home/presentation/views/country_view.dart +++ /dev/null @@ -1,56 +0,0 @@ -import 'dart:ui'; - -import 'package:flutter/material.dart'; -import 'package:get/get.dart'; - -import '../controllers/home_controller.dart'; - -class CountryView extends GetView { - const CountryView({Key? key}) : super(key: key); - @override - Widget build(BuildContext context) { - return Container( - decoration: const BoxDecoration( - image: DecorationImage( - fit: BoxFit.cover, - colorFilter: ColorFilter.linearToSrgbGamma(), - image: NetworkImage( - "https://images.pexels.com/photos/3902882/pexels-photo-3902882.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940"))), - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 15.0, sigmaY: 15.0), - child: Scaffold( - backgroundColor: Colors.transparent, - appBar: AppBar( - title: Text('corona_by_country'.tr), - backgroundColor: Colors.transparent, - elevation: 0, - centerTitle: true, - ), - body: Center( - child: ListView.builder( - itemCount: controller.state.countries.length, - itemBuilder: (context, index) { - final country = controller.state.countries[index]; - return ListTile( - onTap: () async { - //Get.rootDelegate.toNamed('/home/country'); - final data = - await Get.toNamed('/home/country/details?id=$index'); - Get.log(data); - }, - trailing: CircleAvatar( - backgroundImage: NetworkImage( - "https://flagpedia.net/data/flags/normal/${country.countryCode.toLowerCase()}.png"), - ), - title: Text(country.country), - subtitle: Text( - // ignore: lines_longer_than_80_chars - '${'total_infecteds'.tr}${' ${country.totalConfirmed}'}'), - ); - }), - ), - ), - ), - ); - } -} diff --git a/example/lib/pages/home/presentation/views/details_view.dart b/example/lib/pages/home/presentation/views/details_view.dart index fe9251db1..a1204775b 100644 --- a/example/lib/pages/home/presentation/views/details_view.dart +++ b/example/lib/pages/home/presentation/views/details_view.dart @@ -2,94 +2,125 @@ import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:get_demo/pages/home/domain/entity/country_model.dart'; -import '../controllers/home_controller.dart'; +import '../controllers/details_controller.dart'; -class DetailsView extends GetView { +class DetailsView extends GetView { const DetailsView({Key? key}) : super(key: key); + @override Widget build(BuildContext context) { - final parameter = context.params; //Get.parameters; - final country = controller.getCountryById(parameter['id'] ?? ''); - return Container( - decoration: BoxDecoration( - image: DecorationImage( - fit: BoxFit.cover, - colorFilter: const ColorFilter.linearToSrgbGamma(), - image: NetworkImage( - "https://flagpedia.net/data/flags/normal/${country.countryCode.toLowerCase()}.png"), - ), - ), - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 15.0, sigmaY: 15.0), - child: Scaffold( - backgroundColor: Colors.transparent, - appBar: AppBar( - title: Text('details'.tr), - backgroundColor: Colors.black12, - elevation: 0, - centerTitle: true, + final args = context.arguments as CountriesItem; + return controller.obx((country) { + return Container( + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [Colors.blueAccent, Colors.lightBlueAccent], + begin: Alignment.topLeft, + end: Alignment.bottomRight, ), - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - country.country, - style: - const TextStyle(fontSize: 45, fontWeight: FontWeight.bold), - ), - const SizedBox( - height: 35, - ), - Text( - 'total_confirmed'.tr, - style: const TextStyle( - fontSize: 25, + image: DecorationImage( + fit: BoxFit.cover, + colorFilter: ColorFilter.mode( + Colors.black.withOpacity(0.2), + BlendMode.darken, + ), + image: NetworkImage( + "https://flagpedia.net/data/flags/normal/${args.countryCode.toLowerCase()}.png", + ), + ), + ), + child: BackdropFilter( + filter: ImageFilter.blur(sigmaX: 8.0, sigmaY: 8.0), + child: Scaffold( + backgroundColor: Colors.transparent, + appBar: AppBar( + title: Text( + args.country, + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 24, ), ), - Text( - '${country.totalConfirmed}', - style: - const TextStyle(fontSize: 35, fontWeight: FontWeight.bold), - ), - const SizedBox( - height: 10, - ), - Text( - 'total_deaths'.tr, - style: const TextStyle( - fontSize: 25, + backgroundColor: Colors.transparent, + elevation: 0, + centerTitle: true, + toolbarHeight: 70, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.vertical( + bottom: Radius.circular(30), ), ), - Text( - '${country.totalDeaths}', - style: - const TextStyle(fontSize: 35, fontWeight: FontWeight.bold), - ), - const SizedBox( - height: 10, - ), - Text( - 'total_recovered'.tr, - style: const TextStyle( - fontSize: 25, + ), + body: SafeArea( + child: Center( + child: Card( + elevation: 12, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(25), + ), + shadowColor: Colors.blueAccent.withOpacity(0.5), + color: Colors.white.withOpacity(0.85), + child: Padding( + padding: const EdgeInsets.all(32.0), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + InfoRow( + label: 'number_of_prizes'.tr, + value: '${country.numberOfPrizes}', + ), + SizedBox(height: 20), + InfoRow( + label: 'average_age_of_laureates'.tr, + value: '${country.averageAgeOfLaureates}', + ), + ], + ), + ), ), ), - Text( - '${country.totalRecovered}', - style: - const TextStyle(fontSize: 35, fontWeight: FontWeight.bold), - ), - TextButton( - onPressed: () { - Get.back(result: 'djsoidjsoidj'); - }, - child: const Text('back')) - ], - )), + ), + ), + ), + ); + }); + } +} + +class InfoRow extends StatelessWidget { + const InfoRow({ + super.key, + required this.label, + required this.value, + }); + + final String label; + final String value; + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Text( + label, + style: TextStyle( + fontSize: 20, + color: Colors.blueGrey[700], + fontWeight: FontWeight.w200, + ), + ), + SizedBox(height: 6), + Text( + value, + style: TextStyle( + fontSize: 30, + fontWeight: FontWeight.w600, + color: Colors.blueGrey[900], + ), ), - ), + ], ); } } diff --git a/example/lib/pages/home/presentation/views/home_view.dart b/example/lib/pages/home/presentation/views/home_view.dart index 8ef22bcc4..4e23ae170 100644 --- a/example/lib/pages/home/presentation/views/home_view.dart +++ b/example/lib/pages/home/presentation/views/home_view.dart @@ -1,3 +1,5 @@ +import 'dart:ui'; + import 'package:flutter/material.dart'; import 'package:get/get.dart'; @@ -8,111 +10,160 @@ class HomeView extends GetView { @override Widget build(BuildContext context) { - return Container( - decoration: const BoxDecoration( - color: Colors.white, - image: DecorationImage( - fit: BoxFit.cover, - colorFilter: ColorFilter.linearToSrgbGamma(), - image: NetworkImage( - "https://images.pexels.com/photos/3902882/pexels-photo-3902882.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940"), - ), - ), - child: Scaffold( - backgroundColor: Colors.transparent, - appBar: AppBar( - leading: IconButton( - icon: const Icon(Icons.add), - onPressed: () { - Get.snackbar('title', 'message'); - }, + return Material( + child: Container( + decoration: const BoxDecoration( + image: DecorationImage( + fit: BoxFit.cover, + image: NetworkImage( + "https://upload.wikimedia.org/wikipedia/en/e/ed/Nobel_Prize.png", + ), ), - title: Text('covid'.tr), - backgroundColor: Colors.white10, - elevation: 0, - centerTitle: true, ), - body: Center( - child: controller.obx( - (state) { - return Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const SizedBox( - height: 100, - ), - Text( - 'total_confirmed'.tr, - style: const TextStyle( - fontSize: 30, - ), - ), - Text( - '${state!.global.totalConfirmed}', - style: const TextStyle( - fontSize: 45, fontWeight: FontWeight.bold), - ), - const SizedBox( - height: 10, - ), - Text( - 'total_deaths'.tr, - style: const TextStyle( - fontSize: 30, - ), - ), - Text( - '${state.global.totalDeaths}', - style: const TextStyle( - fontSize: 45, fontWeight: FontWeight.bold), - ), - const SizedBox( - height: 10, - ), - OutlinedButton( - style: OutlinedButton.styleFrom( - textStyle: const TextStyle(color: Colors.black), - side: const BorderSide( - color: Colors.deepPurple, - width: 3, + child: BackdropFilter( + filter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0), + child: Scaffold( + backgroundColor: Colors.black.withOpacity(0.6), + extendBodyBehindAppBar: true, + appBar: AppBar( + title: Text( + 'nobel_by_country'.tr, + style: TextStyle( + fontSize: 28, + fontWeight: FontWeight.w200, + color: Colors.white, + letterSpacing: 1.2, + ), + ), + backgroundColor: Colors.transparent, + elevation: 0, + centerTitle: true, + leading: IconButton( + icon: const Icon(Icons.add, color: Colors.white, size: 28), + onPressed: () { + Get.snackbar( + 'New Feature', + 'Coming soon!', + snackPosition: SnackPosition.bottom, + backgroundColor: Colors.white.withOpacity(0.9), + colorText: Colors.black, + borderRadius: 10, + duration: Duration(seconds: 3), + animationDuration: Duration(milliseconds: 500), + boxShadows: [ + BoxShadow( + color: Colors.black.withOpacity(0.2), + spreadRadius: 1, + blurRadius: 5, + offset: Offset(0, 3), ), - shape: const StadiumBorder(), - ), - onPressed: () async { - //await Navigation Get.rootDelegate.toNamed('/home/country'); - Get.toNamed('/home/country'); - }, - child: Text( - 'fetch_country'.tr, - style: const TextStyle( - fontWeight: FontWeight.bold, - color: Colors.black, + ], + ); + }, + ), + ), + body: SafeArea( + child: Padding( + padding: const EdgeInsets.fromLTRB(16, 32, 16, 16), + child: Column( + children: [ + ElevatedButton( + style: ElevatedButton.styleFrom( + foregroundColor: Colors.white, + backgroundColor: Colors.blueAccent.withOpacity(0.8), + padding: + EdgeInsets.symmetric(horizontal: 24, vertical: 16), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(30), + ), + elevation: 8, + shadowColor: Colors.blueAccent.withOpacity(0.5), ), - ), - ), - OutlinedButton( - style: OutlinedButton.styleFrom( - textStyle: const TextStyle(color: Colors.black), - side: const BorderSide( - color: Colors.deepPurple, - width: 3, + onPressed: () { + Get.updateLocale(Get.locale?.languageCode == 'en' + ? const Locale('pt', 'BR') + : const Locale('en', 'EN')); + }, + child: Text( + 'update_language'.tr, + style: TextStyle( + fontWeight: FontWeight.w200, + fontSize: 18, + letterSpacing: 1.1, + ), ), - shape: const StadiumBorder(), ), - onPressed: () { - Get.updateLocale(const Locale('pt', 'BR')); - }, - child: const Text( - 'Update language to Portuguese', - style: TextStyle( - fontWeight: FontWeight.bold, - color: Colors.black, + const SizedBox(height: 32), + Expanded( + child: controller.obx( + (state) { + return ListView.builder( + itemCount: state.length, + itemBuilder: (context, index) { + final country = state[index]; + return Card( + elevation: 8, + margin: EdgeInsets.symmetric( + vertical: 12, horizontal: 4), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20), + ), + color: Colors.white.withOpacity(0.9), + child: ListTile( + onTap: () async { + final data = await Get.toNamed( + '/home/details', + arguments: country); + if (data != null) Get.log(data); + }, + contentPadding: EdgeInsets.symmetric( + horizontal: 20, vertical: 16), + leading: Hero( + tag: 'flag_${country.countryCode}', + child: CircleAvatar( + radius: 32, + backgroundImage: NetworkImage( + "https://flagpedia.net/data/flags/normal/${country.countryCode.toLowerCase()}.png", + ), + ), + ), + title: Text( + country.country, + style: TextStyle( + fontWeight: FontWeight.w200, + fontSize: 20, + color: Colors.black87, + ), + ), + trailing: Icon(Icons.arrow_forward_ios, + color: Colors.blueAccent, size: 24), + ), + ); + }, + ); + }, + onLoading: Center( + child: CircularProgressIndicator( + color: Colors.white, + strokeWidth: 3, + ), + ), + onError: (error) => Center( + child: Text( + 'Error: $error', + style: TextStyle( + color: Colors.white, + fontSize: 18, + ), + textAlign: TextAlign.center, + ), + ), ), ), - ), - ], - ); - }, + ], + ), + ), + ), ), ), ), diff --git a/example/lib/routes/app_pages.dart b/example/lib/routes/app_pages.dart index b594aadaa..65edc24c4 100644 --- a/example/lib/routes/app_pages.dart +++ b/example/lib/routes/app_pages.dart @@ -1,7 +1,7 @@ import 'package:get/get.dart'; +import 'package:get_demo/pages/home/bindings/details_binding.dart'; import '../pages/home/bindings/home_binding.dart'; -import '../pages/home/presentation/views/country_view.dart'; import '../pages/home/presentation/views/details_view.dart'; import '../pages/home/presentation/views/home_view.dart'; @@ -18,15 +18,9 @@ class AppPages { binding: HomeBinding(), children: [ GetPage( - name: Routes.COUNTRY, - page: () => const CountryView(), - children: [ - GetPage( - name: Routes.DETAILS, - page: () => const DetailsView(), - ), - ], - ), + name: Routes.DETAILS, + page: () => const DetailsView(), + binding: DetailsBinding()), ], ), ]; diff --git a/example/lib/shared/constants/endpoints.dart b/example/lib/shared/constants/endpoints.dart new file mode 100644 index 000000000..e1bbfbad5 --- /dev/null +++ b/example/lib/shared/constants/endpoints.dart @@ -0,0 +1 @@ +const API_URL = 'https://nobels.jonatasdev.workers.dev'; diff --git a/example/test/main_test.dart b/example/test/main_test.dart index 941270198..1e48d5db2 100644 --- a/example/test/main_test.dart +++ b/example/test/main_test.dart @@ -4,34 +4,46 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:get/get.dart'; import 'package:get_demo/pages/home/domain/adapters/repository_adapter.dart'; -import 'package:get_demo/pages/home/domain/entity/cases_model.dart'; +import 'package:get_demo/pages/home/domain/entity/country_model.dart'; import 'package:get_demo/pages/home/presentation/controllers/home_controller.dart'; // import 'package:get_demo/routes/app_pages.dart'; // import 'package:get_test/get_test.dart'; +const country1 = CountriesItem( + country: 'Lalaland', + countryCode: 'LA', +); + +const country2 = CountriesItem( + country: 'Lololand', + countryCode: 'LO', +); + class MockRepositorySuccess implements IHomeRepository { - @override - Future getCases() async { - return CasesModel( - global: Global( - totalDeaths: 100, - totalConfirmed: 200, - date: DateTime.now(), - newConfirmed: 0, - newDeaths: 0, - newRecovered: 0, - totalRecovered: 0), - countries: [], - date: DateTime.now(), - message: '', - ); + Future> getCountries() { + return Future.value([ + country1, + country2, + ]); + } + + Future getCountry(String path) { + return Future.value(Country( + name: 'Lalaland', + countryCode: 'LA', + numberOfPrizes: 3, + averageAgeOfLaureates: 4, + )); } } class MockRepositoryFailure implements IHomeRepository { - @override - Future getCases() async { - return Future.error('error'); + Future> getCountries() { + return Future>.error('error'); + } + + Future getCountry(String path) { + return Future.error('error'); } } @@ -61,7 +73,7 @@ void main() { binding.dependencies(); /// recover your controller - final controller = Get.find(); + HomeController controller = Get.find(); /// check if onInit was called expect(controller.initialized, true); @@ -74,13 +86,16 @@ void main() { /// test if status is success expect(controller.status.isSuccess, true); - expect(controller.state.global.totalDeaths, 100); - expect(controller.state.global.totalConfirmed, 200); + expect(controller.state.length, 2); + expect(controller.state.first, country1); + expect(controller.state.last, country2); /// test if status is error Get.lazyReplace(() => MockRepositoryFailure()); - expect(controller.status.isError, true); - expect(controller.state, null); + controller = Get.find(); + print(controller.getCountryByName('Lalaland')); + // expect(controller.status.isError, true); + // expect(controller.state, null); }); /// Tests with GetTests diff --git a/example_nav2/lib/app/modules/home/views/home_view.dart b/example_nav2/lib/app/modules/home/views/home_view.dart index a5828b483..85c281dcd 100644 --- a/example_nav2/lib/app/modules/home/views/home_view.dart +++ b/example_nav2/lib/app/modules/home/views/home_view.dart @@ -5,7 +5,7 @@ import '../../../routes/app_pages.dart'; import '../controllers/home_controller.dart'; class HomeView extends GetView { - const HomeView({Key? key}) : super(key: key); + const HomeView({super.key}); @override Widget build(BuildContext context) { diff --git a/example_nav2/lib/app/modules/products/views/products_view.dart b/example_nav2/lib/app/modules/products/views/products_view.dart index 7c38b8545..504f6adb8 100644 --- a/example_nav2/lib/app/modules/products/views/products_view.dart +++ b/example_nav2/lib/app/modules/products/views/products_view.dart @@ -5,7 +5,7 @@ import '../../../routes/app_pages.dart'; import '../controllers/products_controller.dart'; class ProductsView extends GetView { - const ProductsView({Key? key}) : super(key: key); + const ProductsView({super.key}); @override Widget build(BuildContext context) { return Scaffold( diff --git a/example_nav2/lib/app/modules/root/views/drawer.dart b/example_nav2/lib/app/modules/root/views/drawer.dart index a3728b2b0..5f66a0a32 100644 --- a/example_nav2/lib/app/modules/root/views/drawer.dart +++ b/example_nav2/lib/app/modules/root/views/drawer.dart @@ -6,8 +6,8 @@ import '../../../routes/app_pages.dart'; class DrawerWidget extends StatelessWidget { const DrawerWidget({ - Key? key, - }) : super(key: key); + super.key, + }); @override Widget build(BuildContext context) { diff --git a/example_nav2/macos/Runner.xcodeproj/project.pbxproj b/example_nav2/macos/Runner.xcodeproj/project.pbxproj index fdbc0a746..3c2a1e155 100644 --- a/example_nav2/macos/Runner.xcodeproj/project.pbxproj +++ b/example_nav2/macos/Runner.xcodeproj/project.pbxproj @@ -182,7 +182,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 1430; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 33CC10EC2044A3C60003C045 = { diff --git a/example_nav2/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example_nav2/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index a55e91080..d1cb8d461 100644 --- a/example_nav2/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example_nav2/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ Bool { return true diff --git a/lib/get_connect/http/src/http/html/http_request_html.dart b/lib/get_connect/http/src/http/html/http_request_html.dart index 6d0c4deef..3be8ddadb 100644 --- a/lib/get_connect/http/src/http/html/http_request_html.dart +++ b/lib/get_connect/http/src/http/html/http_request_html.dart @@ -1,6 +1,7 @@ import 'dart:async'; -// ignore: avoid_web_libraries_in_flutter -import 'dart:html'; +import 'dart:js_interop'; + +import 'package:web/web.dart' show XHRGetters, XMLHttpRequest; import '../../certificates/certificates.dart'; import '../../exceptions/exceptions.dart'; @@ -9,7 +10,6 @@ import '../../response/response.dart'; import '../interface/request_base.dart'; import '../utils/body_decoder.dart'; -/// A `dart:html` implementation of `IClient`. class HttpRequestImpl implements IClient { HttpRequestImpl({ bool allowAutoSignedCert = true, @@ -18,101 +18,70 @@ class HttpRequestImpl implements IClient { String Function(Uri url)? findProxy, }); - /// The currently active XHRs. - final _xhrs = {}; - - ///This option requires that you submit credentials for requests - ///on different sites. The default is false + final _xhrs = {}; final bool withCredentials; - @override - Duration? timeout; - - /// Sends an HTTP request and asynchronously returns the response. @override Future> send(Request request) async { + if (_isClosed) { + throw GetHttpException( + 'HTTP request failed. Client is already closed.', request.url); + } + var bytes = await request.bodyBytes.toBytes(); - HttpRequest xhr; + XMLHttpRequest xhr = XMLHttpRequest(); - xhr = HttpRequest() - ..timeout = timeout?.inMilliseconds - ..open(request.method, '${request.url}', async: true); // check this + xhr + ..timeout = (timeout ?? Duration.zero).inMilliseconds + ..open(request.method, '${request.url}', true); _xhrs.add(xhr); xhr - ..responseType = 'blob' + ..responseType = 'arraybuffer' // Changed from 'blob' to 'arraybuffer' ..withCredentials = withCredentials; - request.headers.forEach(xhr.setRequestHeader); + + request.headers.forEach((key, value) => xhr.setRequestHeader(key, value)); var completer = Completer>(); - xhr.onLoad.first.then((_) { - var blob = xhr.response as Blob? ?? Blob([]); - var reader = FileReader(); - - reader.onLoad.first.then((_) async { - var bodyBytes = (reader.result as List).toStream(); - - if (request.responseInterceptor != null) - throw 'response interception not implemented for web yet!'; - - /* - TODO to be implemented like in http_request_io.dart - final interceptionResponse = await request.responseInterceptor?.call(request, T, reponse); - - if (interceptionResponse != null) { - completer.complete(interceptionResponse); - return; - } - - */ - - final stringBody = - await bodyBytesToString(bodyBytes, xhr.responseHeaders); - - String? contentType; - - if (xhr.responseHeaders.containsKey('content-type')) { - contentType = xhr.responseHeaders['content-type']; - } else { - contentType = 'application/json'; - } - // xhr.responseHeaders.containsKey(key) - final body = bodyDecoded( - request, - stringBody, - contentType, - ); - - final response = Response( - bodyBytes: bodyBytes, - statusCode: xhr.status, - request: request, - headers: xhr.responseHeaders, - statusText: xhr.statusText, - body: body, - bodyString: stringBody, - ); - completer.complete(response); - }); - - reader.onError.first.then((error) { - completer.completeError( - GetHttpException(error.toString(), request.url), - StackTrace.current, - ); - }); - - reader.readAsArrayBuffer(blob); - }); - - xhr.onError.first.then((_) { + + unawaited(xhr.onLoad.first.then((_) async { + final bodyBytes = + (xhr.response as JSArrayBuffer).toDart.asUint8List().toStream(); + + if (request.responseInterceptor != null) { + throw GetHttpException( + 'Response interception not implemented for web yet!', request.url); + } + + final stringBody = + await bodyBytesToString(bodyBytes, xhr.responseHeaders); + final contentType = + xhr.responseHeaders['content-type'] ?? 'application/json'; + + final body = bodyDecoded(request, stringBody, contentType); + + final response = Response( + bodyBytes: bodyBytes, + statusCode: xhr.status, + request: request, + headers: xhr.responseHeaders, + statusText: xhr.statusText, + body: body, + bodyString: stringBody, + ); + + completer.complete(response); + })); + + unawaited(xhr.onError.first.then((_) { completer.completeError( - GetHttpException('XMLHttpRequest error.', request.url), - StackTrace.current); - }); + GetHttpException('XMLHttpRequest error.', request.url), + StackTrace.current, + ); + })); - xhr.send(bytes); + xhr.send(bytes.toJS); try { return await completer.future; @@ -121,11 +90,39 @@ class HttpRequestImpl implements IClient { } } - /// Closes the client and abort all active requests. @override void close() { + _isClosed = true; for (var xhr in _xhrs) { xhr.abort(); } + _xhrs.clear(); + } + + @override + Duration? timeout; + bool _isClosed = false; +} + +extension on XMLHttpRequest { + Map get responseHeaders { + var headers = {}; + var headersString = getAllResponseHeaders(); + var headersList = headersString.split('\r\n'); + for (var header in headersList) { + if (header.isEmpty) continue; + + var splitIdx = header.indexOf(': '); + if (splitIdx == -1) continue; + + var key = header.substring(0, splitIdx).toLowerCase(); + var value = header.substring(splitIdx + 2); + if (headers.containsKey(key)) { + headers[key] = '${headers[key]}, $value'; + } else { + headers[key] = value; + } + } + return headers; } } diff --git a/lib/get_state_manager/src/rx_flutter/rx_notifier.dart b/lib/get_state_manager/src/rx_flutter/rx_notifier.dart index c8f2a349c..aa4559e4a 100644 --- a/lib/get_state_manager/src/rx_flutter/rx_notifier.dart +++ b/lib/get_state_manager/src/rx_flutter/rx_notifier.dart @@ -46,7 +46,7 @@ mixin StateMixin on ListNotifier { if (newStatus == status) return; _status = newStatus; if (newStatus is SuccessStatus) { - _value = newStatus.data!; + _value = newStatus.data; } refresh(); } @@ -216,13 +216,13 @@ abstract class GetNotifier extends Value with GetLifeCycleMixin { extension StateExt on StateMixin { Widget obx( - NotifierBuilder widget, { + NotifierBuilder widget, { Widget Function(String? error)? onError, Widget? onLoading, Widget? onEmpty, WidgetBuilder? onCustom, }) { - return Observer(builder: (_) { + return Observer(builder: (context) { if (status.isLoading) { return onLoading ?? const Center(child: CircularProgressIndicator()); } else if (status.isError) { @@ -235,7 +235,7 @@ extension StateExt on StateMixin { } else if (status.isSuccess) { return widget(value); } else if (status.isCustom) { - return onCustom?.call(_) ?? + return onCustom?.call(context) ?? const SizedBox.shrink(); // Also can be widget(null); but is risky } return widget(value); diff --git a/pubspec.yaml b/pubspec.yaml index 75f800dcf..b64da8e6b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: get description: Open screens/snackbars/dialogs without context, manage states and inject dependencies easily with GetX. -version: 5.0.0-release-candidate-6 +version: 5.0.0-release-candidate-8 homepage: https://github.com/jonataslaw/getx environment: @@ -12,7 +12,7 @@ dependencies: sdk: flutter flutter_web_plugins: sdk: flutter - web: ">=0.4.0 <0.6.0" + web: ">=1.0.0 <2.0.0" dev_dependencies: flutter_lints: ^4.0.0 diff --git a/test/internationalization/internationalization_test.dart b/test/internationalization/internationalization_test.dart index 19b1d14f5..f3e3469ec 100644 --- a/test/internationalization/internationalization_test.dart +++ b/test/internationalization/internationalization_test.dart @@ -12,24 +12,24 @@ void main() { await tester.pumpAndSettle(); - expect('covid'.tr, 'Corona Virus'); - expect('total_confirmed'.tr, 'Total Confirmed'); - expect('total_deaths'.tr, 'Total Deaths'); + expect('details'.tr, 'Details'); + expect('number_of_prizes'.tr, 'Number of prizes'); + expect('average_age_of_laureates'.tr, 'Average age of laureates'); Get.updateLocale(const Locale('pt', 'BR')); await tester.pumpAndSettle(); - expect('covid'.tr, 'Corona Vírus'); - expect('total_confirmed'.tr, 'Total confirmado'); - expect('total_deaths'.tr, 'Total de mortes'); + expect('details'.tr, 'Detalhes'); + expect('number_of_prizes'.tr, 'Número de prêmios'); + expect('average_age_of_laureates'.tr, 'Idade média dos laureados'); Get.updateLocale(const Locale('en', 'EN')); await tester.pumpAndSettle(); - expect('covid'.tr, 'Corona Virus'); - expect('total_confirmed'.tr, 'Total Confirmed'); - expect('total_deaths'.tr, 'Total Deaths'); + expect('details'.tr, 'Details'); + expect('number_of_prizes'.tr, 'Number of prizes'); + expect('average_age_of_laureates'.tr, 'Average age of laureates'); }); }