diff --git a/.fvm/fvm_config.json b/.fvm/fvm_config.json
index 160b5b2..305f34d 100644
--- a/.fvm/fvm_config.json
+++ b/.fvm/fvm_config.json
@@ -1,4 +1,3 @@
{
- "flutterSdkVersion": "3.22.3",
- "flavors": {}
+ "flutterSdkVersion": "3.24.3"
}
\ No newline at end of file
diff --git a/.fvmrc b/.fvmrc
new file mode 100644
index 0000000..c62692b
--- /dev/null
+++ b/.fvmrc
@@ -0,0 +1,4 @@
+{
+ "flutter": "3.24.3",
+ "flavors": {}
+}
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 1be2d87..6602f6e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -46,4 +46,9 @@ app.*.map.json
/android/app/release
# fvm
-.fvm/flutter_sdk
\ No newline at end of file
+
+# FVM Version Cache
+.fvm/
+
+#Enviorment file
+.env
\ No newline at end of file
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 5d0f1d3..82011f7 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -7,7 +7,11 @@
{
"name": "app",
"request": "launch",
- "type": "dart"
+ "type": "dart",
+ "args": [
+ "--dart-define-from-file",
+ ".env"
+ ]
}
]
}
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
index f285aa4..ceaf9a6 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,9 +1,9 @@
{
- "dart.flutterSdkPath": ".fvm/flutter_sdk",
- "search.exclude": {
- "**/.fvm": true
- },
- "files.watcherExclude": {
- "**/.fvm": true
- }
+ "dart.flutterSdkPath": ".fvm/versions/3.24.3",
+ "search.exclude": {
+ "**/.fvm": true
+ },
+ "files.watcherExclude": {
+ "**/.fvm": true
+ }
}
\ No newline at end of file
diff --git a/coverage/lcov.info b/coverage/lcov.info
new file mode 100644
index 0000000..810f5ef
--- /dev/null
+++ b/coverage/lcov.info
@@ -0,0 +1,591 @@
+SF:lib/view/widgets/restaurant_category_price_widget.dart
+DA:5,1
+DA:12,1
+DA:14,1
+DA:15,1
+DA:16,1
+DA:17,1
+DA:18,3
+DA:21,1
+DA:22,1
+DA:23,3
+LF:10
+LH:10
+end_of_record
+SF:lib/models/restaurant.dart
+DA:11,1
+DA:16,0
+DA:17,0
+DA:19,0
+DA:27,1
+DA:31,0
+DA:33,0
+DA:43,1
+DA:49,0
+DA:51,0
+DA:61,1
+DA:68,0
+DA:70,0
+DA:78,0
+DA:82,0
+DA:83,0
+DA:85,0
+DA:101,6
+DA:114,1
+DA:126,1
+DA:127,1
+DA:128,1
+DA:129,1
+DA:130,1
+DA:131,1
+DA:132,1
+DA:133,1
+DA:134,1
+DA:135,1
+DA:136,0
+DA:140,0
+DA:141,0
+DA:143,0
+DA:146,0
+DA:147,0
+DA:148,0
+DA:154,0
+DA:155,0
+DA:156,0
+DA:163,3
+DA:164,5
+DA:165,3
+DA:170,1
+DA:171,2
+DA:180,0
+DA:185,0
+DA:186,0
+DA:188,0
+LF:48
+LH:21
+end_of_record
+SF:lib/models/restaurant.g.dart
+DA:9,0
+DA:10,0
+DA:11,0
+DA:14,0
+DA:15,0
+DA:16,0
+DA:19,0
+DA:20,0
+DA:23,0
+DA:24,0
+DA:27,0
+DA:28,0
+DA:29,0
+DA:30,0
+DA:33,0
+DA:34,0
+DA:35,0
+DA:36,0
+DA:39,0
+DA:40,0
+DA:41,0
+DA:42,0
+DA:44,0
+DA:45,0
+DA:48,0
+DA:49,0
+DA:50,0
+DA:51,0
+DA:52,0
+DA:55,0
+DA:56,0
+DA:59,0
+DA:60,0
+DA:63,0
+DA:64,0
+DA:65,0
+DA:66,0
+DA:67,0
+DA:69,0
+DA:70,0
+DA:71,0
+DA:72,0
+DA:73,0
+DA:74,0
+DA:75,0
+DA:76,0
+DA:77,0
+DA:78,0
+DA:79,0
+DA:81,0
+DA:82,0
+DA:85,0
+DA:86,0
+DA:87,0
+DA:88,0
+DA:89,0
+DA:90,0
+DA:91,0
+DA:92,0
+DA:93,0
+DA:94,0
+DA:95,0
+DA:96,0
+DA:99,0
+DA:101,0
+DA:102,0
+DA:103,0
+DA:104,0
+DA:105,0
+DA:108,0
+DA:110,0
+DA:111,0
+DA:112,0
+LF:73
+LH:0
+end_of_record
+SF:lib/view/widgets/restaurant_star_rating_widget.dart
+DA:4,8
+DA:7,4
+DA:9,4
+DA:11,4
+DA:12,12
+DA:13,4
+DA:16,4
+LF:7
+LH:7
+end_of_record
+SF:lib/view/widgets/review_tile.dart
+DA:7,1
+DA:10,1
+DA:12,1
+DA:14,1
+DA:15,3
+DA:17,1
+DA:18,2
+DA:19,3
+DA:22,1
+DA:23,1
+DA:24,1
+DA:25,1
+DA:28,1
+DA:29,3
+DA:33,4
+LF:15
+LH:15
+end_of_record
+SF:lib/domain/repository/restaurants_repository.dart
+DA:6,1
+DA:16,1
+DA:17,2
+DA:18,2
+DA:20,2
+DA:21,2
+DA:23,1
+DA:24,2
+DA:25,1
+DA:28,1
+DA:31,1
+DA:34,0
+DA:35,0
+DA:39,0
+DA:41,0
+DA:42,0
+DA:44,0
+DA:48,1
+DA:49,2
+DA:51,2
+DA:52,2
+DA:53,3
+DA:57,2
+DA:60,1
+DA:61,3
+DA:62,4
+DA:63,2
+DA:64,3
+DA:65,1
+DA:66,2
+DA:70,1
+DA:71,4
+DA:72,2
+DA:73,3
+DA:74,2
+DA:75,1
+DA:76,2
+LF:37
+LH:31
+end_of_record
+SF:lib/view/widgets/address_widget.dart
+DA:5,1
+DA:7,1
+DA:9,1
+DA:11,1
+DA:15,1
+DA:16,1
+DA:17,1
+DA:18,1
+DA:19,1
+DA:20,1
+LF:10
+LH:10
+end_of_record
+SF:lib/view/widgets/restaurant_hero_widget.dart
+DA:4,1
+DA:12,1
+DA:14,1
+DA:15,1
+DA:16,1
+DA:17,0
+DA:19,1
+LF:7
+LH:6
+end_of_record
+SF:lib/view/widgets/favorite_button_widget.dart
+DA:4,1
+DA:12,1
+DA:13,1
+DA:18,1
+DA:20,3
+DA:21,1
+DA:24,1
+DA:26,1
+DA:27,1
+DA:28,2
+DA:29,2
+DA:31,4
+DA:33,1
+LF:13
+LH:13
+end_of_record
+SF:lib/presentation/restaurants/restaurants_bloc.dart
+DA:14,0
+DA:15,0
+DA:16,0
+DA:17,0
+DA:19,0
+DA:20,0
+DA:21,0
+DA:23,0
+DA:26,0
+DA:27,0
+DA:29,0
+DA:32,0
+DA:34,0
+DA:35,0
+DA:37,0
+DA:38,0
+DA:39,0
+DA:40,0
+DA:41,0
+DA:43,0
+DA:45,0
+DA:46,0
+DA:49,0
+DA:54,0
+DA:55,0
+DA:56,0
+DA:63,0
+DA:67,0
+LF:28
+LH:0
+end_of_record
+SF:lib/presentation/restaurants/restaurants_event.dart
+DA:9,0
+LF:1
+LH:0
+end_of_record
+SF:lib/presentation/restaurants/restaurants_state.dart
+DA:11,1
+DA:23,0
+DA:30,0
+DA:31,0
+DA:32,0
+DA:33,0
+DA:34,0
+DA:35,0
+DA:41,0
+LF:9
+LH:1
+end_of_record
+SF:lib/view/widgets/restaurant_list_widget.dart
+DA:9,1
+DA:11,1
+DA:12,1
+DA:17,1
+DA:19,1
+DA:22,0
+DA:24,0
+DA:25,0
+DA:26,0
+DA:30,1
+DA:32,1
+DA:33,2
+DA:34,1
+DA:35,1
+DA:36,1
+DA:37,1
+DA:40,3
+DA:41,1
+DA:42,1
+DA:43,4
+DA:52,4
+DA:53,0
+DA:54,0
+DA:60,3
+DA:61,1
+DA:62,1
+DA:69,1
+DA:70,0
+DA:71,0
+DA:72,0
+DA:73,0
+DA:77,3
+DA:82,1
+DA:83,0
+DA:84,0
+DA:88,1
+DA:93,1
+LF:37
+LH:25
+end_of_record
+SF:lib/common/exceptions/exceptions.dart
+DA:4,0
+DA:5,0
+DA:7,0
+DA:8,0
+DA:9,0
+DA:10,0
+DA:15,0
+DA:18,0
+DA:22,0
+DA:25,0
+DA:29,0
+DA:32,0
+DA:36,0
+DA:39,0
+DA:43,0
+DA:46,0
+LF:16
+LH:0
+end_of_record
+SF:lib/domain/usecase/restaurants_usecase.dart
+DA:5,1
+DA:8,1
+DA:9,2
+DA:12,1
+DA:13,2
+DA:16,1
+DA:17,2
+DA:20,1
+DA:21,2
+DA:24,1
+DA:25,2
+LF:11
+LH:11
+end_of_record
+SF:lib/presentation/favorites/favorites_restaurants_event.dart
+DA:9,0
+DA:14,0
+LF:2
+LH:0
+end_of_record
+SF:lib/presentation/favorites/favorites_restaurants_state.dart
+DA:11,0
+DA:16,0
+DA:21,0
+DA:26,1
+LF:4
+LH:1
+end_of_record
+SF:lib/presentation/favorites/favorites_restaurants_bloc.dart
+DA:15,0
+DA:16,0
+DA:17,0
+DA:18,0
+DA:20,0
+DA:21,0
+DA:22,0
+DA:24,0
+DA:25,0
+DA:29,0
+DA:31,0
+DA:32,0
+DA:34,0
+DA:35,0
+DA:37,0
+DA:38,0
+DA:39,0
+DA:40,0
+DA:42,0
+DA:43,0
+DA:46,0
+DA:49,0
+DA:50,0
+DA:52,0
+DA:53,0
+DA:55,0
+DA:56,0
+DA:57,0
+DA:58,0
+DA:60,0
+DA:61,0
+DA:62,0
+DA:67,0
+DA:72,0
+DA:76,0
+LF:35
+LH:0
+end_of_record
+SF:lib/view/pages/restaurant_page.dart
+DA:16,0
+DA:22,0
+DA:23,0
+DA:28,0
+DA:30,0
+DA:31,0
+DA:34,0
+DA:36,0
+DA:37,0
+DA:38,0
+DA:39,0
+DA:40,0
+DA:41,0
+DA:42,0
+DA:44,0
+DA:45,0
+DA:48,0
+DA:50,0
+DA:54,0
+DA:55,0
+DA:56,0
+DA:57,0
+DA:58,0
+DA:59,0
+DA:61,0
+DA:64,0
+DA:66,0
+DA:67,0
+DA:69,0
+DA:70,0
+DA:71,0
+DA:72,0
+DA:74,0
+DA:79,0
+DA:80,0
+DA:83,0
+DA:85,0
+LF:37
+LH:0
+end_of_record
+SF:lib/view/widgets/overall_rating_widget.dart
+DA:6,0
+DA:8,0
+DA:10,0
+DA:12,0
+DA:16,0
+DA:17,0
+DA:18,0
+DA:19,0
+DA:20,0
+LF:9
+LH:0
+end_of_record
+SF:lib/view/widgets/restaurant_open_widget.dart
+DA:5,3
+DA:7,3
+DA:9,3
+DA:11,3
+DA:12,3
+DA:13,3
+DA:14,3
+DA:15,3
+DA:16,3
+DA:17,3
+DA:20,3
+DA:22,3
+DA:25,3
+LF:13
+LH:13
+end_of_record
+SF:lib/view/widgets/review_list_widget.dart
+DA:7,0
+DA:9,0
+DA:11,0
+DA:12,0
+DA:14,0
+DA:16,0
+DA:17,0
+DA:18,0
+DA:21,0
+DA:24,0
+DA:25,0
+DA:27,0
+DA:31,0
+LF:13
+LH:0
+end_of_record
+SF:lib/view/widgets/restaurant_tile.dart
+DA:8,3
+DA:11,3
+DA:13,3
+DA:14,12
+DA:15,3
+DA:16,3
+DA:18,3
+DA:20,3
+DA:21,3
+DA:22,6
+DA:23,3
+DA:24,3
+DA:25,3
+DA:26,0
+DA:30,9
+DA:35,3
+DA:36,3
+DA:38,3
+DA:41,3
+DA:42,3
+DA:43,3
+DA:44,6
+DA:45,9
+DA:48,3
+DA:49,3
+DA:50,3
+DA:51,6
+DA:52,9
+DA:55,3
+DA:56,8
+DA:57,9
+DA:61,3
+DA:63,3
+DA:64,3
+DA:65,9
+DA:67,9
+LF:36
+LH:35
+end_of_record
+SF:lib/view/widgets/favorite_list_widget.dart
+DA:9,1
+DA:11,1
+DA:12,1
+DA:16,1
+DA:18,1
+DA:19,2
+DA:20,1
+DA:21,1
+DA:22,1
+DA:23,1
+DA:26,2
+DA:27,1
+DA:28,1
+DA:29,0
+DA:30,0
+DA:31,0
+DA:32,0
+DA:36,1
+DA:37,2
+DA:43,1
+DA:44,0
+DA:45,0
+DA:49,1
+DA:54,1
+LF:24
+LH:18
+end_of_record
diff --git a/coverage/report/amber.png b/coverage/report/amber.png
new file mode 100644
index 0000000..2cab170
Binary files /dev/null and b/coverage/report/amber.png differ
diff --git a/coverage/report/cmd_line b/coverage/report/cmd_line
new file mode 100644
index 0000000..01470c3
--- /dev/null
+++ b/coverage/report/cmd_line
@@ -0,0 +1 @@
+genhtml coverage/lcov.info --output=coverage/report
diff --git a/coverage/report/common/exceptions/exceptions.dart.func-c.html b/coverage/report/common/exceptions/exceptions.dart.func-c.html
new file mode 100644
index 0000000..ad939e1
--- /dev/null
+++ b/coverage/report/common/exceptions/exceptions.dart.func-c.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - common/exceptions/exceptions.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/common/exceptions/exceptions.dart.func.html b/coverage/report/common/exceptions/exceptions.dart.func.html
new file mode 100644
index 0000000..49d0f1f
--- /dev/null
+++ b/coverage/report/common/exceptions/exceptions.dart.func.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - common/exceptions/exceptions.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/common/exceptions/exceptions.dart.gcov.html b/coverage/report/common/exceptions/exceptions.dart.gcov.html
new file mode 100644
index 0000000..2bc5120
--- /dev/null
+++ b/coverage/report/common/exceptions/exceptions.dart.gcov.html
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+ LCOV - lcov.info - common/exceptions/exceptions.dart
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+
+
+ Line data Source code
+
+ 1 : class AppException implements Exception {
+ 2 : String code;
+ 3 : String description;
+ 4 0 : AppException(this.code, this.description);
+ 5 0 : @override
+ 6 : String toString() {
+ 7 0 : return {
+ 8 0 : 'code': code,
+ 9 0 : 'description': description,
+ 10 0 : }.toString();
+ 11 : }
+ 12 : }
+ 13 :
+ 14 : class RestaurantNotFoundException extends AppException {
+ 15 0 : RestaurantNotFoundException({
+ 16 : code = "RESTAURANT_NOT_FOUND",
+ 17 : description = "The restaurant searched is not our dataset",
+ 18 0 : }) : super(code, description);
+ 19 : }
+ 20 :
+ 21 : class RestaurantListException extends AppException {
+ 22 0 : RestaurantListException({
+ 23 : code = "RESTAURANTS_LIST_NOT_AVAILABLE",
+ 24 : description = "The restaurant is not available at the moment",
+ 25 0 : }) : super(code, description);
+ 26 : }
+ 27 :
+ 28 : class FavoritesRestaurantsListException extends AppException {
+ 29 0 : FavoritesRestaurantsListException({
+ 30 : code = "FAVORITES_RESTAURANTS_LIST_NOT_AVAILABLE",
+ 31 : description = "The favorite restaurant are not available at the moment",
+ 32 0 : }) : super(code, description);
+ 33 : }
+ 34 :
+ 35 : class AddFavoriteRestaurantException extends AppException {
+ 36 0 : AddFavoriteRestaurantException({
+ 37 : code = "ADD_FAVORITE_RESTAURANT_EXCEPTION",
+ 38 : description = "Couldn't register the favorite restaurant",
+ 39 0 : }) : super(code, description);
+ 40 : }
+ 41 :
+ 42 : class RemoveFavoriteRestaurantException extends AppException {
+ 43 0 : RemoveFavoriteRestaurantException({
+ 44 : code = "REMOVE_FAVORITE_RESTAURANT_EXCEPTION",
+ 45 : description = "Couldn't remove the favorite restaurant",
+ 46 0 : }) : super(code, description);
+ 47 : }
+
+ |
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/common/exceptions/index-sort-f.html b/coverage/report/common/exceptions/index-sort-f.html
new file mode 100644
index 0000000..628c79b
--- /dev/null
+++ b/coverage/report/common/exceptions/index-sort-f.html
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+ LCOV - lcov.info - common/exceptions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
+
+
|
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+ File  |
+ Line Coverage  |
+ Function Coverage  |
+
+
+ | Rate |
+ Total |
+ Hit |
+ Rate |
+ Total |
+ Hit |
+
+
+ | exceptions.dart |
+
+
+ |
+ 0.0 % |
+ 16 |
+ |
+ - |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/common/exceptions/index-sort-l.html b/coverage/report/common/exceptions/index-sort-l.html
new file mode 100644
index 0000000..c839c96
--- /dev/null
+++ b/coverage/report/common/exceptions/index-sort-l.html
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+ LCOV - lcov.info - common/exceptions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
+
+
|
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+ File  |
+ Line Coverage  |
+ Function Coverage  |
+
+
+ | Rate |
+ Total |
+ Hit |
+ Rate |
+ Total |
+ Hit |
+
+
+ | exceptions.dart |
+
+
+ |
+ 0.0 % |
+ 16 |
+ |
+ - |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/common/exceptions/index.html b/coverage/report/common/exceptions/index.html
new file mode 100644
index 0000000..c9945ed
--- /dev/null
+++ b/coverage/report/common/exceptions/index.html
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+ LCOV - lcov.info - common/exceptions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
+
+
|
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+ File  |
+ Line Coverage  |
+ Function Coverage  |
+
+
+ | Rate |
+ Total |
+ Hit |
+ Rate |
+ Total |
+ Hit |
+
+
+ | exceptions.dart |
+
+
+ |
+ 0.0 % |
+ 16 |
+ |
+ - |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/domain/repository/index-sort-f.html b/coverage/report/domain/repository/index-sort-f.html
new file mode 100644
index 0000000..581b6c0
--- /dev/null
+++ b/coverage/report/domain/repository/index-sort-f.html
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+ LCOV - lcov.info - domain/repository
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
+
+
|
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+ File  |
+ Line Coverage  |
+ Function Coverage  |
+
+
+ | Rate |
+ Total |
+ Hit |
+ Rate |
+ Total |
+ Hit |
+
+
+ | restaurants_repository.dart |
+
+
+ |
+ 83.8 % |
+ 37 |
+ 31 |
+ - |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/domain/repository/index-sort-l.html b/coverage/report/domain/repository/index-sort-l.html
new file mode 100644
index 0000000..35cb4b2
--- /dev/null
+++ b/coverage/report/domain/repository/index-sort-l.html
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+ LCOV - lcov.info - domain/repository
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
+
+
|
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+ File  |
+ Line Coverage  |
+ Function Coverage  |
+
+
+ | Rate |
+ Total |
+ Hit |
+ Rate |
+ Total |
+ Hit |
+
+
+ | restaurants_repository.dart |
+
+
+ |
+ 83.8 % |
+ 37 |
+ 31 |
+ - |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/domain/repository/index.html b/coverage/report/domain/repository/index.html
new file mode 100644
index 0000000..72ae3ca
--- /dev/null
+++ b/coverage/report/domain/repository/index.html
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+ LCOV - lcov.info - domain/repository
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
+
+
|
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+ File  |
+ Line Coverage  |
+ Function Coverage  |
+
+
+ | Rate |
+ Total |
+ Hit |
+ Rate |
+ Total |
+ Hit |
+
+
+ | restaurants_repository.dart |
+
+
+ |
+ 83.8 % |
+ 37 |
+ 31 |
+ - |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/domain/repository/restaurants_repository.dart.func-c.html b/coverage/report/domain/repository/restaurants_repository.dart.func-c.html
new file mode 100644
index 0000000..b8d5f93
--- /dev/null
+++ b/coverage/report/domain/repository/restaurants_repository.dart.func-c.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - domain/repository/restaurants_repository.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/domain/repository/restaurants_repository.dart.func.html b/coverage/report/domain/repository/restaurants_repository.dart.func.html
new file mode 100644
index 0000000..b0be46b
--- /dev/null
+++ b/coverage/report/domain/repository/restaurants_repository.dart.func.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - domain/repository/restaurants_repository.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/domain/repository/restaurants_repository.dart.gcov.html b/coverage/report/domain/repository/restaurants_repository.dart.gcov.html
new file mode 100644
index 0000000..af9a7db
--- /dev/null
+++ b/coverage/report/domain/repository/restaurants_repository.dart.gcov.html
@@ -0,0 +1,155 @@
+
+
+
+
+
+
+ LCOV - lcov.info - domain/repository/restaurants_repository.dart
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+
+
+ Line data Source code
+
+ 1 : import 'package:restaurant_tour/domain/datasource/favorite_restaurants_datasource.dart';
+ 2 : import 'package:restaurant_tour/domain/datasource/restaurants_datasource.dart';
+ 3 : import 'package:restaurant_tour/models/restaurant.dart';
+ 4 :
+ 5 : class RestaurantsRepository {
+ 6 1 : RestaurantsRepository(
+ 7 : this._restaurantsDatasource,
+ 8 : this._favoriteRestaurantsDatasource,
+ 9 : );
+ 10 :
+ 11 : final FavoriteRestaurantsDatasource _favoriteRestaurantsDatasource;
+ 12 : final RestaurantsDatasource _restaurantsDatasource;
+ 13 : final List<Restaurant> _restaurants = [];
+ 14 : final Set<Restaurant> _favorites = {};
+ 15 :
+ 16 1 : Future<List<Restaurant>> getRestaurants() async {
+ 17 2 : if (_restaurants.isEmpty) {
+ 18 2 : final remoteRestaurants = await _restaurantsDatasource.getRestaurants();
+ 19 : final favoritesRestaurants =
+ 20 2 : await _favoriteRestaurantsDatasource.getFavoritesRestaurants();
+ 21 2 : _restaurants.addAll(
+ 22 : remoteRestaurants
+ 23 1 : .map(
+ 24 2 : (e) => favoritesRestaurants.contains(e)
+ 25 1 : ? e.copyWith(isFavorite: true)
+ 26 : : e,
+ 27 : )
+ 28 1 : .toList(),
+ 29 : );
+ 30 : }
+ 31 1 : return _restaurants;
+ 32 : }
+ 33 :
+ 34 0 : Future<void> getMoreRestaurants(int offset, int limit) async {
+ 35 0 : final newRemoteRestaurants = await _restaurantsDatasource.getRestaurants(
+ 36 : offset: offset,
+ 37 : limit: limit,
+ 38 : );
+ 39 0 : _restaurants.addAll(
+ 40 : newRemoteRestaurants
+ 41 0 : .map(
+ 42 0 : (e) => _favorites.contains(e) ? e.copyWith(isFavorite: true) : e,
+ 43 : )
+ 44 0 : .toList(),
+ 45 : );
+ 46 : }
+ 47 :
+ 48 1 : Future<List<Restaurant>> getFavoriteRestaurants() async {
+ 49 2 : if (_favorites.isEmpty) {
+ 50 : final favoritesRestaurants =
+ 51 2 : await _favoriteRestaurantsDatasource.getFavoritesRestaurants();
+ 52 2 : _favorites.addAll(
+ 53 3 : favoritesRestaurants.map((e) => e.copyWith(isFavorite: true)),
+ 54 : );
+ 55 : }
+ 56 :
+ 57 2 : return _favorites.toList();
+ 58 : }
+ 59 :
+ 60 1 : Future<void> addFavoriteRestaurant(Restaurant restaurant) async {
+ 61 3 : _favorites.add(restaurant.copyWith(isFavorite: true));
+ 62 4 : final restaurantIndex = _restaurants.indexWhere((e) => e == restaurant);
+ 63 2 : if (restaurantIndex != -1) {
+ 64 3 : _restaurants[restaurantIndex] = restaurant.copyWith(isFavorite: true);
+ 65 1 : await _favoriteRestaurantsDatasource
+ 66 2 : .addFavoriteRestaurant(restaurant.copyWith(isFavorite: true));
+ 67 : }
+ 68 : }
+ 69 :
+ 70 1 : Future<void> removeFavoriteRestaurant(Restaurant restaurant) async {
+ 71 4 : final restaurantIndex = _restaurants.indexWhere((e) => e == restaurant);
+ 72 2 : if (restaurantIndex != -1) {
+ 73 3 : _restaurants[restaurantIndex] = restaurant.copyWith(isFavorite: false);
+ 74 2 : _favorites.remove(restaurant);
+ 75 1 : await _favoriteRestaurantsDatasource
+ 76 2 : .removeFavoriteRestaurant(restaurant.copyWith(isFavorite: false));
+ 77 : }
+ 78 : }
+ 79 : }
+
+ |
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/domain/usecase/index-sort-f.html b/coverage/report/domain/usecase/index-sort-f.html
new file mode 100644
index 0000000..8f72b56
--- /dev/null
+++ b/coverage/report/domain/usecase/index-sort-f.html
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+ LCOV - lcov.info - domain/usecase
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
+
+
|
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+ File  |
+ Line Coverage  |
+ Function Coverage  |
+
+
+ | Rate |
+ Total |
+ Hit |
+ Rate |
+ Total |
+ Hit |
+
+
+ | restaurants_usecase.dart |
+
+
+ |
+ 100.0 % |
+ 11 |
+ 11 |
+ - |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/domain/usecase/index-sort-l.html b/coverage/report/domain/usecase/index-sort-l.html
new file mode 100644
index 0000000..ecd8136
--- /dev/null
+++ b/coverage/report/domain/usecase/index-sort-l.html
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+ LCOV - lcov.info - domain/usecase
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
+
+
|
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+ File  |
+ Line Coverage  |
+ Function Coverage  |
+
+
+ | Rate |
+ Total |
+ Hit |
+ Rate |
+ Total |
+ Hit |
+
+
+ | restaurants_usecase.dart |
+
+
+ |
+ 100.0 % |
+ 11 |
+ 11 |
+ - |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/domain/usecase/index.html b/coverage/report/domain/usecase/index.html
new file mode 100644
index 0000000..d372152
--- /dev/null
+++ b/coverage/report/domain/usecase/index.html
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+ LCOV - lcov.info - domain/usecase
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
+
+
|
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+ File  |
+ Line Coverage  |
+ Function Coverage  |
+
+
+ | Rate |
+ Total |
+ Hit |
+ Rate |
+ Total |
+ Hit |
+
+
+ | restaurants_usecase.dart |
+
+
+ |
+ 100.0 % |
+ 11 |
+ 11 |
+ - |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/domain/usecase/restaurants_usecase.dart.func-c.html b/coverage/report/domain/usecase/restaurants_usecase.dart.func-c.html
new file mode 100644
index 0000000..a899fb2
--- /dev/null
+++ b/coverage/report/domain/usecase/restaurants_usecase.dart.func-c.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - domain/usecase/restaurants_usecase.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/domain/usecase/restaurants_usecase.dart.func.html b/coverage/report/domain/usecase/restaurants_usecase.dart.func.html
new file mode 100644
index 0000000..d9a6ee2
--- /dev/null
+++ b/coverage/report/domain/usecase/restaurants_usecase.dart.func.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - domain/usecase/restaurants_usecase.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/domain/usecase/restaurants_usecase.dart.gcov.html b/coverage/report/domain/usecase/restaurants_usecase.dart.gcov.html
new file mode 100644
index 0000000..1149ec0
--- /dev/null
+++ b/coverage/report/domain/usecase/restaurants_usecase.dart.gcov.html
@@ -0,0 +1,103 @@
+
+
+
+
+
+
+ LCOV - lcov.info - domain/usecase/restaurants_usecase.dart
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+
+
+ Line data Source code
+
+ 1 : import 'package:restaurant_tour/domain/repository/restaurants_repository.dart';
+ 2 : import 'package:restaurant_tour/models/restaurant.dart';
+ 3 :
+ 4 : class RestaurantsUsecase {
+ 5 1 : const RestaurantsUsecase(this._repository);
+ 6 : final RestaurantsRepository _repository;
+ 7 :
+ 8 1 : Future<List<Restaurant>> getRestaurants() {
+ 9 2 : return _repository.getRestaurants();
+ 10 : }
+ 11 :
+ 12 1 : Future<List<Restaurant>> getFavoriteRestaurants() {
+ 13 2 : return _repository.getFavoriteRestaurants();
+ 14 : }
+ 15 :
+ 16 1 : Future<void> addFavoriteRestaurant(Restaurant restaurant) {
+ 17 2 : return _repository.addFavoriteRestaurant(restaurant);
+ 18 : }
+ 19 :
+ 20 1 : Future<void> removeFavoriteRestaurant(Restaurant restaurant) {
+ 21 2 : return _repository.removeFavoriteRestaurant(restaurant);
+ 22 : }
+ 23 :
+ 24 1 : Future loadMoreRestaurants({required int offset, required int limit}) {
+ 25 2 : return _repository.getMoreRestaurants(offset, limit);
+ 26 : }
+ 27 : }
+
+ |
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/emerald.png b/coverage/report/emerald.png
new file mode 100644
index 0000000..38ad4f4
Binary files /dev/null and b/coverage/report/emerald.png differ
diff --git a/coverage/report/gcov.css b/coverage/report/gcov.css
new file mode 100644
index 0000000..6c23ba9
--- /dev/null
+++ b/coverage/report/gcov.css
@@ -0,0 +1,1101 @@
+/* All views: initial background and text color */
+body
+{
+ color: #000000;
+ background-color: #ffffff;
+}
+
+/* All views: standard link format*/
+a:link
+{
+ color: #284fa8;
+ text-decoration: underline;
+}
+
+/* All views: standard link - visited format */
+a:visited
+{
+ color: #00cb40;
+ text-decoration: underline;
+}
+
+/* All views: standard link - activated format */
+a:active
+{
+ color: #ff0040;
+ text-decoration: underline;
+}
+
+/* All views: main title format */
+td.title
+{
+ text-align: center;
+ padding-bottom: 10px;
+ font-family: sans-serif;
+ font-size: 20pt;
+ font-style: italic;
+ font-weight: bold;
+}
+/* "Line coverage date bins" leader */
+td.subTableHeader
+{
+ text-align: center;
+ padding-bottom: 6px;
+ font-family: sans-serif;
+ font-weight: bold;
+ vertical-align: center;
+}
+
+/* All views: header item format */
+td.headerItem
+{
+ text-align: right;
+ padding-right: 6px;
+ font-family: sans-serif;
+ font-weight: bold;
+ vertical-align: top;
+ white-space: nowrap;
+}
+
+/* All views: header item value format */
+td.headerValue
+{
+ text-align: left;
+ color: #284fa8;
+ font-family: sans-serif;
+ font-weight: bold;
+ white-space: nowrap;
+}
+
+/* All views: header item coverage table heading */
+td.headerCovTableHead
+{
+ text-align: center;
+ padding-right: 6px;
+ padding-left: 6px;
+ padding-bottom: 0px;
+ font-family: sans-serif;
+ white-space: nowrap;
+}
+
+/* All views: header item coverage table entry */
+td.headerCovTableEntry
+{
+ text-align: right;
+ color: #284fa8;
+ font-family: sans-serif;
+ font-weight: bold;
+ white-space: nowrap;
+ padding-left: 12px;
+ padding-right: 4px;
+ background-color: #dae7fe;
+}
+
+/* All views: header item coverage table entry for high coverage rate */
+td.headerCovTableEntryHi
+{
+ text-align: right;
+ color: #000000;
+ font-family: sans-serif;
+ font-weight: bold;
+ white-space: nowrap;
+ padding-left: 12px;
+ padding-right: 4px;
+ background-color: #a7fc9d;
+}
+
+/* All views: header item coverage table entry for medium coverage rate */
+td.headerCovTableEntryMed
+{
+ text-align: right;
+ color: #000000;
+ font-family: sans-serif;
+ font-weight: bold;
+ white-space: nowrap;
+ padding-left: 12px;
+ padding-right: 4px;
+ background-color: #ffea20;
+}
+
+/* All views: header item coverage table entry for ow coverage rate */
+td.headerCovTableEntryLo
+{
+ text-align: right;
+ color: #000000;
+ font-family: sans-serif;
+ font-weight: bold;
+ white-space: nowrap;
+ padding-left: 12px;
+ padding-right: 4px;
+ background-color: #ff0000;
+}
+
+/* All views: header legend value for legend entry */
+td.headerValueLeg
+{
+ text-align: left;
+ color: #000000;
+ font-family: sans-serif;
+ font-size: 80%;
+ white-space: nowrap;
+ padding-top: 4px;
+}
+
+/* All views: color of horizontal ruler */
+td.ruler
+{
+ background-color: #6688d4;
+}
+
+/* All views: version string format */
+td.versionInfo
+{
+ text-align: center;
+ padding-top: 2px;
+ font-family: sans-serif;
+ font-style: italic;
+}
+
+/* Directory view/File view (all)/Test case descriptions:
+ table headline format */
+td.tableHead
+{
+ text-align: center;
+ color: #ffffff;
+ background-color: #6688d4;
+ font-family: sans-serif;
+ font-size: 120%;
+ font-weight: bold;
+ white-space: nowrap;
+ padding-left: 4px;
+ padding-right: 4px;
+}
+
+span.tableHeadSort
+{
+ padding-right: 4px;
+}
+
+/* Directory view/File view (all): filename entry format */
+td.coverFile
+{
+ text-align: left;
+ padding-left: 10px;
+ padding-right: 20px;
+ color: #284fa8;
+ background-color: #dae7fe;
+ font-family: monospace;
+}
+
+/* Directory view/File view (all): directory name entry format */
+td.coverDirectory
+{
+ text-align: left;
+ padding-left: 10px;
+ padding-right: 20px;
+ color: #284fa8;
+ background-color: #b8d0ff;
+ font-family: monospace;
+}
+
+/* Directory view/File view (all): filename entry format */
+td.overallOwner
+{
+ text-align: center;
+ font-weight: bold;
+ font-family: sans-serif;
+ background-color: #dae7fe;
+ padding-right: 10px;
+ padding-left: 10px;
+}
+
+/* Directory view/File view (all): filename entry format */
+td.ownerName
+{
+ text-align: right;
+ font-style: italic;
+ font-family: sans-serif;
+ background-color: #E5DBDB;
+ padding-right: 10px;
+ padding-left: 20px;
+}
+
+/* Directory view/File view (all): bar-graph entry format*/
+td.coverBar
+{
+ padding-left: 10px;
+ padding-right: 10px;
+ background-color: #dae7fe;
+}
+
+/* Directory view/File view (all): bar-graph entry format*/
+td.owner_coverBar
+{
+ padding-left: 10px;
+ padding-right: 10px;
+ background-color: #E5DBDB;
+}
+
+/* Directory view/File view (all): bar-graph outline color */
+td.coverBarOutline
+{
+ background-color: #000000;
+}
+
+/* Directory view/File view (all): percentage entry for files with
+ high coverage rate */
+td.coverPerHi
+{
+ text-align: right;
+ padding-left: 10px;
+ padding-right: 10px;
+ background-color: #a7fc9d;
+ font-weight: bold;
+ font-family: sans-serif;
+}
+
+/* 'owner' entry: slightly lighter color than 'coverPerHi' */
+td.owner_coverPerHi
+{
+ text-align: right;
+ padding-left: 10px;
+ padding-right: 10px;
+ background-color: #82E0AA;
+ font-weight: bold;
+ font-family: sans-serif;
+}
+
+/* Directory view/File view (all): line count entry */
+td.coverNumDflt
+{
+ text-align: right;
+ padding-left: 10px;
+ padding-right: 10px;
+ background-color: #dae7fe;
+ white-space: nowrap;
+ font-family: sans-serif;
+}
+
+/* td background color and font for the 'owner' section of the table */
+td.ownerTla
+{
+ text-align: right;
+ padding-left: 10px;
+ padding-right: 10px;
+ background-color: #E5DBDB;
+ white-space: nowrap;
+ font-family: sans-serif;
+ font-style: italic;
+}
+
+/* Directory view/File view (all): line count entry for files with
+ high coverage rate */
+td.coverNumHi
+{
+ text-align: right;
+ padding-left: 10px;
+ padding-right: 10px;
+ background-color: #a7fc9d;
+ white-space: nowrap;
+ font-family: sans-serif;
+}
+
+td.owner_coverNumHi
+{
+ text-align: right;
+ padding-left: 10px;
+ padding-right: 10px;
+ background-color: #82E0AA;
+ white-space: nowrap;
+ font-family: sans-serif;
+}
+
+/* Directory view/File view (all): percentage entry for files with
+ medium coverage rate */
+td.coverPerMed
+{
+ text-align: right;
+ padding-left: 10px;
+ padding-right: 10px;
+ background-color: #ffea20;
+ font-weight: bold;
+ font-family: sans-serif;
+}
+
+td.owner_coverPerMed
+{
+ text-align: right;
+ padding-left: 10px;
+ padding-right: 10px;
+ background-color: #F9E79F;
+ font-weight: bold;
+ font-family: sans-serif;
+}
+
+/* Directory view/File view (all): line count entry for files with
+ medium coverage rate */
+td.coverNumMed
+{
+ text-align: right;
+ padding-left: 10px;
+ padding-right: 10px;
+ background-color: #ffea20;
+ white-space: nowrap;
+ font-family: sans-serif;
+}
+
+td.owner_coverNumMed
+{
+ text-align: right;
+ padding-left: 10px;
+ padding-right: 10px;
+ background-color: #F9E79F;
+ white-space: nowrap;
+ font-family: sans-serif;
+}
+
+/* Directory view/File view (all): percentage entry for files with
+ low coverage rate */
+td.coverPerLo
+{
+ text-align: right;
+ padding-left: 10px;
+ padding-right: 10px;
+ background-color: #ff0000;
+ font-weight: bold;
+ font-family: sans-serif;
+}
+
+td.owner_coverPerLo
+{
+ text-align: right;
+ padding-left: 10px;
+ padding-right: 10px;
+ background-color: #EC7063;
+ font-weight: bold;
+ font-family: sans-serif;
+}
+
+/* Directory view/File view (all): line count entry for files with
+ low coverage rate */
+td.coverNumLo
+{
+ text-align: right;
+ padding-left: 10px;
+ padding-right: 10px;
+ background-color: #ff0000;
+ white-space: nowrap;
+ font-family: sans-serif;
+}
+
+td.owner_coverNumLo
+{
+ text-align: right;
+ padding-left: 10px;
+ padding-right: 10px;
+ background-color: #EC7063;
+ white-space: nowrap;
+ font-family: sans-serif;
+}
+
+/* File view (all): "show/hide details" link format */
+a.detail:link
+{
+ color: #b8d0ff;
+ font-size:80%;
+}
+
+/* File view (all): "show/hide details" link - visited format */
+a.detail:visited
+{
+ color: #b8d0ff;
+ font-size:80%;
+}
+
+/* File view (all): "show/hide details" link - activated format */
+a.detail:active
+{
+ color: #ffffff;
+ font-size:80%;
+}
+
+/* File view (detail): test name entry */
+td.testName
+{
+ text-align: right;
+ padding-right: 10px;
+ background-color: #dae7fe;
+ font-family: sans-serif;
+}
+
+/* File view (detail): test percentage entry */
+td.testPer
+{
+ text-align: right;
+ padding-left: 10px;
+ padding-right: 10px;
+ background-color: #dae7fe;
+ font-family: sans-serif;
+}
+
+/* File view (detail): test lines count entry */
+td.testNum
+{
+ text-align: right;
+ padding-left: 10px;
+ padding-right: 10px;
+ background-color: #dae7fe;
+ font-family: sans-serif;
+}
+
+/* Test case descriptions: test name format*/
+dt
+{
+ font-family: sans-serif;
+ font-weight: bold;
+}
+
+/* Test case descriptions: description table body */
+td.testDescription
+{
+ padding-top: 10px;
+ padding-left: 30px;
+ padding-bottom: 10px;
+ padding-right: 30px;
+ background-color: #dae7fe;
+}
+
+/* Source code view: function entry */
+td.coverFn
+{
+ text-align: left;
+ padding-left: 10px;
+ padding-right: 20px;
+ color: #284fa8;
+ background-color: #dae7fe;
+ font-family: monospace;
+}
+
+/* Source code view: function entry zero count*/
+td.coverFnLo
+{
+ text-align: right;
+ padding-left: 10px;
+ padding-right: 10px;
+ background-color: #ff0000;
+ font-weight: bold;
+ font-family: sans-serif;
+}
+
+/* Source code view: function entry nonzero count*/
+td.coverFnHi
+{
+ text-align: right;
+ padding-left: 10px;
+ padding-right: 10px;
+ background-color: #dae7fe;
+ font-weight: bold;
+ font-family: sans-serif;
+}
+
+td.coverFnAlias
+{
+ text-align: right;
+ padding-left: 10px;
+ padding-right: 20px;
+ color: #284fa8;
+ /* make this a slightly different color than the leader - otherwise,
+ otherwise the alias is hard to distinguish in the table */
+ background-color: #E5DBDB; /* very light pale grey/blue */
+ font-family: monospace;
+}
+
+/* Source code view: function entry zero count*/
+td.coverFnAliasLo
+{
+ text-align: right;
+ padding-left: 10px;
+ padding-right: 10px;
+ background-color: #EC7063; /* lighter red */
+ font-family: sans-serif;
+}
+
+/* Source code view: function entry nonzero count*/
+td.coverFnAliasHi
+{
+ text-align: right;
+ padding-left: 10px;
+ padding-right: 10px;
+ background-color: #dae7fe;
+ font-weight: bold;
+ font-family: sans-serif;
+}
+
+/* Source code view: source code format */
+pre.source
+{
+ font-family: monospace;
+ white-space: pre;
+ margin-top: 2px;
+}
+
+/* elided/removed code */
+span.elidedSource
+{
+ font-family: sans-serif;
+ /*font-size: 8pt; */
+ font-style: italic;
+ background-color: lightgrey;
+}
+
+/* Source code view: line number format */
+span.lineNum
+{
+ background-color: #efe383;
+}
+
+/* Source code view: line number format when there are deleted
+ lines in the corresponding location */
+span.lineNumWithDelete
+{
+ foreground-color: #efe383;
+ background-color: lightgrey;
+}
+
+/* Source code view: format for Cov legend */
+span.coverLegendCov
+{
+ padding-left: 10px;
+ padding-right: 10px;
+ padding-bottom: 2px;
+ background-color: #cad7fe;
+}
+
+/* Source code view: format for NoCov legend */
+span.coverLegendNoCov
+{
+ padding-left: 10px;
+ padding-right: 10px;
+ padding-bottom: 2px;
+ background-color: #ff6230;
+}
+
+/* Source code view: format for the source code heading line */
+pre.sourceHeading
+{
+ white-space: pre;
+ font-family: monospace;
+ font-weight: bold;
+ margin: 0px;
+}
+
+/* All views: header legend value for low rate */
+td.headerValueLegL
+{
+ font-family: sans-serif;
+ text-align: center;
+ white-space: nowrap;
+ padding-left: 4px;
+ padding-right: 2px;
+ background-color: #ff0000;
+ font-size: 80%;
+}
+
+/* All views: header legend value for med rate */
+td.headerValueLegM
+{
+ font-family: sans-serif;
+ text-align: center;
+ white-space: nowrap;
+ padding-left: 2px;
+ padding-right: 2px;
+ background-color: #ffea20;
+ font-size: 80%;
+}
+
+/* All views: header legend value for hi rate */
+td.headerValueLegH
+{
+ font-family: sans-serif;
+ text-align: center;
+ white-space: nowrap;
+ padding-left: 2px;
+ padding-right: 4px;
+ background-color: #a7fc9d;
+ font-size: 80%;
+}
+
+/* All views except source code view: legend format for low coverage */
+span.coverLegendCovLo
+{
+ padding-left: 10px;
+ padding-right: 10px;
+ padding-top: 2px;
+ background-color: #ff0000;
+}
+
+/* All views except source code view: legend format for med coverage */
+span.coverLegendCovMed
+{
+ padding-left: 10px;
+ padding-right: 10px;
+ padding-top: 2px;
+ background-color: #ffea20;
+}
+
+/* All views except source code view: legend format for hi coverage */
+span.coverLegendCovHi
+{
+ padding-left: 10px;
+ padding-right: 10px;
+ padding-top: 2px;
+ background-color: #a7fc9d;
+}
+
+a.branchTla:link
+{
+ color: #000000;
+}
+
+a.branchTla:visited
+{
+ color: #000000;
+}
+
+/* Source code view/table entry background: format for lines classified as "Uncovered New Code (+ => 0):
+Newly added code is not tested" */
+td.tlaUNC
+{
+ text-align: right;
+ background-color: #FF6230;
+}
+td.tlaBgUNC {
+ background-color: #FF6230;
+}
+
+/* Source code view/table entry background: format for lines classified as "Uncovered New Code (+ => 0):
+Newly added code is not tested" */
+span.tlaUNC
+{
+ text-align: left;
+ background-color: #FF6230;
+}
+span.tlaBgUNC {
+ background-color: #FF6230;
+}
+a.tlaBgUNC {
+ background-color: #FF6230;
+ color: #000000;
+}
+
+td.headerCovTableHeadUNC {
+ text-align: center;
+ padding-right: 6px;
+ padding-left: 6px;
+ padding-bottom: 0px;
+ font-family: sans-serif;
+ white-space: nowrap;
+ background-color: #FF6230;
+}
+
+/* Source code view/table entry background: format for lines classified as "Lost Baseline Coverage (1 => 0):
+Unchanged code is no longer tested" */
+td.tlaLBC
+{
+ text-align: right;
+ background-color: #FF6230;
+}
+td.tlaBgLBC {
+ background-color: #FF6230;
+}
+
+/* Source code view/table entry background: format for lines classified as "Lost Baseline Coverage (1 => 0):
+Unchanged code is no longer tested" */
+span.tlaLBC
+{
+ text-align: left;
+ background-color: #FF6230;
+}
+span.tlaBgLBC {
+ background-color: #FF6230;
+}
+a.tlaBgLBC {
+ background-color: #FF6230;
+ color: #000000;
+}
+
+td.headerCovTableHeadLBC {
+ text-align: center;
+ padding-right: 6px;
+ padding-left: 6px;
+ padding-bottom: 0px;
+ font-family: sans-serif;
+ white-space: nowrap;
+ background-color: #FF6230;
+}
+
+/* Source code view/table entry background: format for lines classified as "Uncovered Included Code (# => 0):
+Previously unused code is untested" */
+td.tlaUIC
+{
+ text-align: right;
+ background-color: #FF6230;
+}
+td.tlaBgUIC {
+ background-color: #FF6230;
+}
+
+/* Source code view/table entry background: format for lines classified as "Uncovered Included Code (# => 0):
+Previously unused code is untested" */
+span.tlaUIC
+{
+ text-align: left;
+ background-color: #FF6230;
+}
+span.tlaBgUIC {
+ background-color: #FF6230;
+}
+a.tlaBgUIC {
+ background-color: #FF6230;
+ color: #000000;
+}
+
+td.headerCovTableHeadUIC {
+ text-align: center;
+ padding-right: 6px;
+ padding-left: 6px;
+ padding-bottom: 0px;
+ font-family: sans-serif;
+ white-space: nowrap;
+ background-color: #FF6230;
+}
+
+/* Source code view/table entry background: format for lines classified as "Uncovered Baseline Code (0 => 0):
+Unchanged code was untested before, is untested now" */
+td.tlaUBC
+{
+ text-align: right;
+ background-color: #FF6230;
+}
+td.tlaBgUBC {
+ background-color: #FF6230;
+}
+
+/* Source code view/table entry background: format for lines classified as "Uncovered Baseline Code (0 => 0):
+Unchanged code was untested before, is untested now" */
+span.tlaUBC
+{
+ text-align: left;
+ background-color: #FF6230;
+}
+span.tlaBgUBC {
+ background-color: #FF6230;
+}
+a.tlaBgUBC {
+ background-color: #FF6230;
+ color: #000000;
+}
+
+td.headerCovTableHeadUBC {
+ text-align: center;
+ padding-right: 6px;
+ padding-left: 6px;
+ padding-bottom: 0px;
+ font-family: sans-serif;
+ white-space: nowrap;
+ background-color: #FF6230;
+}
+
+/* Source code view/table entry background: format for lines classified as "Gained Baseline Coverage (0 => 1):
+Unchanged code is tested now" */
+td.tlaGBC
+{
+ text-align: right;
+ background-color: #CAD7FE;
+}
+td.tlaBgGBC {
+ background-color: #CAD7FE;
+}
+
+/* Source code view/table entry background: format for lines classified as "Gained Baseline Coverage (0 => 1):
+Unchanged code is tested now" */
+span.tlaGBC
+{
+ text-align: left;
+ background-color: #CAD7FE;
+}
+span.tlaBgGBC {
+ background-color: #CAD7FE;
+}
+a.tlaBgGBC {
+ background-color: #CAD7FE;
+ color: #000000;
+}
+
+td.headerCovTableHeadGBC {
+ text-align: center;
+ padding-right: 6px;
+ padding-left: 6px;
+ padding-bottom: 0px;
+ font-family: sans-serif;
+ white-space: nowrap;
+ background-color: #CAD7FE;
+}
+
+/* Source code view/table entry background: format for lines classified as "Gained Included Coverage (# => 1):
+Previously unused code is tested now" */
+td.tlaGIC
+{
+ text-align: right;
+ background-color: #CAD7FE;
+}
+td.tlaBgGIC {
+ background-color: #CAD7FE;
+}
+
+/* Source code view/table entry background: format for lines classified as "Gained Included Coverage (# => 1):
+Previously unused code is tested now" */
+span.tlaGIC
+{
+ text-align: left;
+ background-color: #CAD7FE;
+}
+span.tlaBgGIC {
+ background-color: #CAD7FE;
+}
+a.tlaBgGIC {
+ background-color: #CAD7FE;
+ color: #000000;
+}
+
+td.headerCovTableHeadGIC {
+ text-align: center;
+ padding-right: 6px;
+ padding-left: 6px;
+ padding-bottom: 0px;
+ font-family: sans-serif;
+ white-space: nowrap;
+ background-color: #CAD7FE;
+}
+
+/* Source code view/table entry background: format for lines classified as "Gained New Coverage (+ => 1):
+Newly added code is tested" */
+td.tlaGNC
+{
+ text-align: right;
+ background-color: #CAD7FE;
+}
+td.tlaBgGNC {
+ background-color: #CAD7FE;
+}
+
+/* Source code view/table entry background: format for lines classified as "Gained New Coverage (+ => 1):
+Newly added code is tested" */
+span.tlaGNC
+{
+ text-align: left;
+ background-color: #CAD7FE;
+}
+span.tlaBgGNC {
+ background-color: #CAD7FE;
+}
+a.tlaBgGNC {
+ background-color: #CAD7FE;
+ color: #000000;
+}
+
+td.headerCovTableHeadGNC {
+ text-align: center;
+ padding-right: 6px;
+ padding-left: 6px;
+ padding-bottom: 0px;
+ font-family: sans-serif;
+ white-space: nowrap;
+ background-color: #CAD7FE;
+}
+
+/* Source code view/table entry background: format for lines classified as "Covered Baseline Code (1 => 1):
+Unchanged code was tested before and is still tested" */
+td.tlaCBC
+{
+ text-align: right;
+ background-color: #CAD7FE;
+}
+td.tlaBgCBC {
+ background-color: #CAD7FE;
+}
+
+/* Source code view/table entry background: format for lines classified as "Covered Baseline Code (1 => 1):
+Unchanged code was tested before and is still tested" */
+span.tlaCBC
+{
+ text-align: left;
+ background-color: #CAD7FE;
+}
+span.tlaBgCBC {
+ background-color: #CAD7FE;
+}
+a.tlaBgCBC {
+ background-color: #CAD7FE;
+ color: #000000;
+}
+
+td.headerCovTableHeadCBC {
+ text-align: center;
+ padding-right: 6px;
+ padding-left: 6px;
+ padding-bottom: 0px;
+ font-family: sans-serif;
+ white-space: nowrap;
+ background-color: #CAD7FE;
+}
+
+/* Source code view/table entry background: format for lines classified as "Excluded Uncovered Baseline (0 => #):
+Previously untested code is unused now" */
+td.tlaEUB
+{
+ text-align: right;
+ background-color: #FFFFFF;
+}
+td.tlaBgEUB {
+ background-color: #FFFFFF;
+}
+
+/* Source code view/table entry background: format for lines classified as "Excluded Uncovered Baseline (0 => #):
+Previously untested code is unused now" */
+span.tlaEUB
+{
+ text-align: left;
+ background-color: #FFFFFF;
+}
+span.tlaBgEUB {
+ background-color: #FFFFFF;
+}
+a.tlaBgEUB {
+ background-color: #FFFFFF;
+ color: #000000;
+}
+
+td.headerCovTableHeadEUB {
+ text-align: center;
+ padding-right: 6px;
+ padding-left: 6px;
+ padding-bottom: 0px;
+ font-family: sans-serif;
+ white-space: nowrap;
+ background-color: #FFFFFF;
+}
+
+/* Source code view/table entry background: format for lines classified as "Excluded Covered Baseline (1 => #):
+Previously tested code is unused now" */
+td.tlaECB
+{
+ text-align: right;
+ background-color: #FFFFFF;
+}
+td.tlaBgECB {
+ background-color: #FFFFFF;
+}
+
+/* Source code view/table entry background: format for lines classified as "Excluded Covered Baseline (1 => #):
+Previously tested code is unused now" */
+span.tlaECB
+{
+ text-align: left;
+ background-color: #FFFFFF;
+}
+span.tlaBgECB {
+ background-color: #FFFFFF;
+}
+a.tlaBgECB {
+ background-color: #FFFFFF;
+ color: #000000;
+}
+
+td.headerCovTableHeadECB {
+ text-align: center;
+ padding-right: 6px;
+ padding-left: 6px;
+ padding-bottom: 0px;
+ font-family: sans-serif;
+ white-space: nowrap;
+ background-color: #FFFFFF;
+}
+
+/* Source code view/table entry background: format for lines classified as "Deleted Uncovered Baseline (0 => -):
+Previously untested code has been deleted" */
+td.tlaDUB
+{
+ text-align: right;
+ background-color: #FFFFFF;
+}
+td.tlaBgDUB {
+ background-color: #FFFFFF;
+}
+
+/* Source code view/table entry background: format for lines classified as "Deleted Uncovered Baseline (0 => -):
+Previously untested code has been deleted" */
+span.tlaDUB
+{
+ text-align: left;
+ background-color: #FFFFFF;
+}
+span.tlaBgDUB {
+ background-color: #FFFFFF;
+}
+a.tlaBgDUB {
+ background-color: #FFFFFF;
+ color: #000000;
+}
+
+td.headerCovTableHeadDUB {
+ text-align: center;
+ padding-right: 6px;
+ padding-left: 6px;
+ padding-bottom: 0px;
+ font-family: sans-serif;
+ white-space: nowrap;
+ background-color: #FFFFFF;
+}
+
+/* Source code view/table entry background: format for lines classified as "Deleted Covered Baseline (1 => -):
+Previously tested code has been deleted" */
+td.tlaDCB
+{
+ text-align: right;
+ background-color: #FFFFFF;
+}
+td.tlaBgDCB {
+ background-color: #FFFFFF;
+}
+
+/* Source code view/table entry background: format for lines classified as "Deleted Covered Baseline (1 => -):
+Previously tested code has been deleted" */
+span.tlaDCB
+{
+ text-align: left;
+ background-color: #FFFFFF;
+}
+span.tlaBgDCB {
+ background-color: #FFFFFF;
+}
+a.tlaBgDCB {
+ background-color: #FFFFFF;
+ color: #000000;
+}
+
+td.headerCovTableHeadDCB {
+ text-align: center;
+ padding-right: 6px;
+ padding-left: 6px;
+ padding-bottom: 0px;
+ font-family: sans-serif;
+ white-space: nowrap;
+ background-color: #FFFFFF;
+}
+
+/* Source code view: format for date/owner bin that is not hit */
+span.missBins
+{
+ background-color: #ff0000 /* red */
+}
diff --git a/coverage/report/glass.png b/coverage/report/glass.png
new file mode 100644
index 0000000..e1abc00
Binary files /dev/null and b/coverage/report/glass.png differ
diff --git a/coverage/report/index-sort-f.html b/coverage/report/index-sort-f.html
new file mode 100644
index 0000000..c22cf48
--- /dev/null
+++ b/coverage/report/index-sort-f.html
@@ -0,0 +1,189 @@
+
+
+
+
+
+
+ LCOV - lcov.info
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/index-sort-l.html b/coverage/report/index-sort-l.html
new file mode 100644
index 0000000..c28804c
--- /dev/null
+++ b/coverage/report/index-sort-l.html
@@ -0,0 +1,189 @@
+
+
+
+
+
+
+ LCOV - lcov.info
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/index.html b/coverage/report/index.html
new file mode 100644
index 0000000..17e9bc3
--- /dev/null
+++ b/coverage/report/index.html
@@ -0,0 +1,189 @@
+
+
+
+
+
+
+ LCOV - lcov.info
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/models/index-sort-f.html b/coverage/report/models/index-sort-f.html
new file mode 100644
index 0000000..e8801d3
--- /dev/null
+++ b/coverage/report/models/index-sort-f.html
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+ LCOV - lcov.info - models
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
+
+
|
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+ File  |
+ Line Coverage  |
+ Function Coverage  |
+
+
+ | Rate |
+ Total |
+ Hit |
+ Rate |
+ Total |
+ Hit |
+
+
+ | restaurant.dart |
+
+
+ |
+ 43.8 % |
+ 48 |
+ 21 |
+ - |
+ |
+ |
+
+
+ | restaurant.g.dart |
+
+
+ |
+ 0.0 % |
+ 73 |
+ |
+ - |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/models/index-sort-l.html b/coverage/report/models/index-sort-l.html
new file mode 100644
index 0000000..b220af2
--- /dev/null
+++ b/coverage/report/models/index-sort-l.html
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+ LCOV - lcov.info - models
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
+
+
|
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+ File  |
+ Line Coverage  |
+ Function Coverage  |
+
+
+ | Rate |
+ Total |
+ Hit |
+ Rate |
+ Total |
+ Hit |
+
+
+ | restaurant.g.dart |
+
+
+ |
+ 0.0 % |
+ 73 |
+ |
+ - |
+ |
+ |
+
+
+ | restaurant.dart |
+
+
+ |
+ 43.8 % |
+ 48 |
+ 21 |
+ - |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/models/index.html b/coverage/report/models/index.html
new file mode 100644
index 0000000..80e09e8
--- /dev/null
+++ b/coverage/report/models/index.html
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+ LCOV - lcov.info - models
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
+
+
|
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+ File  |
+ Line Coverage  |
+ Function Coverage  |
+
+
+ | Rate |
+ Total |
+ Hit |
+ Rate |
+ Total |
+ Hit |
+
+
+ | restaurant.dart |
+
+
+ |
+ 43.8 % |
+ 48 |
+ 21 |
+ - |
+ |
+ |
+
+
+ | restaurant.g.dart |
+
+
+ |
+ 0.0 % |
+ 73 |
+ |
+ - |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/models/restaurant.dart.func-c.html b/coverage/report/models/restaurant.dart.func-c.html
new file mode 100644
index 0000000..02c30fa
--- /dev/null
+++ b/coverage/report/models/restaurant.dart.func-c.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - models/restaurant.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/models/restaurant.dart.func.html b/coverage/report/models/restaurant.dart.func.html
new file mode 100644
index 0000000..fa27c71
--- /dev/null
+++ b/coverage/report/models/restaurant.dart.func.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - models/restaurant.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/models/restaurant.dart.gcov.html b/coverage/report/models/restaurant.dart.gcov.html
new file mode 100644
index 0000000..d1df434
--- /dev/null
+++ b/coverage/report/models/restaurant.dart.gcov.html
@@ -0,0 +1,265 @@
+
+
+
+
+
+
+ LCOV - lcov.info - models/restaurant.dart
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+
+
+ Line data Source code
+
+ 1 : import 'package:equatable/equatable.dart';
+ 2 : import 'package:json_annotation/json_annotation.dart';
+ 3 :
+ 4 : part 'restaurant.g.dart';
+ 5 :
+ 6 : @JsonSerializable()
+ 7 : class Category {
+ 8 : final String? alias;
+ 9 : final String? title;
+ 10 :
+ 11 1 : Category({
+ 12 : this.alias,
+ 13 : this.title,
+ 14 : });
+ 15 :
+ 16 0 : factory Category.fromJson(Map<String, dynamic> json) =>
+ 17 0 : _$CategoryFromJson(json);
+ 18 :
+ 19 0 : Map<String, dynamic> toJson() => _$CategoryToJson(this);
+ 20 : }
+ 21 :
+ 22 : @JsonSerializable()
+ 23 : class Hours {
+ 24 : @JsonKey(name: 'is_open_now')
+ 25 : final bool? isOpenNow;
+ 26 :
+ 27 1 : const Hours({
+ 28 : this.isOpenNow,
+ 29 : });
+ 30 :
+ 31 0 : factory Hours.fromJson(Map<String, dynamic> json) => _$HoursFromJson(json);
+ 32 :
+ 33 0 : Map<String, dynamic> toJson() => _$HoursToJson(this);
+ 34 : }
+ 35 :
+ 36 : @JsonSerializable()
+ 37 : class User {
+ 38 : final String? id;
+ 39 : @JsonKey(name: 'image_url')
+ 40 : final String? imageUrl;
+ 41 : final String? name;
+ 42 :
+ 43 1 : const User({
+ 44 : this.id,
+ 45 : this.imageUrl,
+ 46 : this.name,
+ 47 : });
+ 48 :
+ 49 0 : factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
+ 50 :
+ 51 0 : Map<String, dynamic> toJson() => _$UserToJson(this);
+ 52 : }
+ 53 :
+ 54 : @JsonSerializable()
+ 55 : class Review {
+ 56 : final String? id;
+ 57 : final int? rating;
+ 58 : final String? text;
+ 59 : final User? user;
+ 60 :
+ 61 1 : const Review({
+ 62 : this.id,
+ 63 : this.rating,
+ 64 : this.user,
+ 65 : this.text,
+ 66 : });
+ 67 :
+ 68 0 : factory Review.fromJson(Map<String, dynamic> json) => _$ReviewFromJson(json);
+ 69 :
+ 70 0 : Map<String, dynamic> toJson() => _$ReviewToJson(this);
+ 71 : }
+ 72 :
+ 73 : @JsonSerializable()
+ 74 : class Location {
+ 75 : @JsonKey(name: 'formatted_address')
+ 76 : final String? formattedAddress;
+ 77 :
+ 78 0 : Location({
+ 79 : this.formattedAddress,
+ 80 : });
+ 81 :
+ 82 0 : factory Location.fromJson(Map<String, dynamic> json) =>
+ 83 0 : _$LocationFromJson(json);
+ 84 :
+ 85 0 : Map<String, dynamic> toJson() => _$LocationToJson(this);
+ 86 : }
+ 87 :
+ 88 : @JsonSerializable()
+ 89 : class Restaurant extends Equatable {
+ 90 : final String? id;
+ 91 : final String? name;
+ 92 : final String? price;
+ 93 : final double? rating;
+ 94 : final List<String>? photos;
+ 95 : final List<Category>? categories;
+ 96 : final List<Hours>? hours;
+ 97 : final List<Review>? reviews;
+ 98 : final Location? location;
+ 99 : final bool? isFavorite;
+ 100 :
+ 101 6 : const Restaurant({
+ 102 : this.id,
+ 103 : this.name,
+ 104 : this.price,
+ 105 : this.rating,
+ 106 : this.photos,
+ 107 : this.categories,
+ 108 : this.hours,
+ 109 : this.reviews,
+ 110 : this.location,
+ 111 : this.isFavorite,
+ 112 : });
+ 113 :
+ 114 1 : Restaurant copyWith({
+ 115 : String? id,
+ 116 : String? name,
+ 117 : String? price,
+ 118 : double? rating,
+ 119 : List<String>? photos,
+ 120 : List<Category>? categories,
+ 121 : List<Hours>? hours,
+ 122 : List<Review>? reviews,
+ 123 : Location? location,
+ 124 : bool? isFavorite,
+ 125 : }) {
+ 126 1 : return Restaurant(
+ 127 1 : id: id ?? this.id,
+ 128 1 : name: name ?? this.name,
+ 129 1 : price: price ?? this.price,
+ 130 1 : rating: rating ?? this.rating,
+ 131 1 : photos: photos ?? this.photos,
+ 132 1 : categories: categories ?? this.categories,
+ 133 1 : hours: hours ?? this.hours,
+ 134 1 : reviews: reviews ?? this.reviews,
+ 135 1 : location: location ?? this.location,
+ 136 0 : isFavorite: isFavorite ?? this.isFavorite,
+ 137 : );
+ 138 : }
+ 139 :
+ 140 0 : factory Restaurant.fromJson(Map<String, dynamic> json) =>
+ 141 0 : _$RestaurantFromJson(json);
+ 142 :
+ 143 0 : Map<String, dynamic> toJson() => _$RestaurantToJson(this);
+ 144 :
+ 145 : /// Use the first category for the category shown to the user
+ 146 0 : String get displayCategory {
+ 147 0 : if (categories != null && categories!.isNotEmpty) {
+ 148 0 : return categories!.first.title ?? '';
+ 149 : }
+ 150 : return '';
+ 151 : }
+ 152 :
+ 153 : /// Use the first image as the image shown to the user
+ 154 0 : String get heroImage {
+ 155 0 : if (photos != null && photos!.isNotEmpty) {
+ 156 0 : return photos!.first;
+ 157 : }
+ 158 : return '';
+ 159 : }
+ 160 :
+ 161 : /// This logic is probably not correct in all cases but it is ok
+ 162 : /// for this application
+ 163 3 : bool get isOpen {
+ 164 5 : if (hours != null && hours!.isNotEmpty) {
+ 165 3 : return hours!.first.isOpenNow ?? false;
+ 166 : }
+ 167 : return false;
+ 168 : }
+ 169 :
+ 170 1 : @override
+ 171 2 : List<Object?> get props => [id];
+ 172 : }
+ 173 :
+ 174 : @JsonSerializable()
+ 175 : class RestaurantQueryResult {
+ 176 : final int? total;
+ 177 : @JsonKey(name: 'business')
+ 178 : final List<Restaurant>? restaurants;
+ 179 :
+ 180 0 : const RestaurantQueryResult({
+ 181 : this.total,
+ 182 : this.restaurants,
+ 183 : });
+ 184 :
+ 185 0 : factory RestaurantQueryResult.fromJson(Map<String, dynamic> json) =>
+ 186 0 : _$RestaurantQueryResultFromJson(json);
+ 187 :
+ 188 0 : Map<String, dynamic> toJson() => _$RestaurantQueryResultToJson(this);
+ 189 : }
+
+ |
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/models/restaurant.g.dart.func-c.html b/coverage/report/models/restaurant.g.dart.func-c.html
new file mode 100644
index 0000000..8d8a077
--- /dev/null
+++ b/coverage/report/models/restaurant.g.dart.func-c.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - models/restaurant.g.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/models/restaurant.g.dart.func.html b/coverage/report/models/restaurant.g.dart.func.html
new file mode 100644
index 0000000..5a36319
--- /dev/null
+++ b/coverage/report/models/restaurant.g.dart.func.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - models/restaurant.g.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/models/restaurant.g.dart.gcov.html b/coverage/report/models/restaurant.g.dart.gcov.html
new file mode 100644
index 0000000..f51d9b3
--- /dev/null
+++ b/coverage/report/models/restaurant.g.dart.gcov.html
@@ -0,0 +1,189 @@
+
+
+
+
+
+
+ LCOV - lcov.info - models/restaurant.g.dart
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+
+
+ Line data Source code
+
+ 1 : // GENERATED CODE - DO NOT MODIFY BY HAND
+ 2 :
+ 3 : part of 'restaurant.dart';
+ 4 :
+ 5 : // **************************************************************************
+ 6 : // JsonSerializableGenerator
+ 7 : // **************************************************************************
+ 8 :
+ 9 0 : Category _$CategoryFromJson(Map<String, dynamic> json) => Category(
+ 10 0 : alias: json['alias'] as String?,
+ 11 0 : title: json['title'] as String?,
+ 12 : );
+ 13 :
+ 14 0 : Map<String, dynamic> _$CategoryToJson(Category instance) => <String, dynamic>{
+ 15 0 : 'alias': instance.alias,
+ 16 0 : 'title': instance.title,
+ 17 : };
+ 18 :
+ 19 0 : Hours _$HoursFromJson(Map<String, dynamic> json) => Hours(
+ 20 0 : isOpenNow: json['is_open_now'] as bool?,
+ 21 : );
+ 22 :
+ 23 0 : Map<String, dynamic> _$HoursToJson(Hours instance) => <String, dynamic>{
+ 24 0 : 'is_open_now': instance.isOpenNow,
+ 25 : };
+ 26 :
+ 27 0 : User _$UserFromJson(Map<String, dynamic> json) => User(
+ 28 0 : id: json['id'] as String?,
+ 29 0 : imageUrl: json['image_url'] as String?,
+ 30 0 : name: json['name'] as String?,
+ 31 : );
+ 32 :
+ 33 0 : Map<String, dynamic> _$UserToJson(User instance) => <String, dynamic>{
+ 34 0 : 'id': instance.id,
+ 35 0 : 'image_url': instance.imageUrl,
+ 36 0 : 'name': instance.name,
+ 37 : };
+ 38 :
+ 39 0 : Review _$ReviewFromJson(Map<String, dynamic> json) => Review(
+ 40 0 : id: json['id'] as String?,
+ 41 0 : rating: (json['rating'] as num?)?.toInt(),
+ 42 0 : user: json['user'] == null
+ 43 : ? null
+ 44 0 : : User.fromJson(json['user'] as Map<String, dynamic>),
+ 45 0 : text: json['text'] as String?,
+ 46 : );
+ 47 :
+ 48 0 : Map<String, dynamic> _$ReviewToJson(Review instance) => <String, dynamic>{
+ 49 0 : 'id': instance.id,
+ 50 0 : 'rating': instance.rating,
+ 51 0 : 'text': instance.text,
+ 52 0 : 'user': instance.user,
+ 53 : };
+ 54 :
+ 55 0 : Location _$LocationFromJson(Map<String, dynamic> json) => Location(
+ 56 0 : formattedAddress: json['formatted_address'] as String?,
+ 57 : );
+ 58 :
+ 59 0 : Map<String, dynamic> _$LocationToJson(Location instance) => <String, dynamic>{
+ 60 0 : 'formatted_address': instance.formattedAddress,
+ 61 : };
+ 62 :
+ 63 0 : Restaurant _$RestaurantFromJson(Map<String, dynamic> json) => Restaurant(
+ 64 0 : id: json['id'] as String?,
+ 65 0 : name: json['name'] as String?,
+ 66 0 : price: json['price'] as String?,
+ 67 0 : rating: (json['rating'] as num?)?.toDouble(),
+ 68 : photos:
+ 69 0 : (json['photos'] as List<dynamic>?)?.map((e) => e as String).toList(),
+ 70 0 : categories: (json['categories'] as List<dynamic>?)
+ 71 0 : ?.map((e) => Category.fromJson(e as Map<String, dynamic>))
+ 72 0 : .toList(),
+ 73 0 : hours: (json['hours'] as List<dynamic>?)
+ 74 0 : ?.map((e) => Hours.fromJson(e as Map<String, dynamic>))
+ 75 0 : .toList(),
+ 76 0 : reviews: (json['reviews'] as List<dynamic>?)
+ 77 0 : ?.map((e) => Review.fromJson(e as Map<String, dynamic>))
+ 78 0 : .toList(),
+ 79 0 : location: json['location'] == null
+ 80 : ? null
+ 81 0 : : Location.fromJson(json['location'] as Map<String, dynamic>),
+ 82 0 : isFavorite: json['isFavorite'] as bool?,
+ 83 : );
+ 84 :
+ 85 0 : Map<String, dynamic> _$RestaurantToJson(Restaurant instance) =>
+ 86 0 : <String, dynamic>{
+ 87 0 : 'id': instance.id,
+ 88 0 : 'name': instance.name,
+ 89 0 : 'price': instance.price,
+ 90 0 : 'rating': instance.rating,
+ 91 0 : 'photos': instance.photos,
+ 92 0 : 'categories': instance.categories,
+ 93 0 : 'hours': instance.hours,
+ 94 0 : 'reviews': instance.reviews,
+ 95 0 : 'location': instance.location,
+ 96 0 : 'isFavorite': instance.isFavorite,
+ 97 : };
+ 98 :
+ 99 0 : RestaurantQueryResult _$RestaurantQueryResultFromJson(
+ 100 : Map<String, dynamic> json) =>
+ 101 0 : RestaurantQueryResult(
+ 102 0 : total: (json['total'] as num?)?.toInt(),
+ 103 0 : restaurants: (json['business'] as List<dynamic>?)
+ 104 0 : ?.map((e) => Restaurant.fromJson(e as Map<String, dynamic>))
+ 105 0 : .toList(),
+ 106 : );
+ 107 :
+ 108 0 : Map<String, dynamic> _$RestaurantQueryResultToJson(
+ 109 : RestaurantQueryResult instance) =>
+ 110 0 : <String, dynamic>{
+ 111 0 : 'total': instance.total,
+ 112 0 : 'business': instance.restaurants,
+ 113 : };
+
+ |
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/presentation/favorites/favorites_restaurants_bloc.dart.func-c.html b/coverage/report/presentation/favorites/favorites_restaurants_bloc.dart.func-c.html
new file mode 100644
index 0000000..944c347
--- /dev/null
+++ b/coverage/report/presentation/favorites/favorites_restaurants_bloc.dart.func-c.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - presentation/favorites/favorites_restaurants_bloc.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/presentation/favorites/favorites_restaurants_bloc.dart.func.html b/coverage/report/presentation/favorites/favorites_restaurants_bloc.dart.func.html
new file mode 100644
index 0000000..dfa99d9
--- /dev/null
+++ b/coverage/report/presentation/favorites/favorites_restaurants_bloc.dart.func.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - presentation/favorites/favorites_restaurants_bloc.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/presentation/favorites/favorites_restaurants_bloc.dart.gcov.html b/coverage/report/presentation/favorites/favorites_restaurants_bloc.dart.gcov.html
new file mode 100644
index 0000000..f4268b3
--- /dev/null
+++ b/coverage/report/presentation/favorites/favorites_restaurants_bloc.dart.gcov.html
@@ -0,0 +1,154 @@
+
+
+
+
+
+
+ LCOV - lcov.info - presentation/favorites/favorites_restaurants_bloc.dart
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+
+
+ Line data Source code
+
+ 1 : import 'package:bloc/bloc.dart';
+ 2 : import 'package:bloc_concurrency/bloc_concurrency.dart';
+ 3 : import 'package:flutter/material.dart';
+ 4 : // ignore: depend_on_referenced_packages, unnecessary_import
+ 5 : import 'package:meta/meta.dart';
+ 6 : import 'package:restaurant_tour/common/exceptions/exceptions.dart';
+ 7 : import 'package:restaurant_tour/domain/usecase/restaurants_usecase.dart';
+ 8 : import 'package:restaurant_tour/models/restaurant.dart';
+ 9 :
+ 10 : part 'favorites_restaurants_event.dart';
+ 11 : part 'favorites_restaurants_state.dart';
+ 12 :
+ 13 : class FavoritesRestaurantsBloc
+ 14 : extends Bloc<FavoritesRestaurantsEvent, FavoritesRestaurantsState> {
+ 15 0 : FavoritesRestaurantsBloc(this.usecase)
+ 16 0 : : super(FavoritesRestaurantsInitial()) {
+ 17 0 : on<LoadFavoritesRestaurants>(
+ 18 0 : (event, emit) async {
+ 19 : try {
+ 20 0 : emit(FavoritesRestaurantsLoading());
+ 21 0 : final favorites = await usecase.getFavoriteRestaurants();
+ 22 0 : emit(FavoritesRestaurantsReady(favorites));
+ 23 : } catch (e) {
+ 24 0 : emit(
+ 25 0 : FavoriteRestaurantsListError(FavoritesRestaurantsListException()),
+ 26 : );
+ 27 : }
+ 28 : },
+ 29 0 : transformer: sequential(),
+ 30 : );
+ 31 0 : on<AddFavoriteRestaurant>(
+ 32 0 : (event, emit) async {
+ 33 : try {
+ 34 0 : while (state is FavoritesRestaurantsLoading) {
+ 35 0 : Future.delayed(const Duration(milliseconds: 500));
+ 36 : }
+ 37 0 : emit(FavoritesRestaurantsLoading());
+ 38 0 : await usecase.addFavoriteRestaurant(event.restaurant);
+ 39 0 : final favoritesRestaurants = await usecase.getFavoriteRestaurants();
+ 40 0 : emit(FavoritesRestaurantsReady(favoritesRestaurants));
+ 41 : } catch (e) {
+ 42 0 : debugPrint(e.toString());
+ 43 0 : emit(AddFavoriteRestaurantsError(AddFavoriteRestaurantException()));
+ 44 : }
+ 45 : },
+ 46 0 : transformer: sequential(),
+ 47 : );
+ 48 :
+ 49 0 : on<RemoveFavoriteRestaurant>(
+ 50 0 : (event, emit) async {
+ 51 : try {
+ 52 0 : while (state is FavoritesRestaurantsLoading) {
+ 53 0 : Future.delayed(const Duration(milliseconds: 500));
+ 54 : }
+ 55 0 : emit(FavoritesRestaurantsLoading());
+ 56 0 : await usecase.removeFavoriteRestaurant(event.restaurant);
+ 57 0 : final favoritesRestaurants = await usecase.getFavoriteRestaurants();
+ 58 0 : emit(FavoritesRestaurantsReady(favoritesRestaurants));
+ 59 : } catch (e) {
+ 60 0 : emit(
+ 61 0 : RemoveFavoriteRestaurantsError(
+ 62 0 : RemoveFavoriteRestaurantException(),
+ 63 : ),
+ 64 : );
+ 65 : }
+ 66 : },
+ 67 0 : transformer: sequential(),
+ 68 : );
+ 69 : }
+ 70 : final RestaurantsUsecase usecase;
+ 71 :
+ 72 0 : @override
+ 73 : void onChange(Change<FavoritesRestaurantsState> change) {
+ 74 : // debugPrint(
+ 75 : // change.currentState.toString() + " - " + change.nextState.toString());
+ 76 0 : super.onChange(change);
+ 77 : }
+ 78 : }
+
+ |
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/presentation/favorites/favorites_restaurants_event.dart.func-c.html b/coverage/report/presentation/favorites/favorites_restaurants_event.dart.func-c.html
new file mode 100644
index 0000000..7fdb847
--- /dev/null
+++ b/coverage/report/presentation/favorites/favorites_restaurants_event.dart.func-c.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - presentation/favorites/favorites_restaurants_event.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/presentation/favorites/favorites_restaurants_event.dart.func.html b/coverage/report/presentation/favorites/favorites_restaurants_event.dart.func.html
new file mode 100644
index 0000000..d698840
--- /dev/null
+++ b/coverage/report/presentation/favorites/favorites_restaurants_event.dart.func.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - presentation/favorites/favorites_restaurants_event.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/presentation/favorites/favorites_restaurants_event.dart.gcov.html b/coverage/report/presentation/favorites/favorites_restaurants_event.dart.gcov.html
new file mode 100644
index 0000000..3983061
--- /dev/null
+++ b/coverage/report/presentation/favorites/favorites_restaurants_event.dart.gcov.html
@@ -0,0 +1,92 @@
+
+
+
+
+
+
+ LCOV - lcov.info - presentation/favorites/favorites_restaurants_event.dart
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+
+
+ Line data Source code
+
+ 1 : part of 'favorites_restaurants_bloc.dart';
+ 2 :
+ 3 : @immutable
+ 4 : sealed class FavoritesRestaurantsEvent {}
+ 5 :
+ 6 : class LoadFavoritesRestaurants extends FavoritesRestaurantsEvent {}
+ 7 :
+ 8 : class AddFavoriteRestaurant extends FavoritesRestaurantsEvent {
+ 9 0 : AddFavoriteRestaurant(this.restaurant);
+ 10 : final Restaurant restaurant;
+ 11 : }
+ 12 :
+ 13 : class RemoveFavoriteRestaurant extends FavoritesRestaurantsEvent {
+ 14 0 : RemoveFavoriteRestaurant(this.restaurant);
+ 15 : final Restaurant restaurant;
+ 16 : }
+
+ |
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/presentation/favorites/favorites_restaurants_state.dart.func-c.html b/coverage/report/presentation/favorites/favorites_restaurants_state.dart.func-c.html
new file mode 100644
index 0000000..d4c12c6
--- /dev/null
+++ b/coverage/report/presentation/favorites/favorites_restaurants_state.dart.func-c.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - presentation/favorites/favorites_restaurants_state.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/presentation/favorites/favorites_restaurants_state.dart.func.html b/coverage/report/presentation/favorites/favorites_restaurants_state.dart.func.html
new file mode 100644
index 0000000..be02594
--- /dev/null
+++ b/coverage/report/presentation/favorites/favorites_restaurants_state.dart.func.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - presentation/favorites/favorites_restaurants_state.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/presentation/favorites/favorites_restaurants_state.dart.gcov.html b/coverage/report/presentation/favorites/favorites_restaurants_state.dart.gcov.html
new file mode 100644
index 0000000..e8d8766
--- /dev/null
+++ b/coverage/report/presentation/favorites/favorites_restaurants_state.dart.gcov.html
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+ LCOV - lcov.info - presentation/favorites/favorites_restaurants_state.dart
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+
+
+ Line data Source code
+
+ 1 : part of 'favorites_restaurants_bloc.dart';
+ 2 :
+ 3 : @immutable
+ 4 : sealed class FavoritesRestaurantsState {}
+ 5 :
+ 6 : final class FavoritesRestaurantsInitial extends FavoritesRestaurantsState {}
+ 7 :
+ 8 : final class FavoritesRestaurantsLoading extends FavoritesRestaurantsState {}
+ 9 :
+ 10 : final class FavoriteRestaurantsListError extends FavoritesRestaurantsState {
+ 11 0 : FavoriteRestaurantsListError(this.exception);
+ 12 : final FavoritesRestaurantsListException exception;
+ 13 : }
+ 14 :
+ 15 : final class AddFavoriteRestaurantsError extends FavoritesRestaurantsState {
+ 16 0 : AddFavoriteRestaurantsError(this.exception);
+ 17 : final AddFavoriteRestaurantException exception;
+ 18 : }
+ 19 :
+ 20 : final class RemoveFavoriteRestaurantsError extends FavoritesRestaurantsState {
+ 21 0 : RemoveFavoriteRestaurantsError(this.exception);
+ 22 : final RemoveFavoriteRestaurantException exception;
+ 23 : }
+ 24 :
+ 25 : final class FavoritesRestaurantsReady extends FavoritesRestaurantsState {
+ 26 1 : FavoritesRestaurantsReady(this.favoritesRestaurants);
+ 27 : final List<Restaurant> favoritesRestaurants;
+ 28 : }
+
+ |
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/presentation/favorites/index-sort-f.html b/coverage/report/presentation/favorites/index-sort-f.html
new file mode 100644
index 0000000..bf620c0
--- /dev/null
+++ b/coverage/report/presentation/favorites/index-sort-f.html
@@ -0,0 +1,129 @@
+
+
+
+
+
+
+ LCOV - lcov.info - presentation/favorites
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/presentation/favorites/index-sort-l.html b/coverage/report/presentation/favorites/index-sort-l.html
new file mode 100644
index 0000000..fccf352
--- /dev/null
+++ b/coverage/report/presentation/favorites/index-sort-l.html
@@ -0,0 +1,129 @@
+
+
+
+
+
+
+ LCOV - lcov.info - presentation/favorites
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/presentation/favorites/index.html b/coverage/report/presentation/favorites/index.html
new file mode 100644
index 0000000..46fbfc6
--- /dev/null
+++ b/coverage/report/presentation/favorites/index.html
@@ -0,0 +1,129 @@
+
+
+
+
+
+
+ LCOV - lcov.info - presentation/favorites
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/presentation/restaurants/index-sort-f.html b/coverage/report/presentation/restaurants/index-sort-f.html
new file mode 100644
index 0000000..1ce5e1f
--- /dev/null
+++ b/coverage/report/presentation/restaurants/index-sort-f.html
@@ -0,0 +1,129 @@
+
+
+
+
+
+
+ LCOV - lcov.info - presentation/restaurants
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/presentation/restaurants/index-sort-l.html b/coverage/report/presentation/restaurants/index-sort-l.html
new file mode 100644
index 0000000..ec3d77b
--- /dev/null
+++ b/coverage/report/presentation/restaurants/index-sort-l.html
@@ -0,0 +1,129 @@
+
+
+
+
+
+
+ LCOV - lcov.info - presentation/restaurants
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/presentation/restaurants/index.html b/coverage/report/presentation/restaurants/index.html
new file mode 100644
index 0000000..02dae2e
--- /dev/null
+++ b/coverage/report/presentation/restaurants/index.html
@@ -0,0 +1,129 @@
+
+
+
+
+
+
+ LCOV - lcov.info - presentation/restaurants
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/presentation/restaurants/restaurants_bloc.dart.func-c.html b/coverage/report/presentation/restaurants/restaurants_bloc.dart.func-c.html
new file mode 100644
index 0000000..ba83a31
--- /dev/null
+++ b/coverage/report/presentation/restaurants/restaurants_bloc.dart.func-c.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - presentation/restaurants/restaurants_bloc.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/presentation/restaurants/restaurants_bloc.dart.func.html b/coverage/report/presentation/restaurants/restaurants_bloc.dart.func.html
new file mode 100644
index 0000000..01ec8d6
--- /dev/null
+++ b/coverage/report/presentation/restaurants/restaurants_bloc.dart.func.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - presentation/restaurants/restaurants_bloc.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/presentation/restaurants/restaurants_bloc.dart.gcov.html b/coverage/report/presentation/restaurants/restaurants_bloc.dart.gcov.html
new file mode 100644
index 0000000..7adde54
--- /dev/null
+++ b/coverage/report/presentation/restaurants/restaurants_bloc.dart.gcov.html
@@ -0,0 +1,145 @@
+
+
+
+
+
+
+ LCOV - lcov.info - presentation/restaurants/restaurants_bloc.dart
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+
+
+ Line data Source code
+
+ 1 : import 'package:bloc/bloc.dart';
+ 2 : import 'package:bloc_concurrency/bloc_concurrency.dart';
+ 3 : import 'package:flutter/material.dart';
+ 4 : // ignore: depend_on_referenced_packages, unnecessary_import
+ 5 : import 'package:meta/meta.dart';
+ 6 : import 'package:restaurant_tour/common/exceptions/exceptions.dart';
+ 7 : import 'package:restaurant_tour/domain/usecase/restaurants_usecase.dart';
+ 8 : import 'package:restaurant_tour/models/restaurant.dart';
+ 9 :
+ 10 : part 'restaurants_event.dart';
+ 11 : part 'restaurants_state.dart';
+ 12 :
+ 13 : class RestaurantsBloc extends Bloc<RestaurantsEvent, RestaurantsState> {
+ 14 0 : RestaurantsBloc(this.usecase) : super(RestaurantsInitial()) {
+ 15 0 : on<LoadRestaurants>(
+ 16 0 : (event, emit) async {
+ 17 0 : emit(RestaurantsLoading());
+ 18 : try {
+ 19 0 : final restaurants = await usecase.getRestaurants();
+ 20 0 : emit(
+ 21 0 : RestaurantsReady(
+ 22 : restaurants,
+ 23 0 : size: restaurants.length,
+ 24 : ),
+ 25 : );
+ 26 0 : } on RestaurantListException catch (e) {
+ 27 0 : emit(RestaurantsError(e));
+ 28 : } catch (e) {
+ 29 0 : emit(RestaurantsError(RestaurantListException()));
+ 30 : }
+ 31 : },
+ 32 0 : transformer: sequential(),
+ 33 : );
+ 34 0 : on<AddMoreRestaurants>(
+ 35 0 : (event, emit) async {
+ 36 : try {
+ 37 0 : if (state is RestaurantsReady) {
+ 38 0 : emit((state as RestaurantsReady).copyWith(isLoadingMore: true));
+ 39 0 : await usecase.loadMoreRestaurants(
+ 40 0 : offset: event.offset,
+ 41 0 : limit: event.limit,
+ 42 : );
+ 43 0 : final restaurants = await usecase.getRestaurants();
+ 44 :
+ 45 0 : emit(
+ 46 0 : (state as RestaurantsReady).copyWith(
+ 47 : isLoadingMore: false,
+ 48 : restaurants: restaurants,
+ 49 0 : size: restaurants.length,
+ 50 : ),
+ 51 : );
+ 52 : }
+ 53 : } catch (e) {
+ 54 0 : emit(
+ 55 0 : (state as RestaurantsReady)
+ 56 0 : .copyWith(isLoadingMore: false, hasError: true),
+ 57 : );
+ 58 : }
+ 59 : },
+ 60 : );
+ 61 : }
+ 62 : final RestaurantsUsecase usecase;
+ 63 0 : @override
+ 64 : void onChange(Change<RestaurantsState> change) {
+ 65 : // debugPrint(
+ 66 : // change.currentState.toString() + " - " + change.nextState.toString());
+ 67 0 : super.onChange(change);
+ 68 : }
+ 69 : }
+
+ |
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/presentation/restaurants/restaurants_event.dart.func-c.html b/coverage/report/presentation/restaurants/restaurants_event.dart.func-c.html
new file mode 100644
index 0000000..199545f
--- /dev/null
+++ b/coverage/report/presentation/restaurants/restaurants_event.dart.func-c.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - presentation/restaurants/restaurants_event.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/presentation/restaurants/restaurants_event.dart.func.html b/coverage/report/presentation/restaurants/restaurants_event.dart.func.html
new file mode 100644
index 0000000..c3b9252
--- /dev/null
+++ b/coverage/report/presentation/restaurants/restaurants_event.dart.func.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - presentation/restaurants/restaurants_event.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/presentation/restaurants/restaurants_event.dart.gcov.html b/coverage/report/presentation/restaurants/restaurants_event.dart.gcov.html
new file mode 100644
index 0000000..d25d71d
--- /dev/null
+++ b/coverage/report/presentation/restaurants/restaurants_event.dart.gcov.html
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+ LCOV - lcov.info - presentation/restaurants/restaurants_event.dart
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+
+
+ Line data Source code
+
+ 1 : part of 'restaurants_bloc.dart';
+ 2 :
+ 3 : @immutable
+ 4 : sealed class RestaurantsEvent {}
+ 5 :
+ 6 : class LoadRestaurants extends RestaurantsEvent {}
+ 7 :
+ 8 : class AddMoreRestaurants extends RestaurantsEvent {
+ 9 0 : AddMoreRestaurants({required this.limit, required this.offset});
+ 10 : final int limit;
+ 11 : final int offset;
+ 12 : }
+
+ |
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/presentation/restaurants/restaurants_state.dart.func-c.html b/coverage/report/presentation/restaurants/restaurants_state.dart.func-c.html
new file mode 100644
index 0000000..5383a1d
--- /dev/null
+++ b/coverage/report/presentation/restaurants/restaurants_state.dart.func-c.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - presentation/restaurants/restaurants_state.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/presentation/restaurants/restaurants_state.dart.func.html b/coverage/report/presentation/restaurants/restaurants_state.dart.func.html
new file mode 100644
index 0000000..a4365e6
--- /dev/null
+++ b/coverage/report/presentation/restaurants/restaurants_state.dart.func.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - presentation/restaurants/restaurants_state.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/presentation/restaurants/restaurants_state.dart.gcov.html b/coverage/report/presentation/restaurants/restaurants_state.dart.gcov.html
new file mode 100644
index 0000000..e093596
--- /dev/null
+++ b/coverage/report/presentation/restaurants/restaurants_state.dart.gcov.html
@@ -0,0 +1,119 @@
+
+
+
+
+
+
+ LCOV - lcov.info - presentation/restaurants/restaurants_state.dart
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+
+
+ Line data Source code
+
+ 1 : part of 'restaurants_bloc.dart';
+ 2 :
+ 3 : @immutable
+ 4 : sealed class RestaurantsState {}
+ 5 :
+ 6 : final class RestaurantsInitial extends RestaurantsState {}
+ 7 :
+ 8 : final class RestaurantsLoading extends RestaurantsState {}
+ 9 :
+ 10 : final class RestaurantsReady extends RestaurantsState {
+ 11 1 : RestaurantsReady(
+ 12 : this.restaurants, {
+ 13 : this.isLoadingMore = false,
+ 14 : this.size = 10,
+ 15 : this.limit = 10,
+ 16 : this.hasError = false,
+ 17 : });
+ 18 : final List<Restaurant> restaurants;
+ 19 : final bool isLoadingMore;
+ 20 : final bool hasError;
+ 21 : final int size;
+ 22 : final int limit;
+ 23 0 : RestaurantsReady copyWith({
+ 24 : List<Restaurant>? restaurants,
+ 25 : bool? isLoadingMore,
+ 26 : int? size,
+ 27 : int? limit,
+ 28 : bool? hasError,
+ 29 : }) {
+ 30 0 : return RestaurantsReady(
+ 31 0 : restaurants ?? this.restaurants,
+ 32 0 : isLoadingMore: isLoadingMore ?? this.isLoadingMore,
+ 33 0 : size: size ?? this.size,
+ 34 0 : hasError: hasError ?? this.hasError,
+ 35 0 : limit: limit ?? this.limit,
+ 36 : );
+ 37 : }
+ 38 : }
+ 39 :
+ 40 : final class RestaurantsError extends RestaurantsState {
+ 41 0 : RestaurantsError(this.exception);
+ 42 : final RestaurantListException exception;
+ 43 : }
+
+ |
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/ruby.png b/coverage/report/ruby.png
new file mode 100644
index 0000000..991b6d4
Binary files /dev/null and b/coverage/report/ruby.png differ
diff --git a/coverage/report/snow.png b/coverage/report/snow.png
new file mode 100644
index 0000000..2cdae10
Binary files /dev/null and b/coverage/report/snow.png differ
diff --git a/coverage/report/updown.png b/coverage/report/updown.png
new file mode 100644
index 0000000..aa56a23
Binary files /dev/null and b/coverage/report/updown.png differ
diff --git a/coverage/report/view/pages/index-sort-f.html b/coverage/report/view/pages/index-sort-f.html
new file mode 100644
index 0000000..207a439
--- /dev/null
+++ b/coverage/report/view/pages/index-sort-f.html
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/pages
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
+
+
|
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+ File  |
+ Line Coverage  |
+ Function Coverage  |
+
+
+ | Rate |
+ Total |
+ Hit |
+ Rate |
+ Total |
+ Hit |
+
+
+ | restaurant_page.dart |
+
+
+ |
+ 0.0 % |
+ 37 |
+ |
+ - |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/pages/index-sort-l.html b/coverage/report/view/pages/index-sort-l.html
new file mode 100644
index 0000000..f43bf8e
--- /dev/null
+++ b/coverage/report/view/pages/index-sort-l.html
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/pages
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
+
+
|
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+ File  |
+ Line Coverage  |
+ Function Coverage  |
+
+
+ | Rate |
+ Total |
+ Hit |
+ Rate |
+ Total |
+ Hit |
+
+
+ | restaurant_page.dart |
+
+
+ |
+ 0.0 % |
+ 37 |
+ |
+ - |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/pages/index.html b/coverage/report/view/pages/index.html
new file mode 100644
index 0000000..77a82e4
--- /dev/null
+++ b/coverage/report/view/pages/index.html
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/pages
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
+
+
|
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+ File  |
+ Line Coverage  |
+ Function Coverage  |
+
+
+ | Rate |
+ Total |
+ Hit |
+ Rate |
+ Total |
+ Hit |
+
+
+ | restaurant_page.dart |
+
+
+ |
+ 0.0 % |
+ 37 |
+ |
+ - |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/pages/restaurant_page.dart.func-c.html b/coverage/report/view/pages/restaurant_page.dart.func-c.html
new file mode 100644
index 0000000..1138856
--- /dev/null
+++ b/coverage/report/view/pages/restaurant_page.dart.func-c.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/pages/restaurant_page.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/pages/restaurant_page.dart.func.html b/coverage/report/view/pages/restaurant_page.dart.func.html
new file mode 100644
index 0000000..c1b71b7
--- /dev/null
+++ b/coverage/report/view/pages/restaurant_page.dart.func.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/pages/restaurant_page.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/pages/restaurant_page.dart.gcov.html b/coverage/report/view/pages/restaurant_page.dart.gcov.html
new file mode 100644
index 0000000..4f269e6
--- /dev/null
+++ b/coverage/report/view/pages/restaurant_page.dart.gcov.html
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/pages/restaurant_page.dart
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+
+
+ Line data Source code
+
+ 1 : import 'package:flutter/material.dart';
+ 2 : import 'package:gap/gap.dart';
+ 3 : import 'package:get_it/get_it.dart';
+ 4 : import 'package:restaurant_tour/models/restaurant.dart';
+ 5 : import 'package:restaurant_tour/presentation/favorites/favorites_restaurants_bloc.dart';
+ 6 : import 'package:restaurant_tour/presentation/restaurants/restaurants_bloc.dart';
+ 7 : import 'package:restaurant_tour/view/widgets/address_widget.dart';
+ 8 : import 'package:restaurant_tour/view/widgets/favorite_button_widget.dart';
+ 9 : import 'package:restaurant_tour/view/widgets/overall_rating_widget.dart';
+ 10 : import 'package:restaurant_tour/view/widgets/restaurant_category_price_widget.dart';
+ 11 : import 'package:restaurant_tour/view/widgets/restaurant_hero_widget.dart';
+ 12 : import 'package:restaurant_tour/view/widgets/restaurant_open_widget.dart';
+ 13 : import 'package:restaurant_tour/view/widgets/review_list_widget.dart';
+ 14 :
+ 15 : class RestaurantPage extends StatefulWidget {
+ 16 0 : const RestaurantPage({
+ 17 : super.key,
+ 18 : required this.restaurant,
+ 19 : });
+ 20 : final Restaurant restaurant;
+ 21 :
+ 22 0 : @override
+ 23 0 : State<RestaurantPage> createState() => _RestaurantPageState();
+ 24 : }
+ 25 :
+ 26 : class _RestaurantPageState extends State<RestaurantPage> {
+ 27 : late bool isFavoriteState = false;
+ 28 0 : @override
+ 29 : void initState() {
+ 30 0 : isFavoriteState = widget.restaurant.isFavorite ?? false;
+ 31 0 : super.initState();
+ 32 : }
+ 33 :
+ 34 0 : @override
+ 35 : Widget build(BuildContext context) {
+ 36 0 : return Scaffold(
+ 37 0 : appBar: AppBar(
+ 38 0 : title: Text(widget.restaurant.name ?? 'Restaurant Name'),
+ 39 0 : actions: [
+ 40 0 : FavoriteButtonWidget(
+ 41 0 : callback: (isFavorite) {
+ 42 0 : GetIt.I.get<FavoritesRestaurantsBloc>().add(
+ 43 : (isFavorite)
+ 44 0 : ? AddFavoriteRestaurant(widget.restaurant)
+ 45 0 : : RemoveFavoriteRestaurant(widget.restaurant),
+ 46 : );
+ 47 :
+ 48 0 : GetIt.I.get<RestaurantsBloc>().add(LoadRestaurants());
+ 49 : },
+ 50 0 : isFavorite: widget.restaurant.isFavorite,
+ 51 : ),
+ 52 : ],
+ 53 : ),
+ 54 0 : body: SingleChildScrollView(
+ 55 0 : child: Column(
+ 56 0 : children: [
+ 57 0 : RestaurantHeroWidget(
+ 58 0 : imageUrl: widget.restaurant.photos?.first,
+ 59 0 : tag: widget.restaurant.id,
+ 60 : ),
+ 61 0 : Padding(
+ 62 : padding:
+ 63 : const EdgeInsets.only(left: 24.0, top: 24.0, right: 24.0),
+ 64 0 : child: Column(
+ 65 : crossAxisAlignment: CrossAxisAlignment.start,
+ 66 0 : children: [
+ 67 0 : Row(
+ 68 : mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ 69 0 : children: [
+ 70 0 : RestaurantCategoryPriceWidget(
+ 71 0 : price: widget.restaurant.price,
+ 72 0 : category: widget.restaurant.categories?.first.title,
+ 73 : ),
+ 74 0 : RestaurantOpenWidget(widget.restaurant.isOpen),
+ 75 : ],
+ 76 : ),
+ 77 : const Gap(16),
+ 78 : const Divider(),
+ 79 0 : AddressWidget(
+ 80 0 : address: widget.restaurant.location?.formattedAddress,
+ 81 : ),
+ 82 : const Divider(),
+ 83 0 : OverallRatingWidget(rating: widget.restaurant.rating),
+ 84 : const Divider(),
+ 85 0 : ReviewListWidget(reviews: widget.restaurant.reviews),
+ 86 : ],
+ 87 : ),
+ 88 : ),
+ 89 : ],
+ 90 : ),
+ 91 : ),
+ 92 : );
+ 93 : }
+ 94 : }
+
+ |
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/widgets/address_widget.dart.func-c.html b/coverage/report/view/widgets/address_widget.dart.func-c.html
new file mode 100644
index 0000000..6e67f69
--- /dev/null
+++ b/coverage/report/view/widgets/address_widget.dart.func-c.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/widgets/address_widget.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/widgets/address_widget.dart.func.html b/coverage/report/view/widgets/address_widget.dart.func.html
new file mode 100644
index 0000000..592b237
--- /dev/null
+++ b/coverage/report/view/widgets/address_widget.dart.func.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/widgets/address_widget.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/widgets/address_widget.dart.gcov.html b/coverage/report/view/widgets/address_widget.dart.gcov.html
new file mode 100644
index 0000000..f584d60
--- /dev/null
+++ b/coverage/report/view/widgets/address_widget.dart.gcov.html
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/widgets/address_widget.dart
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+
+
+ Line data Source code
+
+ 1 : import 'package:flutter/material.dart';
+ 2 : import 'package:gap/gap.dart';
+ 3 :
+ 4 : class AddressWidget extends StatelessWidget {
+ 5 1 : const AddressWidget({required this.address, super.key});
+ 6 : final String? address;
+ 7 1 : @override
+ 8 : Widget build(BuildContext context) {
+ 9 1 : return Column(
+ 10 : crossAxisAlignment: CrossAxisAlignment.start,
+ 11 1 : children: [
+ 12 : const Gap(16),
+ 13 : const Text('Address'),
+ 14 : const Gap(16),
+ 15 1 : Text(
+ 16 1 : address ?? 'Address info',
+ 17 1 : style: Theme.of(context)
+ 18 1 : .textTheme
+ 19 1 : .titleLarge!
+ 20 1 : .copyWith(fontFamily: 'OpenSans', fontWeight: FontWeight.w600),
+ 21 : ),
+ 22 : const Gap(16),
+ 23 : ],
+ 24 : );
+ 25 : }
+ 26 : }
+
+ |
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/widgets/favorite_button_widget.dart.func-c.html b/coverage/report/view/widgets/favorite_button_widget.dart.func-c.html
new file mode 100644
index 0000000..38a2c1e
--- /dev/null
+++ b/coverage/report/view/widgets/favorite_button_widget.dart.func-c.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/widgets/favorite_button_widget.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/widgets/favorite_button_widget.dart.func.html b/coverage/report/view/widgets/favorite_button_widget.dart.func.html
new file mode 100644
index 0000000..8525604
--- /dev/null
+++ b/coverage/report/view/widgets/favorite_button_widget.dart.func.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/widgets/favorite_button_widget.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/widgets/favorite_button_widget.dart.gcov.html b/coverage/report/view/widgets/favorite_button_widget.dart.gcov.html
new file mode 100644
index 0000000..4471e97
--- /dev/null
+++ b/coverage/report/view/widgets/favorite_button_widget.dart.gcov.html
@@ -0,0 +1,114 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/widgets/favorite_button_widget.dart
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+
+
+ Line data Source code
+
+ 1 : import 'package:flutter/material.dart';
+ 2 :
+ 3 : class FavoriteButtonWidget extends StatefulWidget {
+ 4 1 : const FavoriteButtonWidget({
+ 5 : required this.callback,
+ 6 : required this.isFavorite,
+ 7 : super.key,
+ 8 : });
+ 9 : final Function(bool) callback;
+ 10 : final bool? isFavorite;
+ 11 :
+ 12 1 : @override
+ 13 1 : State<FavoriteButtonWidget> createState() => _FavoriteButtonWidgetState();
+ 14 : }
+ 15 :
+ 16 : class _FavoriteButtonWidgetState extends State<FavoriteButtonWidget> {
+ 17 : bool isFavoriteState = false;
+ 18 1 : @override
+ 19 : void initState() {
+ 20 3 : isFavoriteState = widget.isFavorite ?? false;
+ 21 1 : super.initState();
+ 22 : }
+ 23 :
+ 24 1 : @override
+ 25 : Widget build(BuildContext context) {
+ 26 1 : return IconButton(
+ 27 1 : onPressed: () {
+ 28 2 : setState(() {
+ 29 2 : isFavoriteState = !isFavoriteState;
+ 30 : });
+ 31 4 : widget.callback(isFavoriteState);
+ 32 : },
+ 33 1 : icon: (isFavoriteState)
+ 34 : ? const Icon(Icons.favorite)
+ 35 : : const Icon(Icons.favorite_outline),
+ 36 : );
+ 37 : }
+ 38 : }
+
+ |
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/widgets/favorite_list_widget.dart.func-c.html b/coverage/report/view/widgets/favorite_list_widget.dart.func-c.html
new file mode 100644
index 0000000..69cbf8f
--- /dev/null
+++ b/coverage/report/view/widgets/favorite_list_widget.dart.func-c.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/widgets/favorite_list_widget.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/widgets/favorite_list_widget.dart.func.html b/coverage/report/view/widgets/favorite_list_widget.dart.func.html
new file mode 100644
index 0000000..b1ec987
--- /dev/null
+++ b/coverage/report/view/widgets/favorite_list_widget.dart.func.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/widgets/favorite_list_widget.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/widgets/favorite_list_widget.dart.gcov.html b/coverage/report/view/widgets/favorite_list_widget.dart.gcov.html
new file mode 100644
index 0000000..d204a6a
--- /dev/null
+++ b/coverage/report/view/widgets/favorite_list_widget.dart.gcov.html
@@ -0,0 +1,134 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/widgets/favorite_list_widget.dart
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+
+
+ Line data Source code
+
+ 1 : import 'package:flutter/material.dart';
+ 2 : import 'package:flutter_bloc/flutter_bloc.dart';
+ 3 : import 'package:get_it/get_it.dart';
+ 4 : import 'package:restaurant_tour/presentation/favorites/favorites_restaurants_bloc.dart';
+ 5 : import 'package:restaurant_tour/view/pages/restaurant_page.dart';
+ 6 : import 'package:restaurant_tour/view/widgets/restaurant_tile.dart';
+ 7 :
+ 8 : class FavoriteListWidget extends StatefulWidget {
+ 9 1 : const FavoriteListWidget({super.key});
+ 10 :
+ 11 1 : @override
+ 12 1 : State<FavoriteListWidget> createState() => _FavoriteListWidgetState();
+ 13 : }
+ 14 :
+ 15 : class _FavoriteListWidgetState extends State<FavoriteListWidget> {
+ 16 1 : @override
+ 17 : Widget build(BuildContext context) {
+ 18 1 : return BlocBuilder<FavoritesRestaurantsBloc, FavoritesRestaurantsState>(
+ 19 2 : bloc: GetIt.I.get<FavoritesRestaurantsBloc>(),
+ 20 1 : builder: (context, state) {
+ 21 1 : if (state is FavoritesRestaurantsReady) {
+ 22 1 : return ListView.separated(
+ 23 1 : separatorBuilder: (context, index) => const SizedBox(
+ 24 : height: 2,
+ 25 : ),
+ 26 2 : itemCount: state.favoritesRestaurants.length,
+ 27 1 : itemBuilder: (context, index) {
+ 28 1 : return GestureDetector(
+ 29 0 : onTap: () => Navigator.of(context).push(
+ 30 0 : MaterialPageRoute<RestaurantPage>(
+ 31 0 : builder: (context) => RestaurantPage(
+ 32 0 : restaurant: state.favoritesRestaurants[index],
+ 33 : ),
+ 34 : ),
+ 35 : ),
+ 36 1 : child: RestaurantTile(
+ 37 2 : restaurant: state.favoritesRestaurants[index],
+ 38 : ),
+ 39 : );
+ 40 : },
+ 41 : );
+ 42 : }
+ 43 1 : if (state is FavoriteRestaurantsListError) {
+ 44 0 : return Center(
+ 45 0 : child: Text(state.exception.description),
+ 46 : );
+ 47 : }
+ 48 :
+ 49 1 : if (state is FavoritesRestaurantsLoading) {
+ 50 : return const Center(
+ 51 : child: CircularProgressIndicator(),
+ 52 : );
+ 53 : }
+ 54 1 : return Container();
+ 55 : },
+ 56 : );
+ 57 : }
+ 58 : }
+
+ |
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/widgets/index-sort-f.html b/coverage/report/view/widgets/index-sort-f.html
new file mode 100644
index 0000000..e78866f
--- /dev/null
+++ b/coverage/report/view/widgets/index-sort-f.html
@@ -0,0 +1,237 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/widgets
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/widgets/index-sort-l.html b/coverage/report/view/widgets/index-sort-l.html
new file mode 100644
index 0000000..ebac973
--- /dev/null
+++ b/coverage/report/view/widgets/index-sort-l.html
@@ -0,0 +1,237 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/widgets
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/widgets/index.html b/coverage/report/view/widgets/index.html
new file mode 100644
index 0000000..05421e6
--- /dev/null
+++ b/coverage/report/view/widgets/index.html
@@ -0,0 +1,237 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/widgets
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/widgets/overall_rating_widget.dart.func-c.html b/coverage/report/view/widgets/overall_rating_widget.dart.func-c.html
new file mode 100644
index 0000000..6cbb92e
--- /dev/null
+++ b/coverage/report/view/widgets/overall_rating_widget.dart.func-c.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/widgets/overall_rating_widget.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/widgets/overall_rating_widget.dart.func.html b/coverage/report/view/widgets/overall_rating_widget.dart.func.html
new file mode 100644
index 0000000..9187a36
--- /dev/null
+++ b/coverage/report/view/widgets/overall_rating_widget.dart.func.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/widgets/overall_rating_widget.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/widgets/overall_rating_widget.dart.gcov.html b/coverage/report/view/widgets/overall_rating_widget.dart.gcov.html
new file mode 100644
index 0000000..9289558
--- /dev/null
+++ b/coverage/report/view/widgets/overall_rating_widget.dart.gcov.html
@@ -0,0 +1,111 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/widgets/overall_rating_widget.dart
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+
+
+ Line data Source code
+
+ 1 : import 'package:flutter/material.dart';
+ 2 : import 'package:gap/gap.dart';
+ 3 : import 'package:restaurant_tour/view/widgets/restaurant_star_rating_widget.dart';
+ 4 :
+ 5 : class OverallRatingWidget extends StatelessWidget {
+ 6 0 : const OverallRatingWidget({required this.rating, super.key});
+ 7 : final double? rating;
+ 8 0 : @override
+ 9 : Widget build(BuildContext context) {
+ 10 0 : return Column(
+ 11 : crossAxisAlignment: CrossAxisAlignment.start,
+ 12 0 : children: [
+ 13 : const Gap(16),
+ 14 : const Text('Overall Rating'),
+ 15 : const Gap(16),
+ 16 0 : Row(
+ 17 0 : children: [
+ 18 0 : Text(
+ 19 0 : rating?.toString() ?? '0',
+ 20 0 : style: Theme.of(context).textTheme.headlineLarge!.copyWith(
+ 21 : fontFamily: 'Lora',
+ 22 : fontWeight: FontWeight.bold,
+ 23 : ),
+ 24 : ),
+ 25 : const Padding(
+ 26 : padding: EdgeInsets.only(left: 2, top: 16.0),
+ 27 : child: RestaurantStarRatingWidget(1),
+ 28 : ),
+ 29 : ],
+ 30 : ),
+ 31 : const Gap(16),
+ 32 : ],
+ 33 : );
+ 34 : }
+ 35 : }
+
+ |
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/widgets/restaurant_category_price_widget.dart.func-c.html b/coverage/report/view/widgets/restaurant_category_price_widget.dart.func-c.html
new file mode 100644
index 0000000..d93e854
--- /dev/null
+++ b/coverage/report/view/widgets/restaurant_category_price_widget.dart.func-c.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/widgets/restaurant_category_price_widget.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/widgets/restaurant_category_price_widget.dart.func.html b/coverage/report/view/widgets/restaurant_category_price_widget.dart.func.html
new file mode 100644
index 0000000..ae14663
--- /dev/null
+++ b/coverage/report/view/widgets/restaurant_category_price_widget.dart.func.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/widgets/restaurant_category_price_widget.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/widgets/restaurant_category_price_widget.dart.gcov.html b/coverage/report/view/widgets/restaurant_category_price_widget.dart.gcov.html
new file mode 100644
index 0000000..2583746
--- /dev/null
+++ b/coverage/report/view/widgets/restaurant_category_price_widget.dart.gcov.html
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/widgets/restaurant_category_price_widget.dart
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+
+
+ Line data Source code
+
+ 1 : import 'package:flutter/material.dart';
+ 2 : import 'package:gap/gap.dart';
+ 3 :
+ 4 : class RestaurantCategoryPriceWidget extends StatelessWidget {
+ 5 1 : const RestaurantCategoryPriceWidget({
+ 6 : required this.price,
+ 7 : required this.category,
+ 8 : super.key,
+ 9 : });
+ 10 : final String? price;
+ 11 : final String? category;
+ 12 1 : @override
+ 13 : Widget build(BuildContext context) {
+ 14 1 : return Row(
+ 15 1 : children: [
+ 16 1 : Text(
+ 17 1 : price ?? "\$\$",
+ 18 3 : style: Theme.of(context).textTheme.bodyMedium,
+ 19 : ),
+ 20 : const Gap(4),
+ 21 1 : Text(
+ 22 1 : category ?? "",
+ 23 3 : style: Theme.of(context).textTheme.bodyMedium,
+ 24 : ),
+ 25 : ],
+ 26 : );
+ 27 : }
+ 28 : }
+
+ |
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/widgets/restaurant_hero_widget.dart.func-c.html b/coverage/report/view/widgets/restaurant_hero_widget.dart.func-c.html
new file mode 100644
index 0000000..5133f87
--- /dev/null
+++ b/coverage/report/view/widgets/restaurant_hero_widget.dart.func-c.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/widgets/restaurant_hero_widget.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/widgets/restaurant_hero_widget.dart.func.html b/coverage/report/view/widgets/restaurant_hero_widget.dart.func.html
new file mode 100644
index 0000000..be21443
--- /dev/null
+++ b/coverage/report/view/widgets/restaurant_hero_widget.dart.func.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/widgets/restaurant_hero_widget.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/widgets/restaurant_hero_widget.dart.gcov.html b/coverage/report/view/widgets/restaurant_hero_widget.dart.gcov.html
new file mode 100644
index 0000000..13f4914
--- /dev/null
+++ b/coverage/report/view/widgets/restaurant_hero_widget.dart.gcov.html
@@ -0,0 +1,100 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/widgets/restaurant_hero_widget.dart
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+
+
+ Line data Source code
+
+ 1 : import 'package:flutter/material.dart';
+ 2 :
+ 3 : class RestaurantHeroWidget extends StatelessWidget {
+ 4 1 : const RestaurantHeroWidget({
+ 5 : required this.imageUrl,
+ 6 : required this.tag,
+ 7 : super.key,
+ 8 : });
+ 9 : final String? tag;
+ 10 : final String? imageUrl;
+ 11 :
+ 12 1 : @override
+ 13 : Widget build(BuildContext context) {
+ 14 1 : return Hero(
+ 15 1 : tag: tag ?? 'restaurant_id',
+ 16 1 : child: Image.network(
+ 17 0 : errorBuilder: (context, error, stackTrace) =>
+ 18 : const Center(child: Icon(Icons.error)),
+ 19 1 : imageUrl ?? 'https://picsum.photos/375/361',
+ 20 : fit: BoxFit.fitWidth,
+ 21 : ),
+ 22 : );
+ 23 : }
+ 24 : }
+
+ |
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/widgets/restaurant_list_widget.dart.func-c.html b/coverage/report/view/widgets/restaurant_list_widget.dart.func-c.html
new file mode 100644
index 0000000..79f43b8
--- /dev/null
+++ b/coverage/report/view/widgets/restaurant_list_widget.dart.func-c.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/widgets/restaurant_list_widget.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/widgets/restaurant_list_widget.dart.func.html b/coverage/report/view/widgets/restaurant_list_widget.dart.func.html
new file mode 100644
index 0000000..1d158dc
--- /dev/null
+++ b/coverage/report/view/widgets/restaurant_list_widget.dart.func.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/widgets/restaurant_list_widget.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/widgets/restaurant_list_widget.dart.gcov.html b/coverage/report/view/widgets/restaurant_list_widget.dart.gcov.html
new file mode 100644
index 0000000..f135ca3
--- /dev/null
+++ b/coverage/report/view/widgets/restaurant_list_widget.dart.gcov.html
@@ -0,0 +1,173 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/widgets/restaurant_list_widget.dart
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+
+
+ Line data Source code
+
+ 1 : import 'package:flutter/material.dart';
+ 2 : import 'package:flutter_bloc/flutter_bloc.dart';
+ 3 : import 'package:get_it/get_it.dart';
+ 4 : import 'package:restaurant_tour/presentation/restaurants/restaurants_bloc.dart';
+ 5 : import 'package:restaurant_tour/view/pages/restaurant_page.dart';
+ 6 : import 'package:restaurant_tour/view/widgets/restaurant_tile.dart';
+ 7 :
+ 8 : class RestaurantListWidget extends StatefulWidget {
+ 9 1 : const RestaurantListWidget({super.key});
+ 10 :
+ 11 1 : @override
+ 12 1 : State<RestaurantListWidget> createState() => _RestaurantListWidgetState();
+ 13 : }
+ 14 :
+ 15 : class _RestaurantListWidgetState extends State<RestaurantListWidget> {
+ 16 : final _scrollController = ScrollController();
+ 17 1 : @override
+ 18 : void initState() {
+ 19 1 : super.initState();
+ 20 : }
+ 21 :
+ 22 0 : void addMore() {
+ 23 : final blocState =
+ 24 0 : (GetIt.I.get<RestaurantsBloc>().state) as RestaurantsReady;
+ 25 0 : GetIt.I.get<RestaurantsBloc>().add(
+ 26 0 : AddMoreRestaurants(offset: blocState.size, limit: blocState.limit),
+ 27 : );
+ 28 : }
+ 29 :
+ 30 1 : @override
+ 31 : Widget build(BuildContext context) {
+ 32 1 : return BlocBuilder<RestaurantsBloc, RestaurantsState>(
+ 33 2 : bloc: GetIt.I.get<RestaurantsBloc>(),
+ 34 1 : builder: (context, state) {
+ 35 1 : if (state is RestaurantsReady) {
+ 36 1 : return ListView.separated(
+ 37 1 : separatorBuilder: (context, index) => const SizedBox(
+ 38 : height: 2,
+ 39 : ),
+ 40 3 : itemCount: state.restaurants.length + 1,
+ 41 1 : controller: _scrollController,
+ 42 1 : itemBuilder: (context, index) {
+ 43 4 : if (index == state.restaurants.length && state.isLoadingMore) {
+ 44 : return const Padding(
+ 45 : padding: EdgeInsets.all(16.0),
+ 46 : child: Center(
+ 47 : child: CircularProgressIndicator(),
+ 48 : ),
+ 49 : );
+ 50 : }
+ 51 :
+ 52 4 : if (index == state.restaurants.length && state.hasError) {
+ 53 0 : return ElevatedButton(
+ 54 0 : onPressed: addMore,
+ 55 : child: const Text(
+ 56 : 'Error trying to fetch more, try again',
+ 57 : ),
+ 58 : );
+ 59 : }
+ 60 3 : if (index == state.restaurants.length) {
+ 61 1 : return ElevatedButton(
+ 62 1 : onPressed: addMore,
+ 63 : child: const Text(
+ 64 : 'Load more',
+ 65 : ),
+ 66 : );
+ 67 : }
+ 68 :
+ 69 1 : return GestureDetector(
+ 70 0 : onTap: () => Navigator.of(context).push(
+ 71 0 : MaterialPageRoute<RestaurantPage>(
+ 72 0 : builder: (context) => RestaurantPage(
+ 73 0 : restaurant: state.restaurants[index],
+ 74 : ),
+ 75 : ),
+ 76 : ),
+ 77 3 : child: RestaurantTile(restaurant: state.restaurants[index]),
+ 78 : );
+ 79 : },
+ 80 : );
+ 81 : }
+ 82 1 : if (state is RestaurantsError) {
+ 83 0 : return Center(
+ 84 0 : child: Text(state.exception.description),
+ 85 : );
+ 86 : }
+ 87 :
+ 88 1 : if (state is RestaurantsLoading) {
+ 89 : return const Center(
+ 90 : child: CircularProgressIndicator(),
+ 91 : );
+ 92 : }
+ 93 1 : return Container();
+ 94 : },
+ 95 : );
+ 96 : }
+ 97 : }
+
+ |
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/widgets/restaurant_open_widget.dart.func-c.html b/coverage/report/view/widgets/restaurant_open_widget.dart.func-c.html
new file mode 100644
index 0000000..84df7b5
--- /dev/null
+++ b/coverage/report/view/widgets/restaurant_open_widget.dart.func-c.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/widgets/restaurant_open_widget.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/widgets/restaurant_open_widget.dart.func.html b/coverage/report/view/widgets/restaurant_open_widget.dart.func.html
new file mode 100644
index 0000000..0bce58f
--- /dev/null
+++ b/coverage/report/view/widgets/restaurant_open_widget.dart.func.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/widgets/restaurant_open_widget.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/widgets/restaurant_open_widget.dart.gcov.html b/coverage/report/view/widgets/restaurant_open_widget.dart.gcov.html
new file mode 100644
index 0000000..ae2555d
--- /dev/null
+++ b/coverage/report/view/widgets/restaurant_open_widget.dart.gcov.html
@@ -0,0 +1,107 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/widgets/restaurant_open_widget.dart
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+
+
+ Line data Source code
+
+ 1 : import 'package:flutter/material.dart';
+ 2 : import 'package:gap/gap.dart';
+ 3 :
+ 4 : class RestaurantOpenWidget extends StatelessWidget {
+ 5 3 : const RestaurantOpenWidget(this.isOpen, {super.key});
+ 6 : final bool isOpen;
+ 7 3 : @override
+ 8 : Widget build(BuildContext context) {
+ 9 3 : return Row(
+ 10 : crossAxisAlignment: CrossAxisAlignment.center,
+ 11 3 : children: [
+ 12 3 : Text(
+ 13 3 : isOpen ? 'Open Now' : 'Closed',
+ 14 3 : style: Theme.of(context)
+ 15 3 : .textTheme
+ 16 3 : .bodyMedium!
+ 17 3 : .copyWith(fontStyle: FontStyle.italic),
+ 18 : ),
+ 19 : const Gap(6),
+ 20 3 : Padding(
+ 21 : padding: const EdgeInsets.only(top: 4.0),
+ 22 3 : child: Icon(
+ 23 : Icons.circle,
+ 24 : size: 8,
+ 25 3 : color: isOpen ? Colors.green : Colors.red,
+ 26 : ),
+ 27 : ),
+ 28 : ],
+ 29 : );
+ 30 : }
+ 31 : }
+
+ |
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/widgets/restaurant_star_rating_widget.dart.func-c.html b/coverage/report/view/widgets/restaurant_star_rating_widget.dart.func-c.html
new file mode 100644
index 0000000..11fe6b5
--- /dev/null
+++ b/coverage/report/view/widgets/restaurant_star_rating_widget.dart.func-c.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/widgets/restaurant_star_rating_widget.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/widgets/restaurant_star_rating_widget.dart.func.html b/coverage/report/view/widgets/restaurant_star_rating_widget.dart.func.html
new file mode 100644
index 0000000..3bb9846
--- /dev/null
+++ b/coverage/report/view/widgets/restaurant_star_rating_widget.dart.func.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/widgets/restaurant_star_rating_widget.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/widgets/restaurant_star_rating_widget.dart.gcov.html b/coverage/report/view/widgets/restaurant_star_rating_widget.dart.gcov.html
new file mode 100644
index 0000000..8faf5a9
--- /dev/null
+++ b/coverage/report/view/widgets/restaurant_star_rating_widget.dart.gcov.html
@@ -0,0 +1,97 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/widgets/restaurant_star_rating_widget.dart
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+
+
+ Line data Source code
+
+ 1 : import 'package:flutter/material.dart';
+ 2 :
+ 3 : class RestaurantStarRatingWidget extends StatelessWidget {
+ 4 8 : const RestaurantStarRatingWidget(this.rating, {super.key});
+ 5 : final starColor = const Color(0xFFFFB800);
+ 6 : final int rating;
+ 7 4 : @override
+ 8 : Widget build(BuildContext context) {
+ 9 4 : return Row(
+ 10 : mainAxisAlignment: MainAxisAlignment.start,
+ 11 4 : children: [
+ 12 12 : for (int i = 0; i < rating; i++)
+ 13 4 : Icon(
+ 14 : Icons.star,
+ 15 : size: 12,
+ 16 4 : color: starColor,
+ 17 : ),
+ 18 : ],
+ 19 : );
+ 20 : }
+ 21 : }
+
+ |
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/widgets/restaurant_tile.dart.func-c.html b/coverage/report/view/widgets/restaurant_tile.dart.func-c.html
new file mode 100644
index 0000000..57c862d
--- /dev/null
+++ b/coverage/report/view/widgets/restaurant_tile.dart.func-c.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/widgets/restaurant_tile.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/widgets/restaurant_tile.dart.func.html b/coverage/report/view/widgets/restaurant_tile.dart.func.html
new file mode 100644
index 0000000..47813fb
--- /dev/null
+++ b/coverage/report/view/widgets/restaurant_tile.dart.func.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/widgets/restaurant_tile.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/widgets/restaurant_tile.dart.gcov.html b/coverage/report/view/widgets/restaurant_tile.dart.gcov.html
new file mode 100644
index 0000000..7e1fc02
--- /dev/null
+++ b/coverage/report/view/widgets/restaurant_tile.dart.gcov.html
@@ -0,0 +1,156 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/widgets/restaurant_tile.dart
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+
+
+ Line data Source code
+
+ 1 : import 'package:flutter/material.dart';
+ 2 : import 'package:gap/gap.dart';
+ 3 : import 'package:restaurant_tour/models/restaurant.dart';
+ 4 : import 'package:restaurant_tour/view/widgets/restaurant_open_widget.dart';
+ 5 : import 'package:restaurant_tour/view/widgets/restaurant_star_rating_widget.dart';
+ 6 :
+ 7 : class RestaurantTile extends StatelessWidget {
+ 8 3 : const RestaurantTile({required this.restaurant, super.key});
+ 9 : final Restaurant restaurant;
+ 10 :
+ 11 3 : @override
+ 12 : Widget build(BuildContext context) {
+ 13 3 : return Container(
+ 14 12 : decoration: BoxDecoration(color: Theme.of(context).colorScheme.surface),
+ 15 3 : child: Card(
+ 16 3 : child: Padding(
+ 17 : padding: const EdgeInsets.all(8.0),
+ 18 3 : child: Row(
+ 19 : crossAxisAlignment: CrossAxisAlignment.start,
+ 20 3 : children: [
+ 21 3 : Hero(
+ 22 6 : tag: restaurant.id ?? 'restaurant_id',
+ 23 3 : child: ClipRRect(
+ 24 3 : borderRadius: BorderRadius.circular(8.0),
+ 25 3 : child: Image.network(
+ 26 0 : errorBuilder: (context, error, stackTrace) =>
+ 27 : const Center(child: Icon(Icons.error)),
+ 28 : width: 88,
+ 29 : height: 88,
+ 30 9 : restaurant.photos?.first ?? 'https://picsum.photos/200/300',
+ 31 : ),
+ 32 : ),
+ 33 : ),
+ 34 : const Gap(12),
+ 35 3 : Expanded(
+ 36 3 : child: SizedBox(
+ 37 : height: 88,
+ 38 3 : child: Column(
+ 39 : mainAxisAlignment: MainAxisAlignment.start,
+ 40 : crossAxisAlignment: CrossAxisAlignment.start,
+ 41 3 : children: [
+ 42 3 : Expanded(
+ 43 3 : child: Text(
+ 44 6 : restaurant.name ?? 'Restaurant Name',
+ 45 9 : style: Theme.of(context).textTheme.titleLarge,
+ 46 : ),
+ 47 : ),
+ 48 3 : Row(
+ 49 3 : children: [
+ 50 3 : Text(
+ 51 6 : restaurant.price ?? "\$\$",
+ 52 9 : style: Theme.of(context).textTheme.bodyMedium,
+ 53 : ),
+ 54 : const Gap(4),
+ 55 3 : Text(
+ 56 8 : restaurant.categories?.first.title ?? "",
+ 57 9 : style: Theme.of(context).textTheme.bodyMedium,
+ 58 : ),
+ 59 : ],
+ 60 : ),
+ 61 3 : Row(
+ 62 : mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ 63 3 : children: [
+ 64 3 : RestaurantStarRatingWidget(
+ 65 9 : restaurant.rating?.toInt() ?? 2,
+ 66 : ),
+ 67 9 : RestaurantOpenWidget(restaurant.isOpen),
+ 68 : ],
+ 69 : ),
+ 70 : ],
+ 71 : ),
+ 72 : ),
+ 73 : ),
+ 74 : ],
+ 75 : ),
+ 76 : ),
+ 77 : ),
+ 78 : );
+ 79 : }
+ 80 : }
+
+ |
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/widgets/review_list_widget.dart.func-c.html b/coverage/report/view/widgets/review_list_widget.dart.func-c.html
new file mode 100644
index 0000000..dde4b0f
--- /dev/null
+++ b/coverage/report/view/widgets/review_list_widget.dart.func-c.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/widgets/review_list_widget.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/widgets/review_list_widget.dart.func.html b/coverage/report/view/widgets/review_list_widget.dart.func.html
new file mode 100644
index 0000000..da73755
--- /dev/null
+++ b/coverage/report/view/widgets/review_list_widget.dart.func.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/widgets/review_list_widget.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/widgets/review_list_widget.dart.gcov.html b/coverage/report/view/widgets/review_list_widget.dart.gcov.html
new file mode 100644
index 0000000..d2ce1e2
--- /dev/null
+++ b/coverage/report/view/widgets/review_list_widget.dart.gcov.html
@@ -0,0 +1,113 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/widgets/review_list_widget.dart
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+
+
+ Line data Source code
+
+ 1 : import 'package:flutter/material.dart';
+ 2 : import 'package:gap/gap.dart';
+ 3 : import 'package:restaurant_tour/models/restaurant.dart';
+ 4 : import 'package:restaurant_tour/view/widgets/review_tile.dart';
+ 5 :
+ 6 : class ReviewListWidget extends StatelessWidget {
+ 7 0 : const ReviewListWidget({required this.reviews, super.key});
+ 8 : final List<Review>? reviews;
+ 9 0 : @override
+ 10 : Widget build(BuildContext context) {
+ 11 0 : return (reviews?.isNotEmpty ?? false)
+ 12 0 : ? Column(
+ 13 : crossAxisAlignment: CrossAxisAlignment.start,
+ 14 0 : children: [
+ 15 : const Gap(16),
+ 16 0 : Text(
+ 17 0 : '${reviews!.length} Reviews',
+ 18 0 : style: Theme.of(context).textTheme.bodyMedium,
+ 19 : ),
+ 20 : const Gap(16),
+ 21 0 : ListView.separated(
+ 22 : physics: const NeverScrollableScrollPhysics(),
+ 23 : shrinkWrap: true,
+ 24 0 : itemBuilder: (context, index) {
+ 25 0 : return ReviewTile(reviews![index]);
+ 26 : },
+ 27 0 : separatorBuilder: (context, index) => const Padding(
+ 28 : padding: EdgeInsets.symmetric(vertical: 8.0),
+ 29 : child: Divider(),
+ 30 : ),
+ 31 0 : itemCount: reviews!.length,
+ 32 : ),
+ 33 : ],
+ 34 : )
+ 35 : : const Text('This restaurant has no reviews');
+ 36 : }
+ 37 : }
+
+ |
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/widgets/review_tile.dart.func-c.html b/coverage/report/view/widgets/review_tile.dart.func-c.html
new file mode 100644
index 0000000..ce82bb5
--- /dev/null
+++ b/coverage/report/view/widgets/review_tile.dart.func-c.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/widgets/review_tile.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/widgets/review_tile.dart.func.html b/coverage/report/view/widgets/review_tile.dart.func.html
new file mode 100644
index 0000000..7b7bf00
--- /dev/null
+++ b/coverage/report/view/widgets/review_tile.dart.func.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/widgets/review_tile.dart - functions
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+ Function Name  |
+
+ Hit count  |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coverage/report/view/widgets/review_tile.dart.gcov.html b/coverage/report/view/widgets/review_tile.dart.gcov.html
new file mode 100644
index 0000000..a1141c9
--- /dev/null
+++ b/coverage/report/view/widgets/review_tile.dart.gcov.html
@@ -0,0 +1,115 @@
+
+
+
+
+
+
+ LCOV - lcov.info - view/widgets/review_tile.dart
+
+
+
+
+
+
+ | LCOV - code coverage report |
+  |
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+  |
+
+ |
+
+
+  |
+
+
+
+
+
|
+
+
+
+ Line data Source code
+
+ 1 : import 'package:flutter/material.dart';
+ 2 : import 'package:gap/gap.dart';
+ 3 : import 'package:restaurant_tour/models/restaurant.dart';
+ 4 : import 'package:restaurant_tour/view/widgets/restaurant_star_rating_widget.dart';
+ 5 :
+ 6 : class ReviewTile extends StatelessWidget {
+ 7 1 : const ReviewTile(this.review, {super.key});
+ 8 : final Review review;
+ 9 :
+ 10 1 : @override
+ 11 : Widget build(BuildContext context) {
+ 12 1 : return Column(
+ 13 : crossAxisAlignment: CrossAxisAlignment.start,
+ 14 1 : children: [
+ 15 3 : RestaurantStarRatingWidget(review.rating ?? 1),
+ 16 : const Gap(12),
+ 17 1 : Text(
+ 18 2 : review.text ?? 'no comment',
+ 19 3 : style: Theme.of(context).textTheme.bodyMedium,
+ 20 : ),
+ 21 : const Gap(12),
+ 22 1 : Row(
+ 23 1 : children: [
+ 24 1 : CircleAvatar(
+ 25 1 : onForegroundImageError: (exception, stackTrace) => const Center(
+ 26 : child: Icon(Icons.error),
+ 27 : ),
+ 28 1 : foregroundImage: NetworkImage(
+ 29 3 : review.user?.imageUrl ?? 'https://picsum.photos/200/300',
+ 30 : ),
+ 31 : ),
+ 32 : const Gap(8),
+ 33 4 : Text(review.user?.name ?? 'user name'),
+ 34 : ],
+ 35 : ),
+ 36 : ],
+ 37 : );
+ 38 : }
+ 39 : }
+
+ |
+
+
+
+
+
+
+
+
+
diff --git a/integration_test/restaurant_tour_integreation_test.dart b/integration_test/restaurant_tour_integreation_test.dart
new file mode 100644
index 0000000..d569369
--- /dev/null
+++ b/integration_test/restaurant_tour_integreation_test.dart
@@ -0,0 +1,141 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:integration_test/integration_test.dart';
+import 'package:restaurant_tour/main.dart';
+import 'package:restaurant_tour/view/widgets/favorite_button_widget.dart';
+import 'package:restaurant_tour/view/widgets/favorite_list_widget.dart';
+import 'package:restaurant_tour/view/widgets/restaurant_hero_widget.dart';
+import 'package:restaurant_tour/view/widgets/restaurant_tile.dart';
+
+void main() {
+ IntegrationTestWidgetsFlutterBinding.ensureInitialized();
+
+ group('end-to-end test', () {
+ testWidgets('Tapping on RestaurantTitle navigates to correct page',
+ (WidgetTester tester) async {
+ // init
+ await tester.pumpWidget(
+ const RestaurantTour(
+ testMode: true,
+ ),
+ );
+ await tester.pumpAndSettle();
+
+ // find and tap restaurant tile
+ final restaurantTitleFinder = find.byType(RestaurantTile);
+ expect(restaurantTitleFinder, findsAny);
+ await tester.tap(restaurantTitleFinder.first);
+
+ // // Trigger a frame.
+ await tester.pumpAndSettle();
+
+ // // Verify hero widget is found.
+ expect(
+ find.byWidgetPredicate((widget) => widget is RestaurantHeroWidget),
+ findsOneWidget,
+ );
+ });
+
+ testWidgets('Tapping on Favorite Tab navigates to correct page',
+ (WidgetTester tester) async {
+ await tester.pumpWidget(
+ const RestaurantTour(
+ testMode: true,
+ ),
+ );
+ await tester.pumpAndSettle();
+
+ await tester.tap(find.byType(Tab).last);
+
+ // // Trigger a frame.
+ await tester.pumpAndSettle();
+
+ // // Verify hero widget is found.
+ expect(
+ find.byType(FavoriteListWidget),
+ findsOneWidget,
+ );
+ });
+
+ testWidgets(
+ 'Tapping on FavoriteButtonWidget add Restaurant to Favorite Restaurant List page',
+ (WidgetTester tester) async {
+ await tester.pumpWidget(
+ const RestaurantTour(
+ testMode: true,
+ ),
+ );
+ await tester.pumpAndSettle();
+
+ final restaurantTitleFinder =
+ find.byWidgetPredicate((widget) => widget is RestaurantTile);
+ expect(restaurantTitleFinder, findsAny);
+ await tester.tap(restaurantTitleFinder.first);
+
+ // Trigger a frame.
+ await tester.pumpAndSettle();
+
+ // // Verify hero widget is found.
+ final favoriteButton = find.byType(FavoriteButtonWidget);
+ expect(
+ favoriteButton,
+ findsOneWidget,
+ );
+ await tester.tap(favoriteButton);
+ // Trigger a frame.
+ await tester.pumpAndSettle();
+ await tester.pageBack();
+ // Trigger a frame.
+ await tester.pumpAndSettle();
+ final favoriteTab = find.byType(Tab).last;
+ await tester.tap(favoriteTab);
+ // Trigger a frame.
+ await tester.pumpAndSettle();
+
+ expect(find.byType(RestaurantTile), findsOne);
+ });
+
+ testWidgets(
+ 'Tapping on FavoriteButtonWidget again removes Restaurant to Favorite Restaurant List page',
+ (WidgetTester tester) async {
+ //Init
+ await tester.pumpWidget(
+ const RestaurantTour(
+ testMode: true,
+ ),
+ );
+ await tester.pumpAndSettle();
+
+ // Tap first Restaurant on the list
+ final restaurantTitleFinder = find.byType(RestaurantTile);
+ expect(restaurantTitleFinder, findsAny);
+ await tester.tap(restaurantTitleFinder.first);
+
+ // Trigger a frame.
+ await tester.pumpAndSettle();
+
+ // Tap Favorite Widget
+ final favoriteButton = find.byType(FavoriteButtonWidget);
+ expect(
+ favoriteButton,
+ findsOneWidget,
+ );
+ //Check if already favorite
+ expect(find.byIcon(Icons.favorite), findsOne);
+ await tester.tap(favoriteButton);
+ // Trigger a frame.
+ await tester.pumpAndSettle();
+
+ // Check if restaurant was added
+ await tester.pageBack();
+ // Trigger a frame.
+ await tester.pumpAndSettle();
+ final favoriteTab = find.byType(Tab).last;
+ await tester.tap(favoriteTab);
+ // Trigger a frame.
+ await tester.pumpAndSettle();
+
+ expect(find.byType(RestaurantTile), findsNothing);
+ });
+ });
+}
diff --git a/ios/Flutter/Debug.xcconfig b/ios/Flutter/Debug.xcconfig
index 592ceee..ec97fc6 100644
--- a/ios/Flutter/Debug.xcconfig
+++ b/ios/Flutter/Debug.xcconfig
@@ -1 +1,2 @@
+#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"
diff --git a/ios/Flutter/Release.xcconfig b/ios/Flutter/Release.xcconfig
index 592ceee..c4855bf 100644
--- a/ios/Flutter/Release.xcconfig
+++ b/ios/Flutter/Release.xcconfig
@@ -1 +1,2 @@
+#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"
diff --git a/ios/Podfile b/ios/Podfile
new file mode 100644
index 0000000..d97f17e
--- /dev/null
+++ b/ios/Podfile
@@ -0,0 +1,44 @@
+# Uncomment this line to define a global platform for your project
+# platform :ios, '12.0'
+
+# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
+ENV['COCOAPODS_DISABLE_STATS'] = 'true'
+
+project 'Runner', {
+ 'Debug' => :debug,
+ 'Profile' => :release,
+ 'Release' => :release,
+}
+
+def flutter_root
+ generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
+ unless File.exist?(generated_xcode_build_settings_path)
+ raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
+ end
+
+ File.foreach(generated_xcode_build_settings_path) do |line|
+ matches = line.match(/FLUTTER_ROOT\=(.*)/)
+ return matches[1].strip if matches
+ end
+ raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
+end
+
+require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
+
+flutter_ios_podfile_setup
+
+target 'Runner' do
+ use_frameworks!
+ use_modular_headers!
+
+ flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
+ target 'RunnerTests' do
+ inherit! :search_paths
+ end
+end
+
+post_install do |installer|
+ installer.pods_project.targets.each do |target|
+ flutter_additional_ios_build_settings(target)
+ end
+end
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
new file mode 100644
index 0000000..4248ccc
--- /dev/null
+++ b/ios/Podfile.lock
@@ -0,0 +1,29 @@
+PODS:
+ - Flutter (1.0.0)
+ - integration_test (0.0.1):
+ - Flutter
+ - shared_preferences_foundation (0.0.1):
+ - Flutter
+ - FlutterMacOS
+
+DEPENDENCIES:
+ - Flutter (from `Flutter`)
+ - integration_test (from `.symlinks/plugins/integration_test/ios`)
+ - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
+
+EXTERNAL SOURCES:
+ Flutter:
+ :path: Flutter
+ integration_test:
+ :path: ".symlinks/plugins/integration_test/ios"
+ shared_preferences_foundation:
+ :path: ".symlinks/plugins/shared_preferences_foundation/darwin"
+
+SPEC CHECKSUMS:
+ Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
+ integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573
+ shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
+
+PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796
+
+COCOAPODS: 1.15.0
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index 182fb57..1a323dc 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -8,12 +8,14 @@
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
+ 2E7AC0E2BF1914619CC87154 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CAF89E9B64414FEEC5D2A12E /* Pods_Runner.framework */; };
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
+ CAFD963A19518EE06B28572F /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAB9E9B0776B6D1DFE565129 /* Pods_RunnerTests.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -40,8 +42,10 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
+ 052B8C3ECEA6F7626E6ABB78 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; };
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
+ 2BF43EFC5F34CD0DCD05C5B2 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; };
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; };
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
@@ -55,13 +59,28 @@
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ B3483201A35C22C977D73AEC /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; };
+ B9570B291C027B904606AAEE /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; };
+ BA66C17775294B8B99618420 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; };
+ CAF89E9B64414FEEC5D2A12E /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ D7366470E54C01FD66673A14 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; };
+ DAB9E9B0776B6D1DFE565129 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
+ 964F26580A7E44CC7BEBCCF8 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ CAFD963A19518EE06B28572F /* Pods_RunnerTests.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ 2E7AC0E2BF1914619CC87154 /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -76,6 +95,20 @@
path = RunnerTests;
sourceTree = "";
};
+ 45B4539ABC9C5B0032715023 /* Pods */ = {
+ isa = PBXGroup;
+ children = (
+ B9570B291C027B904606AAEE /* Pods-Runner.debug.xcconfig */,
+ B3483201A35C22C977D73AEC /* Pods-Runner.release.xcconfig */,
+ 2BF43EFC5F34CD0DCD05C5B2 /* Pods-Runner.profile.xcconfig */,
+ 052B8C3ECEA6F7626E6ABB78 /* Pods-RunnerTests.debug.xcconfig */,
+ BA66C17775294B8B99618420 /* Pods-RunnerTests.release.xcconfig */,
+ D7366470E54C01FD66673A14 /* Pods-RunnerTests.profile.xcconfig */,
+ );
+ name = Pods;
+ path = Pods;
+ sourceTree = "";
+ };
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
@@ -94,6 +127,8 @@
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
331C8082294A63A400263BE5 /* RunnerTests */,
+ 45B4539ABC9C5B0032715023 /* Pods */,
+ FE910C7D9B36D82D28120FD1 /* Frameworks */,
);
sourceTree = "";
};
@@ -121,6 +156,15 @@
path = Runner;
sourceTree = "";
};
+ FE910C7D9B36D82D28120FD1 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ CAF89E9B64414FEEC5D2A12E /* Pods_Runner.framework */,
+ DAB9E9B0776B6D1DFE565129 /* Pods_RunnerTests.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "";
+ };
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@@ -128,8 +172,10 @@
isa = PBXNativeTarget;
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
buildPhases = (
+ 72A43B65184BD54708A6665F /* [CP] Check Pods Manifest.lock */,
331C807D294A63A400263BE5 /* Sources */,
331C807F294A63A400263BE5 /* Resources */,
+ 964F26580A7E44CC7BEBCCF8 /* Frameworks */,
);
buildRules = (
);
@@ -145,12 +191,14 @@
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
+ E927B33ED62B0169B756632F /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
+ 2874CF3702615B08A5FE951E /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@@ -222,6 +270,23 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
+ 2874CF3702615B08A5FE951E /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
+ );
+ name = "[CP] Embed Pods Frameworks";
+ outputFileListPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
@@ -238,6 +303,28 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
+ 72A43B65184BD54708A6665F /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputFileListPaths = (
+ );
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
@@ -253,6 +340,28 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
+ E927B33ED62B0169B756632F /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputFileListPaths = (
+ );
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
@@ -379,6 +488,7 @@
};
331C8088294A63A400263BE5 /* Debug */ = {
isa = XCBuildConfiguration;
+ baseConfigurationReference = 052B8C3ECEA6F7626E6ABB78 /* Pods-RunnerTests.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
@@ -396,6 +506,7 @@
};
331C8089294A63A400263BE5 /* Release */ = {
isa = XCBuildConfiguration;
+ baseConfigurationReference = BA66C17775294B8B99618420 /* Pods-RunnerTests.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
@@ -411,6 +522,7 @@
};
331C808A294A63A400263BE5 /* Profile */ = {
isa = XCBuildConfiguration;
+ baseConfigurationReference = D7366470E54C01FD66673A14 /* Pods-RunnerTests.profile.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
diff --git a/ios/Runner.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcworkspace/contents.xcworkspacedata
index 1d526a1..21a3cc1 100644
--- a/ios/Runner.xcworkspace/contents.xcworkspacedata
+++ b/ios/Runner.xcworkspace/contents.xcworkspacedata
@@ -4,4 +4,7 @@
+
+
diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift
index 9074fee..6266644 100644
--- a/ios/Runner/AppDelegate.swift
+++ b/ios/Runner/AppDelegate.swift
@@ -1,7 +1,7 @@
import Flutter
import UIKit
-@UIApplicationMain
+@main
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
diff --git a/lib/common/enviorment/enviorment.dart b/lib/common/enviorment/enviorment.dart
new file mode 100644
index 0000000..f80bc1e
--- /dev/null
+++ b/lib/common/enviorment/enviorment.dart
@@ -0,0 +1,2 @@
+const yelpApiKey = String.fromEnvironment('YELP_API_KEY', defaultValue: '');
+const yelpBaseUrl = String.fromEnvironment('YELP_API_URL', defaultValue: '');
diff --git a/lib/common/exceptions/exceptions.dart b/lib/common/exceptions/exceptions.dart
new file mode 100644
index 0000000..74e49f0
--- /dev/null
+++ b/lib/common/exceptions/exceptions.dart
@@ -0,0 +1,47 @@
+class AppException implements Exception {
+ String code;
+ String description;
+ AppException(this.code, this.description);
+ @override
+ String toString() {
+ return {
+ 'code': code,
+ 'description': description,
+ }.toString();
+ }
+}
+
+class RestaurantNotFoundException extends AppException {
+ RestaurantNotFoundException({
+ code = "RESTAURANT_NOT_FOUND",
+ description = "The restaurant searched is not our dataset",
+ }) : super(code, description);
+}
+
+class RestaurantListException extends AppException {
+ RestaurantListException({
+ code = "RESTAURANTS_LIST_NOT_AVAILABLE",
+ description = "The restaurant is not available at the moment",
+ }) : super(code, description);
+}
+
+class FavoritesRestaurantsListException extends AppException {
+ FavoritesRestaurantsListException({
+ code = "FAVORITES_RESTAURANTS_LIST_NOT_AVAILABLE",
+ description = "The favorite restaurant are not available at the moment",
+ }) : super(code, description);
+}
+
+class AddFavoriteRestaurantException extends AppException {
+ AddFavoriteRestaurantException({
+ code = "ADD_FAVORITE_RESTAURANT_EXCEPTION",
+ description = "Couldn't register the favorite restaurant",
+ }) : super(code, description);
+}
+
+class RemoveFavoriteRestaurantException extends AppException {
+ RemoveFavoriteRestaurantException({
+ code = "REMOVE_FAVORITE_RESTAURANT_EXCEPTION",
+ description = "Couldn't remove the favorite restaurant",
+ }) : super(code, description);
+}
diff --git a/lib/data/datasource/graphql/graphql_restaurants_datasource.dart b/lib/data/datasource/graphql/graphql_restaurants_datasource.dart
new file mode 100644
index 0000000..9b0b6ed
--- /dev/null
+++ b/lib/data/datasource/graphql/graphql_restaurants_datasource.dart
@@ -0,0 +1,58 @@
+import 'dart:convert';
+
+import 'package:flutter/material.dart';
+import 'package:logger/logger.dart';
+import 'package:restaurant_tour/common/exceptions/exceptions.dart';
+import 'package:restaurant_tour/data/datasource/graphql/query.dart';
+import 'package:restaurant_tour/domain/datasource/restaurants_datasource.dart';
+import 'package:restaurant_tour/models/restaurant.dart';
+import 'package:http/http.dart' as http;
+import 'package:restaurant_tour/common/enviorment/enviorment.dart';
+
+class GraphqlRestaurantsDatasource implements RestaurantsDatasource {
+ @override
+ Future> getRestaurants({
+ int offset = 0,
+ int limit = 10,
+ }) async {
+ final headers = {
+ 'Authorization': 'Bearer $yelpApiKey',
+ 'Content-Type': 'application/graphql',
+ };
+
+ try {
+ final response = await http.post(
+ Uri.parse(yelpBaseUrl),
+ headers: headers,
+ body: query(offset, limit),
+ );
+
+ if (response.statusCode == 200) {
+ var logger = Logger();
+ logger.t("Trace log");
+
+ final map = jsonDecode(response.body);
+ final data = map['data'] as Map;
+ final search = data['search'] as Map;
+ final total = search['total'] as int;
+ final businessesJson = search['business'] as List;
+
+ final businesses = businessesJson
+ .map((business) => Restaurant.fromJson(business))
+ .toList();
+
+ debugPrint('Total restaurants: $total');
+
+ return businesses ?? [];
+ } else {
+ throw RestaurantListException(
+ description: 'Failed to load restaurants: ${response.statusCode}',
+ );
+ }
+ } catch (e) {
+ throw RestaurantListException(
+ description: 'Error fetching restaurants: $e',
+ );
+ }
+ }
+}
diff --git a/lib/query.dart b/lib/data/datasource/graphql/query.dart
similarity index 81%
rename from lib/query.dart
rename to lib/data/datasource/graphql/query.dart
index 7a8993b..d0b325b 100644
--- a/lib/query.dart
+++ b/lib/data/datasource/graphql/query.dart
@@ -1,6 +1,6 @@
-String query(int offset) => '''
+String query(int offset, int limit) => '''
query getRestaurants {
- search(location: "Las Vegas", limit: 20, offset: $offset) {
+ search(location: "Las Vegas", limit: $limit, offset: $offset) {
total
business {
id
diff --git a/lib/data/datasource/local/sp_favorite_restaurants_datasource.dart b/lib/data/datasource/local/sp_favorite_restaurants_datasource.dart
new file mode 100644
index 0000000..f753b2c
--- /dev/null
+++ b/lib/data/datasource/local/sp_favorite_restaurants_datasource.dart
@@ -0,0 +1,40 @@
+import 'dart:convert';
+
+import 'package:restaurant_tour/domain/datasource/favorite_restaurants_datasource.dart';
+import 'package:restaurant_tour/models/restaurant.dart';
+import 'package:shared_preferences/shared_preferences.dart';
+
+class SpFavoriteRestaurantsDatasource implements FavoriteRestaurantsDatasource {
+ final String _favoriteResturantsKey = 'spFavoritesRestaurants';
+ final SharedPreferences _sharedPreferences;
+ SpFavoriteRestaurantsDatasource(this._sharedPreferences);
+ @override
+ Future addFavoriteRestaurant(Restaurant restaurant) async {
+ final result = _sharedPreferences.getStringList(_favoriteResturantsKey);
+ final restaurantJsonString = jsonEncode(restaurant.toJson());
+ if (result == null) {
+ _sharedPreferences
+ .setStringList(_favoriteResturantsKey, [restaurantJsonString]);
+ } else {
+ result.add(restaurantJsonString);
+ _sharedPreferences.setStringList(_favoriteResturantsKey, result);
+ }
+ }
+
+ @override
+ Future> getFavoritesRestaurants() async {
+ final result = _sharedPreferences.getStringList(_favoriteResturantsKey);
+
+ return result?.map((e) => Restaurant.fromJson(jsonDecode(e))).toList() ??
+ [];
+ }
+
+ @override
+ Future removeFavoriteRestaurant(Restaurant restaurant) async {
+ final result = _sharedPreferences.getStringList(_favoriteResturantsKey);
+ result?.removeWhere(
+ (restaurantJsonString) => restaurantJsonString.contains(restaurant.id!),
+ );
+ _sharedPreferences.setStringList(_favoriteResturantsKey, result ?? []);
+ }
+}
diff --git a/lib/data/datasource/memory/memory_favorite_restaurants_datasource.dart b/lib/data/datasource/memory/memory_favorite_restaurants_datasource.dart
new file mode 100644
index 0000000..aea2ce8
--- /dev/null
+++ b/lib/data/datasource/memory/memory_favorite_restaurants_datasource.dart
@@ -0,0 +1,25 @@
+import 'package:restaurant_tour/domain/datasource/favorite_restaurants_datasource.dart';
+import 'package:restaurant_tour/models/restaurant.dart';
+
+class MemoryFavoriteRestaurantsDatasource
+ implements FavoriteRestaurantsDatasource {
+ final List _favoritesRestaurants = [];
+ @override
+ Future addFavoriteRestaurant(Restaurant restaurant) async {
+ if (restaurant.id != null && restaurant.id!.isNotEmpty) {
+ _favoritesRestaurants.add(restaurant);
+ }
+ }
+
+ @override
+ Future removeFavoriteRestaurant(Restaurant restaurant) async {
+ if (restaurant.id != null && restaurant.id!.isNotEmpty) {
+ _favoritesRestaurants.remove(restaurant);
+ }
+ }
+
+ @override
+ Future> getFavoritesRestaurants() {
+ return Future.value(_favoritesRestaurants);
+ }
+}
diff --git a/lib/data/datasource/memory/memory_restaurants_datasource.dart b/lib/data/datasource/memory/memory_restaurants_datasource.dart
new file mode 100644
index 0000000..efc7e6c
--- /dev/null
+++ b/lib/data/datasource/memory/memory_restaurants_datasource.dart
@@ -0,0 +1,43 @@
+import 'package:restaurant_tour/domain/datasource/restaurants_datasource.dart';
+import 'package:restaurant_tour/models/restaurant.dart';
+
+class MemoryRestaurantsDatasource implements RestaurantsDatasource {
+ var restaurants = List.generate(
+ 100,
+ (i) => Restaurant(
+ id: "restaurant_$i",
+ name: "Amazing Pizza ${i + 1}",
+ price: "\$\$\$",
+ rating: 4.8,
+ photos: const ["https://picsum.photos/361/360"],
+ categories: [Category(alias: 'demo', title: 'Italian')],
+ hours: const [Hours(isOpenNow: true)],
+ location: Location(formattedAddress: "123 Main St, Anytown, CA"),
+ reviews: [1, 2, 3, 4, 5, 6]
+ .map(
+ (e) => const Review(
+ id: 'review_id',
+ text:
+ 'Review text goes here. Review text goes here. This is a review. This is a review that is 3 lines long.',
+ rating: 5,
+ user: User(
+ id: 'user_id',
+ imageUrl: 'https://picsum.photos/200/300',
+ name: 'Test User',
+ ),
+ ),
+ )
+ .toList(),
+ ),
+ growable: true,
+ );
+
+ @override
+ Future> getRestaurants({
+ int offset = 0,
+ int limit = 10,
+ }) async {
+ final result = restaurants.sublist(offset, offset + limit);
+ return Future.value(result);
+ }
+}
diff --git a/lib/di/di.dart b/lib/di/di.dart
new file mode 100644
index 0000000..9cf6754
--- /dev/null
+++ b/lib/di/di.dart
@@ -0,0 +1,63 @@
+import 'package:get_it/get_it.dart';
+import 'package:restaurant_tour/data/datasource/graphql/graphql_restaurants_datasource.dart';
+import 'package:restaurant_tour/data/datasource/local/sp_favorite_restaurants_datasource.dart';
+import 'package:restaurant_tour/data/datasource/memory/memory_restaurants_datasource.dart';
+import 'package:restaurant_tour/domain/datasource/favorite_restaurants_datasource.dart';
+import 'package:restaurant_tour/domain/datasource/restaurants_datasource.dart';
+import 'package:restaurant_tour/domain/repository/restaurants_repository.dart';
+import 'package:restaurant_tour/domain/usecase/restaurants_usecase.dart';
+import 'package:restaurant_tour/presentation/favorites/favorites_restaurants_bloc.dart';
+import 'package:restaurant_tour/presentation/restaurants/restaurants_bloc.dart';
+import 'package:shared_preferences/shared_preferences.dart';
+
+final getIt = GetIt.instance;
+
+void setup({testMode = false}) {
+ getIt.allowReassignment = testMode;
+ getIt.registerSingletonAsync(
+ () => SharedPreferences.getInstance(),
+ );
+
+ getIt.registerSingletonAsync(
+ () async => SpFavoriteRestaurantsDatasource(GetIt.I.get()),
+ dependsOn: [InitDependency(SharedPreferences)],
+ );
+ getIt.registerSingleton(
+ testMode ? MemoryRestaurantsDatasource() : GraphqlRestaurantsDatasource(),
+ );
+
+ getIt.registerSingletonAsync(
+ () async => RestaurantsRepository(
+ GetIt.I.get(),
+ GetIt.I.get(),
+ ),
+ dependsOn: [
+ InitDependency(FavoriteRestaurantsDatasource),
+ ],
+ );
+
+ getIt.registerSingletonAsync(
+ () async => RestaurantsUsecase(
+ GetIt.I.get(),
+ ),
+ dependsOn: [
+ InitDependency(RestaurantsRepository),
+ ],
+ );
+ getIt.registerSingletonAsync(
+ () async => RestaurantsBloc(
+ GetIt.I.get(),
+ ),
+ dependsOn: [
+ InitDependency(RestaurantsUsecase),
+ ],
+ );
+ getIt.registerSingletonAsync(
+ () async => FavoritesRestaurantsBloc(
+ GetIt.I.get(),
+ ),
+ dependsOn: [
+ InitDependency(RestaurantsUsecase),
+ ],
+ );
+}
diff --git a/lib/domain/datasource/favorite_restaurants_datasource.dart b/lib/domain/datasource/favorite_restaurants_datasource.dart
new file mode 100644
index 0000000..5038d86
--- /dev/null
+++ b/lib/domain/datasource/favorite_restaurants_datasource.dart
@@ -0,0 +1,7 @@
+import 'package:restaurant_tour/models/restaurant.dart';
+
+abstract class FavoriteRestaurantsDatasource {
+ Future addFavoriteRestaurant(Restaurant restaurant);
+ Future removeFavoriteRestaurant(Restaurant restaurant);
+ Future> getFavoritesRestaurants();
+}
diff --git a/lib/domain/datasource/restaurants_datasource.dart b/lib/domain/datasource/restaurants_datasource.dart
new file mode 100644
index 0000000..fe00284
--- /dev/null
+++ b/lib/domain/datasource/restaurants_datasource.dart
@@ -0,0 +1,5 @@
+import 'package:restaurant_tour/models/restaurant.dart';
+
+abstract class RestaurantsDatasource {
+ Future> getRestaurants({int offset, int limit});
+}
diff --git a/lib/domain/repository/restaurants_repository.dart b/lib/domain/repository/restaurants_repository.dart
new file mode 100644
index 0000000..8a3be6a
--- /dev/null
+++ b/lib/domain/repository/restaurants_repository.dart
@@ -0,0 +1,79 @@
+import 'package:restaurant_tour/domain/datasource/favorite_restaurants_datasource.dart';
+import 'package:restaurant_tour/domain/datasource/restaurants_datasource.dart';
+import 'package:restaurant_tour/models/restaurant.dart';
+
+class RestaurantsRepository {
+ RestaurantsRepository(
+ this._restaurantsDatasource,
+ this._favoriteRestaurantsDatasource,
+ );
+
+ final FavoriteRestaurantsDatasource _favoriteRestaurantsDatasource;
+ final RestaurantsDatasource _restaurantsDatasource;
+ final List _restaurants = [];
+ final Set _favorites = {};
+
+ Future> getRestaurants() async {
+ if (_restaurants.isEmpty) {
+ final remoteRestaurants = await _restaurantsDatasource.getRestaurants();
+ final favoritesRestaurants =
+ await _favoriteRestaurantsDatasource.getFavoritesRestaurants();
+ _restaurants.addAll(
+ remoteRestaurants
+ .map(
+ (e) => favoritesRestaurants.contains(e)
+ ? e.copyWith(isFavorite: true)
+ : e,
+ )
+ .toList(),
+ );
+ }
+ return _restaurants;
+ }
+
+ Future getMoreRestaurants(int offset, int limit) async {
+ final newRemoteRestaurants = await _restaurantsDatasource.getRestaurants(
+ offset: offset,
+ limit: limit,
+ );
+ _restaurants.addAll(
+ newRemoteRestaurants
+ .map(
+ (e) => _favorites.contains(e) ? e.copyWith(isFavorite: true) : e,
+ )
+ .toList(),
+ );
+ }
+
+ Future> getFavoriteRestaurants() async {
+ if (_favorites.isEmpty) {
+ final favoritesRestaurants =
+ await _favoriteRestaurantsDatasource.getFavoritesRestaurants();
+ _favorites.addAll(
+ favoritesRestaurants.map((e) => e.copyWith(isFavorite: true)),
+ );
+ }
+
+ return _favorites.toList();
+ }
+
+ Future addFavoriteRestaurant(Restaurant restaurant) async {
+ _favorites.add(restaurant.copyWith(isFavorite: true));
+ final restaurantIndex = _restaurants.indexWhere((e) => e == restaurant);
+ if (restaurantIndex != -1) {
+ _restaurants[restaurantIndex] = restaurant.copyWith(isFavorite: true);
+ await _favoriteRestaurantsDatasource
+ .addFavoriteRestaurant(restaurant.copyWith(isFavorite: true));
+ }
+ }
+
+ Future removeFavoriteRestaurant(Restaurant restaurant) async {
+ final restaurantIndex = _restaurants.indexWhere((e) => e == restaurant);
+ if (restaurantIndex != -1) {
+ _restaurants[restaurantIndex] = restaurant.copyWith(isFavorite: false);
+ _favorites.remove(restaurant);
+ await _favoriteRestaurantsDatasource
+ .removeFavoriteRestaurant(restaurant.copyWith(isFavorite: false));
+ }
+ }
+}
diff --git a/lib/domain/usecase/restaurants_usecase.dart b/lib/domain/usecase/restaurants_usecase.dart
new file mode 100644
index 0000000..d567c10
--- /dev/null
+++ b/lib/domain/usecase/restaurants_usecase.dart
@@ -0,0 +1,27 @@
+import 'package:restaurant_tour/domain/repository/restaurants_repository.dart';
+import 'package:restaurant_tour/models/restaurant.dart';
+
+class RestaurantsUsecase {
+ const RestaurantsUsecase(this._repository);
+ final RestaurantsRepository _repository;
+
+ Future> getRestaurants() {
+ return _repository.getRestaurants();
+ }
+
+ Future> getFavoriteRestaurants() {
+ return _repository.getFavoriteRestaurants();
+ }
+
+ Future addFavoriteRestaurant(Restaurant restaurant) {
+ return _repository.addFavoriteRestaurant(restaurant);
+ }
+
+ Future removeFavoriteRestaurant(Restaurant restaurant) {
+ return _repository.removeFavoriteRestaurant(restaurant);
+ }
+
+ Future loadMoreRestaurants({required int offset, required int limit}) {
+ return _repository.getMoreRestaurants(offset, limit);
+ }
+}
diff --git a/lib/main.dart b/lib/main.dart
index ae7012a..f2801db 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -1,86 +1,42 @@
-import 'dart:convert';
-
import 'package:flutter/material.dart';
-import 'package:http/http.dart' as http;
-import 'package:restaurant_tour/models/restaurant.dart';
-import 'package:restaurant_tour/query.dart';
-
-const _apiKey = '';
-const _baseUrl = 'https://api.yelp.com/v3/graphql';
+import 'package:get_it/get_it.dart';
+import 'package:restaurant_tour/di/di.dart';
+import 'package:restaurant_tour/view/pages/main_page.dart';
+import './view/theme/app_theme.dart';
void main() {
runApp(const RestaurantTour());
}
-class RestaurantTour extends StatelessWidget {
- const RestaurantTour({super.key});
+class RestaurantTour extends StatefulWidget {
+ const RestaurantTour({super.key, this.testMode = false});
+ final bool testMode;
@override
- Widget build(BuildContext context) {
- return const MaterialApp(
- title: 'Restaurant Tour',
- home: HomePage(),
- );
- }
+ State createState() => _RestaurantTourState();
}
-// TODO: Architect code
-// This is just a POC of the API integration
-class HomePage extends StatelessWidget {
- const HomePage({super.key});
-
- Future getRestaurants({int offset = 0}) async {
- final headers = {
- 'Authorization': 'Bearer $_apiKey',
- 'Content-Type': 'application/graphql',
- };
-
- try {
- final response = await http.post(
- Uri.parse(_baseUrl),
- headers: headers,
- body: query(offset),
- );
-
- if (response.statusCode == 200) {
- return RestaurantQueryResult.fromJson(
- jsonDecode(response.body)['data']['search'],
- );
- } else {
- print('Failed to load restaurants: ${response.statusCode}');
- return null;
- }
- } catch (e) {
- print('Error fetching restaurants: $e');
- return null;
- }
+class _RestaurantTourState extends State {
+ @override
+ void initState() {
+ setup(testMode: widget.testMode);
+ super.initState();
}
@override
Widget build(BuildContext context) {
- return Scaffold(
- body: Center(
- child: Column(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- const Text('Restaurant Tour'),
- ElevatedButton(
- child: const Text('Fetch Restaurants'),
- onPressed: () async {
- try {
- final result = await getRestaurants();
- if (result != null) {
- print('Fetched ${result.restaurants!.length} restaurants');
- } else {
- print('No restaurants fetched');
- }
- } catch (e) {
- print('Failed to fetch restaurants: $e');
- }
- },
- ),
- ],
- ),
+ return MaterialApp(
+ title: 'Restaurant Tour',
+ theme: AppTheme.lightTheme,
+ home: FutureBuilder(
+ future: GetIt.I.allReady(),
+ builder: (context, snapshot) {
+ if (snapshot.connectionState == ConnectionState.done) {
+ return const MainPage();
+ } else {
+ return const Center(child: CircularProgressIndicator());
+ }
+ },
),
);
}
diff --git a/lib/models/restaurant.dart b/lib/models/restaurant.dart
index 1c7ad2f..642cb8a 100644
--- a/lib/models/restaurant.dart
+++ b/lib/models/restaurant.dart
@@ -1,3 +1,4 @@
+import 'package:equatable/equatable.dart';
import 'package:json_annotation/json_annotation.dart';
part 'restaurant.g.dart';
@@ -85,7 +86,7 @@ class Location {
}
@JsonSerializable()
-class Restaurant {
+class Restaurant extends Equatable {
final String? id;
final String? name;
final String? price;
@@ -95,6 +96,7 @@ class Restaurant {
final List? hours;
final List? reviews;
final Location? location;
+ final bool? isFavorite;
const Restaurant({
this.id,
@@ -106,8 +108,35 @@ class Restaurant {
this.hours,
this.reviews,
this.location,
+ this.isFavorite,
});
+ Restaurant copyWith({
+ String? id,
+ String? name,
+ String? price,
+ double? rating,
+ List? photos,
+ List? categories,
+ List? hours,
+ List? reviews,
+ Location? location,
+ bool? isFavorite,
+ }) {
+ return Restaurant(
+ id: id ?? this.id,
+ name: name ?? this.name,
+ price: price ?? this.price,
+ rating: rating ?? this.rating,
+ photos: photos ?? this.photos,
+ categories: categories ?? this.categories,
+ hours: hours ?? this.hours,
+ reviews: reviews ?? this.reviews,
+ location: location ?? this.location,
+ isFavorite: isFavorite ?? this.isFavorite,
+ );
+ }
+
factory Restaurant.fromJson(Map json) =>
_$RestaurantFromJson(json);
@@ -137,6 +166,9 @@ class Restaurant {
}
return false;
}
+
+ @override
+ List