Showing
26 changed files
with
283 additions
and
210 deletions
@@ -96,7 +96,7 @@ Get.put<S>( | @@ -96,7 +96,7 @@ Get.put<S>( | ||
96 | bool overrideAbstract = false, | 96 | bool overrideAbstract = false, |
97 | 97 | ||
98 | // optional: allows you to create the dependency using function instead of the dependency itself. | 98 | // optional: allows you to create the dependency using function instead of the dependency itself. |
99 | - FcBuilderFunc<S> builder, | 99 | + InstanceBuilderCallback<S> builder, |
100 | ) | 100 | ) |
101 | ``` | 101 | ``` |
102 | 102 | ||
@@ -106,7 +106,7 @@ Get.put<S>( | @@ -106,7 +106,7 @@ Get.put<S>( | ||
106 | Get.lazyPut<S>( | 106 | Get.lazyPut<S>( |
107 | // mandatory: a method that will be executed when your class is called for the first time | 107 | // mandatory: a method that will be executed when your class is called for the first time |
108 | // Example: Get.lazyPut<Controller>( () => Controller() ) | 108 | // Example: Get.lazyPut<Controller>( () => Controller() ) |
109 | - FcBuilderFunc builder, | 109 | + InstanceBuilderCallback builder, |
110 | 110 | ||
111 | // optional: same as Get.put(), it is used for when you want multiple different instance of a same class | 111 | // optional: same as Get.put(), it is used for when you want multiple different instance of a same class |
112 | // must be unique | 112 | // must be unique |
@@ -128,7 +128,7 @@ Get.putAsync<S>( | @@ -128,7 +128,7 @@ Get.putAsync<S>( | ||
128 | 128 | ||
129 | // mandatory: an async method that will be executed to instantiate your class | 129 | // mandatory: an async method that will be executed to instantiate your class |
130 | // Example: Get.putAsync<YourAsyncClass>( () async => await YourAsyncClass() ) | 130 | // Example: Get.putAsync<YourAsyncClass>( () async => await YourAsyncClass() ) |
131 | - FcBuilderFuncAsync<S> builder, | 131 | + AsyncInstanceBuilderCallback<S> builder, |
132 | 132 | ||
133 | // optional: same as Get.put(), it is used for when you want multiple different instance of a same class | 133 | // optional: same as Get.put(), it is used for when you want multiple different instance of a same class |
134 | // must be unique | 134 | // must be unique |
@@ -99,7 +99,7 @@ Get.put<S>( | @@ -99,7 +99,7 @@ Get.put<S>( | ||
99 | bool overrideAbstract = false, | 99 | bool overrideAbstract = false, |
100 | 100 | ||
101 | // optional: allows you to create the dependency using function instead of the dependency itself. | 101 | // optional: allows you to create the dependency using function instead of the dependency itself. |
102 | - FcBuilderFunc<S> builder, | 102 | + InstanceBuilderCallback<S> builder, |
103 | ) | 103 | ) |
104 | ``` | 104 | ``` |
105 | 105 | ||
@@ -109,7 +109,7 @@ Get.put<S>( | @@ -109,7 +109,7 @@ Get.put<S>( | ||
109 | Get.lazyPut<S>( | 109 | Get.lazyPut<S>( |
110 | // mandatory: a method that will be executed when your class is called for the first time | 110 | // mandatory: a method that will be executed when your class is called for the first time |
111 | // Example: Get.lazyPut<Controller>( () => Controller() ) | 111 | // Example: Get.lazyPut<Controller>( () => Controller() ) |
112 | - FcBuilderFunc builder, | 112 | + InstanceBuilderCallback builder, |
113 | 113 | ||
114 | // optional: same as Get.put(), it is used for when you want multiple different instance of a same class | 114 | // optional: same as Get.put(), it is used for when you want multiple different instance of a same class |
115 | // must be unique | 115 | // must be unique |
@@ -131,7 +131,7 @@ Get.putAsync<S>( | @@ -131,7 +131,7 @@ Get.putAsync<S>( | ||
131 | 131 | ||
132 | // mandatory: an async method that will be executed to instantiate your class | 132 | // mandatory: an async method that will be executed to instantiate your class |
133 | // Example: Get.putAsync<YourAsyncClass>( () async => await YourAsyncClass() ) | 133 | // Example: Get.putAsync<YourAsyncClass>( () async => await YourAsyncClass() ) |
134 | - FcBuilderFuncAsync<S> builder, | 134 | + AsyncInstanceBuilderCallback<S> builder, |
135 | 135 | ||
136 | // optional: same as Get.put(), it is used for when you want multiple different instance of a same class | 136 | // optional: same as Get.put(), it is used for when you want multiple different instance of a same class |
137 | // must be unique | 137 | // must be unique |
@@ -96,7 +96,7 @@ Get.put<S>( | @@ -96,7 +96,7 @@ Get.put<S>( | ||
96 | bool permanent = false, | 96 | bool permanent = false, |
97 | 97 | ||
98 | // opcional: permite criar a dependência usando uma função em vez da dependênia em si | 98 | // opcional: permite criar a dependência usando uma função em vez da dependênia em si |
99 | - FcBuilderFunc<S> builder, | 99 | + InstanceBuilderCallback<S> builder, |
100 | ) | 100 | ) |
101 | ``` | 101 | ``` |
102 | 102 | ||
@@ -106,7 +106,7 @@ Get.put<S>( | @@ -106,7 +106,7 @@ Get.put<S>( | ||
106 | Get.lazyPut<S>( | 106 | Get.lazyPut<S>( |
107 | // obrigatório: um método que vai ser executado quando sua classe é chamada pela primeira vez | 107 | // obrigatório: um método que vai ser executado quando sua classe é chamada pela primeira vez |
108 | // Exemplo: "Get.lazyPut<Controller>( () => Controller() | 108 | // Exemplo: "Get.lazyPut<Controller>( () => Controller() |
109 | - FcBuilderFunc builder, | 109 | + InstanceBuilderCallback builder, |
110 | 110 | ||
111 | // opcional: igual ao Get.put(), é usado quando você precisa de múltiplas instâncias de uma mesma classe | 111 | // opcional: igual ao Get.put(), é usado quando você precisa de múltiplas instâncias de uma mesma classe |
112 | // precisa ser uma string única | 112 | // precisa ser uma string única |
@@ -127,7 +127,7 @@ Get.lazyPut<S>( | @@ -127,7 +127,7 @@ Get.lazyPut<S>( | ||
127 | Get.putAsync<S>( | 127 | Get.putAsync<S>( |
128 | // Obrigatório: um método assíncrono que vai ser executado para instanciar sua classe | 128 | // Obrigatório: um método assíncrono que vai ser executado para instanciar sua classe |
129 | // Exemplo: Get.putAsyn<YourAsyncClass>( () async => await YourAsyncClass() ) | 129 | // Exemplo: Get.putAsyn<YourAsyncClass>( () async => await YourAsyncClass() ) |
130 | - FcBuilderFuncAsync<S> builder, | 130 | + AsyncInstanceBuilderCallback<S> builder, |
131 | 131 | ||
132 | // opcional: igual ao Get.put(), é usado quando você precisa de múltiplas instâncias de uma mesma classe | 132 | // opcional: igual ao Get.put(), é usado quando você precisa de múltiplas instâncias de uma mesma classe |
133 | // precisa ser uma string única | 133 | // precisa ser uma string única |
@@ -144,7 +144,7 @@ Get.putAsync<S>( | @@ -144,7 +144,7 @@ Get.putAsync<S>( | ||
144 | Get.create<S>( | 144 | Get.create<S>( |
145 | // Obrigatório: Uma função que retorna uma classe que será "fabricada" toda vez que Get.find() for chamado | 145 | // Obrigatório: Uma função que retorna uma classe que será "fabricada" toda vez que Get.find() for chamado |
146 | // Exemplo: Get.create<YourClass>(() => YourClass()) | 146 | // Exemplo: Get.create<YourClass>(() => YourClass()) |
147 | - FcBuilderFunc<S> builder, | 147 | + InstanceBuilderCallback<S> builder, |
148 | 148 | ||
149 | // opcional: igual ao Get.put(), mas é usado quando você precisa de múltiplas instâncias de uma mesma classe. | 149 | // opcional: igual ao Get.put(), mas é usado quando você precisa de múltiplas instâncias de uma mesma classe. |
150 | // Útil caso você tenha uma lista em que cada item precise de um controller próprio | 150 | // Útil caso você tenha uma lista em que cada item precise de um controller próprio |
@@ -170,7 +170,7 @@ A diferença fundamental entre `permanent` e `fenix` está em como você quer ar | @@ -170,7 +170,7 @@ A diferença fundamental entre `permanent` e `fenix` está em como você quer ar | ||
170 | 170 | ||
171 | Prosseguindo com as diferenças entre os métodos: | 171 | Prosseguindo com as diferenças entre os métodos: |
172 | 172 | ||
173 | -- Get.put e Get.putAsync seguem a mesma ordem de criação, com a diferença que o Async opta por aplicar um método assíncrono: Esses dois métodos criam e já inicializam a instância. Esta é inserida diretamente na memória, através do método interno `insert` com os parâmetros `permanent: false` e `isSingleton: true` (esse parâmetro `isSingleton` serve apenas para dizer se é para utilizar a dependência colocada em `dependency`, ou se é para usar a dependência colocada no `FcBuilderFunc`). Depois disso, é chamado o `Get.find` que imediatamente inicializa as instâncias que estão na memória. | 173 | +- Get.put e Get.putAsync seguem a mesma ordem de criação, com a diferença que o Async opta por aplicar um método assíncrono: Esses dois métodos criam e já inicializam a instância. Esta é inserida diretamente na memória, através do método interno `insert` com os parâmetros `permanent: false` e `isSingleton: true` (esse parâmetro `isSingleton` serve apenas para dizer se é para utilizar a dependência colocada em `dependency`, ou se é para usar a dependência colocada no `InstanceBuilderCallback`). Depois disso, é chamado o `Get.find` que imediatamente inicializa as instâncias que estão na memória. |
174 | 174 | ||
175 | - Get.create: Como o nome indica, você vai "criar" a sua dependência! Similar ao `Get.put`, ela também chama o método interno `insert` para instanciamento. Contudo, `permanent` e `isSingleton` passam a ser `true` e `false` (Como estamos "criando" a nossa dependência, não tem como ela ser um Singleton de algo, logo, `false`). E por ser `permanent: true`, temos por padrão o benefício de não se perder entre telas! Além disso, não é chamado o `Get.find`, logo ela fica esperando ser chamada para ser usada. Ele é criado dessa forma para aproveitar o uso do parâmetro `permanent`, já que, vale ressaltar, o Get.create foi criado com o objetivo de criar instâncias não compartilhadas, mas que não se perdem, como por exemplo um botão em um listView, que você quer uma instância única para aquela lista - por conta disso, o Get.create deve ser usado em conjunto com o GetWidget. | 175 | - Get.create: Como o nome indica, você vai "criar" a sua dependência! Similar ao `Get.put`, ela também chama o método interno `insert` para instanciamento. Contudo, `permanent` e `isSingleton` passam a ser `true` e `false` (Como estamos "criando" a nossa dependência, não tem como ela ser um Singleton de algo, logo, `false`). E por ser `permanent: true`, temos por padrão o benefício de não se perder entre telas! Além disso, não é chamado o `Get.find`, logo ela fica esperando ser chamada para ser usada. Ele é criado dessa forma para aproveitar o uso do parâmetro `permanent`, já que, vale ressaltar, o Get.create foi criado com o objetivo de criar instâncias não compartilhadas, mas que não se perdem, como por exemplo um botão em um listView, que você quer uma instância única para aquela lista - por conta disso, o Get.create deve ser usado em conjunto com o GetWidget. |
176 | 176 |
1 | -import 'package:get/get.dart'; | ||
2 | -import '../data/home_model.dart'; | ||
3 | -import '../data/home_repository.dart'; | ||
4 | - | ||
5 | -class HomeController extends GetxController { | ||
6 | - HomeController({this.homeRepository}); | ||
7 | - final HomeRepository homeRepository; | ||
8 | - | ||
9 | - Rx<ApiModel> data = Rx<ApiModel>(); | ||
10 | - | ||
11 | - @override | ||
12 | - void onInit() => fetchDataFromApi(); | ||
13 | - | ||
14 | - void fetchDataFromApi() async { | ||
15 | - data.value = await homeRepository.getData(); | ||
16 | - if (data.value == null) { | ||
17 | - Get.snackbar("Error", "Can't connect to server"); | ||
18 | - } | ||
19 | - } | ||
20 | -} |
1 | -import 'package:dio/dio.dart'; | ||
2 | -import 'package:flutter/foundation.dart'; | ||
3 | -import 'home_model.dart'; | ||
4 | - | ||
5 | -abstract class IHomeProvider { | ||
6 | - Future<ApiModel> get(); | ||
7 | - Future<ApiModel> post(Map<String, dynamic> data); | ||
8 | - Future<ApiModel> put(Map<String, dynamic> data); | ||
9 | - Future<ApiModel> delete(int id); | ||
10 | -} | ||
11 | - | ||
12 | -class HomeProvider implements IHomeProvider { | ||
13 | - final Dio dio; | ||
14 | - | ||
15 | - HomeProvider({@required this.dio}); | ||
16 | - | ||
17 | - Future<ApiModel> get() async { | ||
18 | - try { | ||
19 | - final response = await dio.get("https://api.covid19api.com/summary"); | ||
20 | - return ApiModel.fromJson(response.data); | ||
21 | - } catch (e) { | ||
22 | - print(e.toString()); | ||
23 | - return null; | ||
24 | - } | ||
25 | - } | ||
26 | - | ||
27 | - @override | ||
28 | - Future<ApiModel> post(Map<String, dynamic> data) { | ||
29 | - throw UnimplementedError(); | ||
30 | - } | ||
31 | - | ||
32 | - @override | ||
33 | - Future<ApiModel> put(Map<String, dynamic> data) { | ||
34 | - throw UnimplementedError(); | ||
35 | - } | ||
36 | - | ||
37 | - @override | ||
38 | - Future<ApiModel> delete(int id) { | ||
39 | - throw UnimplementedError(); | ||
40 | - } | ||
41 | -} |
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 | -import 'package:get_state/home/bindings/home_binding.dart'; | ||
4 | -import 'package:get_state/home/views/country_view.dart'; | ||
5 | -import 'home/views/details_view.dart'; | ||
6 | -import 'home/views/home_view.dart'; | 3 | +import 'package:get_state/routes/app_pages.dart'; |
4 | +import 'shared/logger/logger_utils.dart'; | ||
7 | 5 | ||
8 | void main() { | 6 | void main() { |
9 | - runApp( | ||
10 | - GetMaterialApp( | ||
11 | - debugShowCheckedModeBanner: false, | ||
12 | - initialRoute: '/', | ||
13 | - enableLog: true, | ||
14 | - // logWriterCallback: localLogWriter, | ||
15 | - getPages: [ | ||
16 | - GetPage(name: '/', page: () => HomePage(), binding: HomeBinding()), | ||
17 | - GetPage(name: '/country', page: () => CountryPage()), | ||
18 | - GetPage(name: '/details', page: () => DetailsPage()), | ||
19 | - ], | ||
20 | - ), | ||
21 | - ); | 7 | + runApp(MyApp()); |
22 | } | 8 | } |
23 | 9 | ||
24 | -// Sample of abstract logging function | ||
25 | -void localLogWriter(String text, {bool isError = false}) { | ||
26 | - print('** ' + text + ' [' + isError.toString() + ']'); | 10 | +class MyApp extends StatelessWidget { |
11 | + const MyApp({Key key}) : super(key: key); | ||
12 | + | ||
13 | + @override | ||
14 | + Widget build(BuildContext context) { | ||
15 | + return GetMaterialApp( | ||
16 | + debugShowCheckedModeBanner: false, | ||
17 | + enableLog: true, | ||
18 | + logWriterCallback: Logger.write, | ||
19 | + initialRoute: AppPages.INITIAL, | ||
20 | + getPages: AppPages.routes, | ||
21 | + ); | ||
22 | + } | ||
27 | } | 23 | } |
1 | import 'package:dio/dio.dart'; | 1 | import 'package:dio/dio.dart'; |
2 | import 'package:get/get.dart'; | 2 | import 'package:get/get.dart'; |
3 | -import '../controllers/home_controller.dart'; | ||
4 | -import '../data/home_provider.dart'; | 3 | +import 'package:get_state/pages/home/domain/adapters/repository_adapter.dart'; |
4 | +import 'package:get_state/pages/home/presentation/controllers/home_controller.dart'; | ||
5 | import '../data/home_repository.dart'; | 5 | import '../data/home_repository.dart'; |
6 | 6 | ||
7 | class HomeBinding extends Bindings { | 7 | class HomeBinding extends Bindings { |
8 | @override | 8 | @override |
9 | void dependencies() { | 9 | void dependencies() { |
10 | - Get.lazyPut<HomeController>(() { | ||
11 | - Get.put(Dio()); | ||
12 | - Get.put(HomeProvider(dio: Get.find())); | ||
13 | - Get.put(HomeRepository(homeProvider: Get.find())); | ||
14 | - return HomeController(homeRepository: Get.find()); | ||
15 | - }); | 10 | + Get.lazyPut(() => Dio()); |
11 | + Get.lazyPut<IHomeRepository>(() => HomeRepository(dio: Get.find())); | ||
12 | + Get.lazyPut(() => HomeController(homeRepository: Get.find())); | ||
16 | } | 13 | } |
17 | } | 14 | } |
1 | +import 'package:dio/dio.dart'; | ||
2 | +import 'package:get_state/pages/home/domain/adapters/repository_adapter.dart'; | ||
3 | +import 'package:get_state/pages/home/domain/entity/cases_model.dart'; | ||
4 | + | ||
5 | +class HomeRepository implements IHomeRepository { | ||
6 | + HomeRepository({this.dio}); | ||
7 | + final Dio dio; | ||
8 | + | ||
9 | + @override | ||
10 | + Future<CasesModel> getCases() async { | ||
11 | + try { | ||
12 | + final response = await dio.get("https://api.covid19api.com/summary"); | ||
13 | + return CasesModel.fromJson(response.data); | ||
14 | + } catch (e) { | ||
15 | + print(e.toString()); | ||
16 | + return Future.error(e.toString()); | ||
17 | + } | ||
18 | + } | ||
19 | +} |
1 | // To parse this JSON data, do | 1 | // To parse this JSON data, do |
2 | // | 2 | // |
3 | -// final apiModel = apiModelFromJson(jsonString); | 3 | +// final CasesModel = CasesModelFromJson(jsonString); |
4 | 4 | ||
5 | import 'dart:convert'; | 5 | import 'dart:convert'; |
6 | 6 | ||
7 | -class ApiModel { | 7 | +class CasesModel { |
8 | final Global global; | 8 | final Global global; |
9 | final List<Country> countries; | 9 | final List<Country> countries; |
10 | final String date; | 10 | final String date; |
11 | 11 | ||
12 | - ApiModel({ | 12 | + CasesModel({ |
13 | this.global, | 13 | this.global, |
14 | this.countries, | 14 | this.countries, |
15 | this.date, | 15 | this.date, |
16 | }); | 16 | }); |
17 | 17 | ||
18 | - factory ApiModel.fromRawJson(String str) => | ||
19 | - ApiModel.fromJson(json.decode(str)); | 18 | + factory CasesModel.fromRawJson(String str) => |
19 | + CasesModel.fromJson(json.decode(str)); | ||
20 | 20 | ||
21 | String toRawJson() => json.encode(toJson()); | 21 | String toRawJson() => json.encode(toJson()); |
22 | 22 | ||
23 | - factory ApiModel.fromJson(Map<String, dynamic> json) => ApiModel( | 23 | + factory CasesModel.fromJson(Map<String, dynamic> json) => CasesModel( |
24 | global: json["Global"] == null ? null : Global.fromJson(json["Global"]), | 24 | global: json["Global"] == null ? null : Global.fromJson(json["Global"]), |
25 | countries: json["Countries"] == null | 25 | countries: json["Countries"] == null |
26 | ? null | 26 | ? null |
1 | +import 'package:get/get.dart'; | ||
2 | +import 'package:get_state/pages/home/domain/adapters/repository_adapter.dart'; | ||
3 | +import 'package:get_state/pages/home/domain/entity/cases_model.dart'; | ||
4 | + | ||
5 | +enum Status { loading, success, error } | ||
6 | + | ||
7 | +class HomeController extends GetxController { | ||
8 | + HomeController({this.homeRepository}); | ||
9 | + | ||
10 | + /// inject repo abstraction dependency | ||
11 | + final IHomeRepository homeRepository; | ||
12 | + | ||
13 | + /// create a reactive status from request with initial value = loading | ||
14 | + final status = Status.loading.obs; | ||
15 | + | ||
16 | + /// create a reactive CasesModel. CasesModel().obs has same result | ||
17 | + final cases = Rx<CasesModel>(); | ||
18 | + | ||
19 | + /// When the controller is initialized, make the http request | ||
20 | + @override | ||
21 | + void onInit() => fetchDataFromApi(); | ||
22 | + | ||
23 | + /// fetch cases from Api | ||
24 | + Future<void> fetchDataFromApi() async { | ||
25 | + /// When the repository returns the value, change the status to success, and fill in "cases" | ||
26 | + return homeRepository.getCases().then( | ||
27 | + (data) { | ||
28 | + cases(data); | ||
29 | + status(Status.success); | ||
30 | + }, | ||
31 | + | ||
32 | + /// In case of error, print the error and change the status to Status.error | ||
33 | + onError: (err) { | ||
34 | + print("$err"); | ||
35 | + return status(Status.error); | ||
36 | + }, | ||
37 | + ); | ||
38 | + } | ||
39 | +} |
1 | import 'dart:ui'; | 1 | import 'dart:ui'; |
2 | import 'package:flutter/material.dart'; | 2 | import 'package:flutter/material.dart'; |
3 | -import 'package:get_state/home/controllers/home_controller.dart'; | ||
4 | -import 'package:get_state/home/data/home_model.dart'; | ||
5 | import 'package:get/get.dart'; | 3 | import 'package:get/get.dart'; |
4 | +import 'package:get_state/pages/home/domain/entity/cases_model.dart'; | ||
5 | +import '../controllers/home_controller.dart'; | ||
6 | 6 | ||
7 | -class CountryPage extends GetWidget<HomeController> { | 7 | +class CountryView extends GetWidget<HomeController> { |
8 | @override | 8 | @override |
9 | Widget build(BuildContext context) { | 9 | Widget build(BuildContext context) { |
10 | return Container( | 10 | return Container( |
@@ -28,9 +28,9 @@ class CountryPage extends GetWidget<HomeController> { | @@ -28,9 +28,9 @@ class CountryPage extends GetWidget<HomeController> { | ||
28 | ), | 28 | ), |
29 | body: Center( | 29 | body: Center( |
30 | child: ListView.builder( | 30 | child: ListView.builder( |
31 | - itemCount: controller.data.value.countries.length, | 31 | + itemCount: controller.cases.value.countries.length, |
32 | itemBuilder: (context, index) { | 32 | itemBuilder: (context, index) { |
33 | - Country country = controller.data.value.countries[index]; | 33 | + Country country = controller.cases.value.countries[index]; |
34 | return ListTile( | 34 | return ListTile( |
35 | onTap: () { | 35 | onTap: () { |
36 | Get.toNamed('/details', arguments: country); | 36 | Get.toNamed('/details', arguments: country); |
1 | import 'dart:ui'; | 1 | import 'dart:ui'; |
2 | import 'package:flutter/material.dart'; | 2 | import 'package:flutter/material.dart'; |
3 | import 'package:get/get.dart'; | 3 | import 'package:get/get.dart'; |
4 | -import 'package:get_state/home/data/home_model.dart'; | 4 | +import 'package:get_state/pages/home/domain/entity/cases_model.dart'; |
5 | 5 | ||
6 | -class DetailsPage extends StatelessWidget { | 6 | +class DetailsView extends StatelessWidget { |
7 | @override | 7 | @override |
8 | Widget build(BuildContext context) { | 8 | Widget build(BuildContext context) { |
9 | Country country = Get.arguments; | 9 | Country country = Get.arguments; |
1 | import 'dart:ui'; | 1 | import 'dart:ui'; |
2 | import 'package:flutter/material.dart'; | 2 | import 'package:flutter/material.dart'; |
3 | import 'package:get/get.dart'; | 3 | import 'package:get/get.dart'; |
4 | -import 'package:get_state/home/controllers/home_controller.dart'; | 4 | +import 'package:get_state/pages/home/presentation/controllers/home_controller.dart'; |
5 | 5 | ||
6 | -class HomePage extends GetWidget<HomeController> { | 6 | +class HomeView extends GetView<HomeController> { |
7 | @override | 7 | @override |
8 | Widget build(BuildContext context) { | 8 | Widget build(BuildContext context) { |
9 | return Container( | 9 | return Container( |
@@ -23,58 +23,61 @@ class HomePage extends GetWidget<HomeController> { | @@ -23,58 +23,61 @@ class HomePage extends GetWidget<HomeController> { | ||
23 | centerTitle: true, | 23 | centerTitle: true, |
24 | ), | 24 | ), |
25 | body: Center( | 25 | body: Center( |
26 | - child: Obx(() => (controller.data() == null) | ||
27 | - ? CircularProgressIndicator() | ||
28 | - : Column( | ||
29 | - mainAxisAlignment: MainAxisAlignment.center, | ||
30 | - children: [ | ||
31 | - SizedBox( | ||
32 | - height: 100, | 26 | + child: Obx( |
27 | + () { | ||
28 | + Status status = controller.status.value; | ||
29 | + if (status == Status.loading) return CircularProgressIndicator(); | ||
30 | + if (status == Status.error) return Text('Error on connection :('); | ||
31 | + return Column( | ||
32 | + mainAxisAlignment: MainAxisAlignment.center, | ||
33 | + children: [ | ||
34 | + SizedBox( | ||
35 | + height: 100, | ||
36 | + ), | ||
37 | + Text( | ||
38 | + "Total Confirmed", | ||
39 | + style: TextStyle( | ||
40 | + fontSize: 30, | ||
33 | ), | 41 | ), |
34 | - Text( | ||
35 | - "Total Confirmed", | ||
36 | - style: TextStyle( | ||
37 | - fontSize: 30, | ||
38 | - ), | 42 | + ), |
43 | + Text( | ||
44 | + '${controller.cases.value.global.totalConfirmed}', | ||
45 | + style: TextStyle(fontSize: 45, fontWeight: FontWeight.bold), | ||
46 | + ), | ||
47 | + SizedBox( | ||
48 | + height: 10, | ||
49 | + ), | ||
50 | + Text( | ||
51 | + "Total Deaths", | ||
52 | + style: TextStyle( | ||
53 | + fontSize: 30, | ||
39 | ), | 54 | ), |
40 | - Text( | ||
41 | - '${controller.data.value.global.totalConfirmed}', | ||
42 | - style: | ||
43 | - TextStyle(fontSize: 45, fontWeight: FontWeight.bold), | 55 | + ), |
56 | + Text( | ||
57 | + '${controller.cases.value.global.totalDeaths}', | ||
58 | + style: TextStyle(fontSize: 45, fontWeight: FontWeight.bold), | ||
59 | + ), | ||
60 | + SizedBox( | ||
61 | + height: 10, | ||
62 | + ), | ||
63 | + OutlineButton( | ||
64 | + borderSide: BorderSide( | ||
65 | + color: Colors.deepPurple, | ||
66 | + width: 3, | ||
44 | ), | 67 | ), |
45 | - SizedBox( | ||
46 | - height: 10, | 68 | + shape: StadiumBorder(), |
69 | + onPressed: () { | ||
70 | + Get.toNamed('/country'); | ||
71 | + }, | ||
72 | + child: Text( | ||
73 | + "Fetch by country", | ||
74 | + style: TextStyle(fontWeight: FontWeight.bold), | ||
47 | ), | 75 | ), |
48 | - Text( | ||
49 | - "Total Deaths", | ||
50 | - style: TextStyle( | ||
51 | - fontSize: 30, | ||
52 | - ), | ||
53 | - ), | ||
54 | - Text( | ||
55 | - '${controller.data.value.global.totalDeaths}', | ||
56 | - style: | ||
57 | - TextStyle(fontSize: 45, fontWeight: FontWeight.bold), | ||
58 | - ), | ||
59 | - SizedBox( | ||
60 | - height: 10, | ||
61 | - ), | ||
62 | - OutlineButton( | ||
63 | - borderSide: BorderSide( | ||
64 | - color: Colors.deepPurple, | ||
65 | - width: 3, | ||
66 | - ), | ||
67 | - shape: StadiumBorder(), | ||
68 | - onPressed: () { | ||
69 | - Get.toNamed('/country'); | ||
70 | - }, | ||
71 | - child: Text( | ||
72 | - "Fetch by country", | ||
73 | - style: TextStyle(fontWeight: FontWeight.bold), | ||
74 | - ), | ||
75 | - ) | ||
76 | - ], | ||
77 | - )), | 76 | + ) |
77 | + ], | ||
78 | + ); | ||
79 | + }, | ||
80 | + ), | ||
78 | ), | 81 | ), |
79 | ), | 82 | ), |
80 | ); | 83 | ); |
example/lib/routes/app_pages.dart
0 → 100644
1 | +import 'package:get/get.dart'; | ||
2 | +import 'package:get_state/pages/home/bindings/home_binding.dart'; | ||
3 | +import 'package:get_state/pages/home/presentation/views/country_view.dart'; | ||
4 | +import 'package:get_state/pages/home/presentation/views/details_view.dart'; | ||
5 | +import 'package:get_state/pages/home/presentation/views/home_view.dart'; | ||
6 | + | ||
7 | +part 'app_routes.dart'; | ||
8 | + | ||
9 | +class AppPages { | ||
10 | + static const INITIAL = Routes.HOME; | ||
11 | + | ||
12 | + static final routes = [ | ||
13 | + GetPage( | ||
14 | + name: Routes.HOME, | ||
15 | + page: () => HomeView(), | ||
16 | + binding: HomeBinding(), | ||
17 | + ), | ||
18 | + GetPage( | ||
19 | + name: Routes.COUNTRY, | ||
20 | + page: () => CountryView(), | ||
21 | + ), | ||
22 | + GetPage( | ||
23 | + name: Routes.DETAILS, | ||
24 | + page: () => DetailsView(), | ||
25 | + ), | ||
26 | + ]; | ||
27 | +} |
example/lib/routes/app_routes.dart
0 → 100644
example/lib/shared/logger/logger_utils.dart
0 → 100644
@@ -69,4 +69,4 @@ flutter: | @@ -69,4 +69,4 @@ flutter: | ||
69 | # weight: 700 | 69 | # weight: 700 |
70 | # | 70 | # |
71 | # For details regarding fonts from package dependencies, | 71 | # For details regarding fonts from package dependencies, |
72 | - # see https://flutter.dev/custom-fonts/#from-packages | 72 | + # see https://flutter.dev/custom-fonts/#from-packages |
example/test/test.dart
0 → 100644
1 | +import 'dart:math'; | ||
2 | +import 'package:flutter_test/flutter_test.dart'; | ||
3 | +import 'package:get/get.dart'; | ||
4 | +import 'package:get_state/pages/home/domain/adapters/repository_adapter.dart'; | ||
5 | +import 'package:get_state/pages/home/domain/entity/cases_model.dart'; | ||
6 | +import 'package:get_state/pages/home/presentation/controllers/home_controller.dart'; | ||
7 | +import 'package:matcher/matcher.dart'; | ||
8 | + | ||
9 | +class MockReposity implements IHomeRepository { | ||
10 | + @override | ||
11 | + Future<CasesModel> getCases() async { | ||
12 | + await Future.delayed(Duration(milliseconds: 100)); | ||
13 | + return Random().nextBool() | ||
14 | + ? CasesModel( | ||
15 | + global: Global(totalDeaths: 100, totalConfirmed: 200), | ||
16 | + ) | ||
17 | + : Future.error('error'); | ||
18 | + } | ||
19 | +} | ||
20 | + | ||
21 | +void main() { | ||
22 | + final binding = BindingsBuilder(() { | ||
23 | + Get.lazyPut<IHomeRepository>(() => MockReposity()); | ||
24 | + Get.lazyPut<HomeController>( | ||
25 | + () => HomeController(homeRepository: Get.find())); | ||
26 | + }); | ||
27 | + | ||
28 | + test('Test Binding', () { | ||
29 | + expect(Get.isPrepared<HomeController>(), false); | ||
30 | + expect(Get.isPrepared<IHomeRepository>(), false); | ||
31 | + | ||
32 | + /// test you Binding class with BindingsBuilder | ||
33 | + binding.builder(); | ||
34 | + | ||
35 | + expect(Get.isPrepared<HomeController>(), true); | ||
36 | + expect(Get.isPrepared<IHomeRepository>(), true); | ||
37 | + | ||
38 | + Get.reset(); | ||
39 | + }); | ||
40 | + test('Test Controller', () async { | ||
41 | + /// Controller can't be on memory | ||
42 | + expect(() => Get.find<HomeController>(), throwsA(TypeMatcher<String>())); | ||
43 | + | ||
44 | + /// build Binding | ||
45 | + binding.builder(); | ||
46 | + | ||
47 | + /// recover your controller | ||
48 | + HomeController controller = Get.find(); | ||
49 | + | ||
50 | + /// check if onInit was called | ||
51 | + expect(controller.initialized, true); | ||
52 | + | ||
53 | + /// check initial Status | ||
54 | + expect(controller.status.value, Status.loading); | ||
55 | + | ||
56 | + /// await time request | ||
57 | + await Future.delayed(Duration(milliseconds: 100)); | ||
58 | + | ||
59 | + if (controller.status.value == Status.error) { | ||
60 | + expect(controller.cases.value, null); | ||
61 | + } | ||
62 | + | ||
63 | + if (controller.status.value == Status.success) { | ||
64 | + expect(controller.cases.value.global.totalDeaths, 100); | ||
65 | + expect(controller.cases.value.global.totalConfirmed, 200); | ||
66 | + } | ||
67 | + }); | ||
68 | +} |
example/test/widget_test.dart
deleted
100644 → 0
1 | -// // This is a basic Flutter widget test. | ||
2 | -// // | ||
3 | -// // To perform an interaction with a widget in your test, use the WidgetTester | ||
4 | -// // utility that Flutter provides. For example, you can send tap and scroll | ||
5 | -// // gestures. You can also use WidgetTester to find child widgets in the widget | ||
6 | -// // tree, read text, and verify that the values of widget properties are correct. | ||
7 | - | ||
8 | -// import 'package:flutter/material.dart'; | ||
9 | -// import 'package:flutter_test/flutter_test.dart'; | ||
10 | - | ||
11 | -// import 'package:get_state/main.dart'; | ||
12 | - | ||
13 | -// void main() { | ||
14 | -// testWidgets('Counter increments smoke test', (WidgetTester tester) async { | ||
15 | -// // Build our app and trigger a frame. | ||
16 | -// await tester.pumpWidget(MyApp()); | ||
17 | - | ||
18 | -// // Verify that our counter starts at 0. | ||
19 | -// expect(find.text('0'), findsOneWidget); | ||
20 | -// expect(find.text('1'), findsNothing); | ||
21 | - | ||
22 | -// // Tap the '+' icon and trigger a frame. | ||
23 | -// await tester.tap(find.byIcon(Icons.add)); | ||
24 | -// await tester.pump(); | ||
25 | - | ||
26 | -// // Verify that our counter has incremented. | ||
27 | -// expect(find.text('0'), findsNothing); | ||
28 | -// expect(find.text('1'), findsOneWidget); | ||
29 | -// }); | ||
30 | -// } |
@@ -91,4 +91,6 @@ extension Inst on GetInterface { | @@ -91,4 +91,6 @@ extension Inst on GetInterface { | ||
91 | /// Check if a Class Instance<[S]> (or [tag]) is registered in memory. | 91 | /// Check if a Class Instance<[S]> (or [tag]) is registered in memory. |
92 | /// - [tag] optional, if you use a [tag] to register the Instance. | 92 | /// - [tag] optional, if you use a [tag] to register the Instance. |
93 | bool isRegistered<S>({String tag}) => GetInstance().isRegistered<S>(tag: tag); | 93 | bool isRegistered<S>({String tag}) => GetInstance().isRegistered<S>(tag: tag); |
94 | + | ||
95 | + bool isPrepared<S>({String tag}) => GetInstance().isPrepared<S>(tag: tag); | ||
94 | } | 96 | } |
@@ -209,6 +209,7 @@ class GetInstance { | @@ -209,6 +209,7 @@ class GetInstance { | ||
209 | S find<S>({String tag}) { | 209 | S find<S>({String tag}) { |
210 | String key = _getKey(S, tag); | 210 | String key = _getKey(S, tag); |
211 | if (isRegistered<S>(tag: tag)) { | 211 | if (isRegistered<S>(tag: tag)) { |
212 | + | ||
212 | if (_singl[key] == null) { | 213 | if (_singl[key] == null) { |
213 | if (tag == null) { | 214 | if (tag == null) { |
214 | throw 'Class "$S" is not register'; | 215 | throw 'Class "$S" is not register'; |
@@ -363,6 +364,5 @@ class _InstanceBuilderFactory<S> { | @@ -363,6 +364,5 @@ class _InstanceBuilderFactory<S> { | ||
363 | class _Lazy { | 364 | class _Lazy { |
364 | bool fenix; | 365 | bool fenix; |
365 | InstanceBuilderCallback builder; | 366 | InstanceBuilderCallback builder; |
366 | - | ||
367 | _Lazy(this.builder, this.fenix); | 367 | _Lazy(this.builder, this.fenix); |
368 | } | 368 | } |
@@ -758,7 +758,7 @@ extension GetNavigation on GetInterface { | @@ -758,7 +758,7 @@ extension GetNavigation on GetInterface { | ||
758 | Text( | 758 | Text( |
759 | title, | 759 | title, |
760 | style: TextStyle( | 760 | style: TextStyle( |
761 | - color: colorText ?? theme.iconTheme.color, | 761 | + color: colorText ?? Colors.black, |
762 | fontWeight: FontWeight.w800, | 762 | fontWeight: FontWeight.w800, |
763 | fontSize: 16), | 763 | fontSize: 16), |
764 | ), | 764 | ), |
@@ -766,7 +766,7 @@ extension GetNavigation on GetInterface { | @@ -766,7 +766,7 @@ extension GetNavigation on GetInterface { | ||
766 | Text( | 766 | Text( |
767 | message, | 767 | message, |
768 | style: TextStyle( | 768 | style: TextStyle( |
769 | - color: colorText ?? theme.iconTheme.color, | 769 | + color: colorText ?? Colors.black, |
770 | fontWeight: FontWeight.w300, | 770 | fontWeight: FontWeight.w300, |
771 | fontSize: 14), | 771 | fontSize: 14), |
772 | ), | 772 | ), |
@@ -19,7 +19,7 @@ abstract class Bindings { | @@ -19,7 +19,7 @@ abstract class Bindings { | ||
19 | /// ```` | 19 | /// ```` |
20 | class BindingsBuilder extends Bindings { | 20 | class BindingsBuilder extends Bindings { |
21 | /// Register your dependencies in the [builder] callback. | 21 | /// Register your dependencies in the [builder] callback. |
22 | - final Function() builder; | 22 | + final void Function() builder; |
23 | 23 | ||
24 | BindingsBuilder(this.builder); | 24 | BindingsBuilder(this.builder); |
25 | 25 |
@@ -44,9 +44,13 @@ abstract class DisposableInterface { | @@ -44,9 +44,13 @@ abstract class DisposableInterface { | ||
44 | /// It uses an internal "callable" type, to avoid any @overrides in subclases. | 44 | /// It uses an internal "callable" type, to avoid any @overrides in subclases. |
45 | /// This method should be internal and is required to define the lifetime cycle | 45 | /// This method should be internal and is required to define the lifetime cycle |
46 | /// of the subclass. | 46 | /// of the subclass. |
47 | - /// | ||
48 | final onStart = _InternalFinalCallback<void>(); | 47 | final onStart = _InternalFinalCallback<void>(); |
49 | 48 | ||
49 | + bool _initialized = false; | ||
50 | + | ||
51 | + /// Checks whether the controller has already been initialized. | ||
52 | + bool get initialized => _initialized; | ||
53 | + | ||
50 | DisposableInterface() { | 54 | DisposableInterface() { |
51 | onStart.callback = _onStart; | 55 | onStart.callback = _onStart; |
52 | } | 56 | } |
@@ -54,6 +58,7 @@ abstract class DisposableInterface { | @@ -54,6 +58,7 @@ abstract class DisposableInterface { | ||
54 | // Internal callback that starts the cycle of this controller. | 58 | // Internal callback that starts the cycle of this controller. |
55 | void _onStart() { | 59 | void _onStart() { |
56 | onInit(); | 60 | onInit(); |
61 | + _initialized = true; | ||
57 | SchedulerBinding.instance?.addPostFrameCallback((_) => onReady()); | 62 | SchedulerBinding.instance?.addPostFrameCallback((_) => onReady()); |
58 | } | 63 | } |
59 | 64 |
-
Please register or login to post a comment