Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
f09f919
feat: initial design for the view of all restaurants
daniesquivelc97 Sep 13, 2024
5bf6e63
feat: card info and image widget implemeted
daniesquivelc97 Sep 13, 2024
6081a60
feat: restaurant info view and restaurant reviews implemented
daniesquivelc97 Sep 13, 2024
3aba8f1
feat: star icon optimized
daniesquivelc97 Sep 13, 2024
391e69f
fix: all restaurants view updated to get information from API
daniesquivelc97 Sep 13, 2024
1a5aef3
fix: restaurant info view updated to get information from API
daniesquivelc97 Sep 13, 2024
8644779
fix: code optimization
daniesquivelc97 Sep 13, 2024
6372c66
feat: toggle to save favorites with shared preferences implemented
daniesquivelc97 Sep 14, 2024
084d01f
feat: favorite restaurants view implemented
daniesquivelc97 Sep 14, 2024
80d957f
fix: code optimizations
daniesquivelc97 Sep 14, 2024
ac755bb
fix: code optimization
daniesquivelc97 Sep 14, 2024
a669c15
feat: unit tests created to widgets folder
daniesquivelc97 Sep 14, 2024
3fa76a3
feat: tests implemented for favorite restaurants
daniesquivelc97 Sep 14, 2024
3af2cb1
feat: unit test implemented for all restaurants view
daniesquivelc97 Sep 14, 2024
ca00697
feat: tests implemented to repositiry
daniesquivelc97 Sep 14, 2024
2c7a049
feat: unit tests implemented to info page
daniesquivelc97 Sep 14, 2024
be87f58
fix: tests updated to info page
daniesquivelc97 Sep 14, 2024
26f25a6
fix: tests updated and others added
daniesquivelc97 Sep 14, 2024
8c49f7c
fix: code optimization
daniesquivelc97 Sep 14, 2024
ae63448
feat: constants file created
daniesquivelc97 Sep 15, 2024
fd8eafe
fix: Delete query.dart.gcov.html
daniesquivelc97 Sep 15, 2024
f5e78a4
feat: riverpod implemented
daniesquivelc97 Sep 15, 2024
c31cc46
feat: tests implemented
daniesquivelc97 Sep 15, 2024
5178dba
fix: file deleted
daniesquivelc97 Sep 15, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 6 additions & 61 deletions lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
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 = '<PUT YOUR API KEY HERE>';
const _baseUrl = 'https://api.yelp.com/v3/graphql';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:restaurant_tour/src/features/restaurant_tour/presentation/pages/restaurant_tour_page.dart';

void main() {
runApp(const RestaurantTour());
runApp(const ProviderScope(child: RestaurantTour()));
}

class RestaurantTour extends StatelessWidget {
Expand All @@ -24,63 +18,14 @@ class RestaurantTour extends StatelessWidget {
}
}

// TODO: Architect code
// This is just a POC of the API integration
class HomePage extends StatelessWidget {
const HomePage({super.key});

Future<RestaurantQueryResult?> 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;
}
}

@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 const MaterialApp(
home: Scaffold(
body: RestaurantTourPage(),
),
);
}
Expand Down
3 changes: 3 additions & 0 deletions lib/src/constants/constants.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const String apiKey =
'y0RvKbozyu07RfpByqrdTJGyAOzhaNZH9T5X5pzBOoSh9uqOULc8h6yx89Z5nPjYtNaPHp9aqX0ZKF5pHSuYTeWcrYJS9r4EoHb7WmVLKPSmPW-L0FloXZJUInTkZnYx';
const String baseUrl = 'https://api.yelp.com/v3/graphql';
File renamed without changes.
15 changes: 15 additions & 0 deletions lib/src/constants/strings.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Application strings
const String addressText = 'Address';
const String allRestaurants = 'All Restaurants';
const String closedText = 'Closed';
const String failedDataText =
'Failed to load data: You have reached the GraphQL daily points limit for this API key';
const String myFavorites = 'My Favorites';
const String noFavoriteRestaurantsText = 'You do not have favorite restaurants';
const String overallRatingText = 'Overall Rating';
const String openNowText = 'Open Now';
const String reviewsText = 'Reviews';
const String restaurantAddedText = 'Restaurant added to favorites';
const String restaurantDeletedText = 'Restaurant deleted from favorites';
const String sorryText = '¡Sorry!';
const String titleApp = 'Restaurant Tour';
File renamed without changes.
176 changes: 176 additions & 0 deletions lib/src/features/restaurant_tour/data/mock.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
import 'package:restaurant_tour/src/features/restaurant_tour/models/restaurant.dart';

RestaurantQueryResult? mockQueryResult = RestaurantQueryResult(
total: 10,
restaurants: mockRestaurants,
);

List<Restaurant> mockRestaurants = [
Restaurant(
id: '100',
name: 'Pasta Paradise',
price: '\$\$',
rating: 4.5,
photos: [
'https://i.pinimg.com/originals/b5/90/a7/b590a70a53f5712d4abfd6bf938d054d.jpg',
'https://www.metacritic.com/a/img/catalog/provider/6/12/6-1-764252-52.jpg',
],
categories: [
Category(alias: 'italian', title: 'Italian'),
],
hours: [
const Hours(isOpenNow: true),
],
reviews: [
const Review(
id: 'r1',
rating: 5,
text:
'Amazing food! Highly recommended. Amazing food! Highly recommended.',
user: User(
id: 'u1',
imageUrl: 'https://randomuser.me/api/portraits/men/1.jpg',
name: 'John Doe',
),
),
const Review(
id: 'r2',
rating: 2,
text:
'Review text goes there. Review text goes here. This is a review. This is a review that is 3 lines long.',
user: User(
id: 'u1',
imageUrl: 'https://randomuser.me/api/portraits/men/2.jpg',
name: 'John Test',
),
),
],
location: Location(
formattedAddress: '123 Pasta Lane, Food City, FC 12345',
),
),
Restaurant(
id: '200',
name: 'Burger Bonanza',
price: '\$\$',
rating: 4.0,
photos: [
'https://cdn.hobbyconsolas.com/sites/navi.axelspringer.es/public/media/image/2022/07/marvels-avengers-2748987.jpg',
'https://images.unsplash.com/photo-1567439204-e8a1c3c1ea80',
],
categories: [
Category(alias: 'american', title: 'American'),
],
hours: [
const Hours(isOpenNow: false),
],
reviews: [
const Review(
id: 'r2',
rating: 4,
text: 'Great burgers but a bit expensive.',
user: User(
id: 'u2',
imageUrl: 'https://randomuser.me/api/portraits/women/2.jpg',
name: 'Jane Smith',
),
),
],
location: Location(
formattedAddress: '456 Burger Blvd, Meat Town, MT 67890',
),
),
Restaurant(
id: '300',
name: 'Sushi World',
price: '\$\$\$',
rating: 4.8,
photos: [
'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSqQrl5EGU85_IW-T1FQcfTexUPr8htRkBzIw&s',
'https://images.unsplash.com/photo-1534503829050-1c8b38c9d137',
],
categories: [
Category(alias: 'japanese', title: 'Japanese'),
],
hours: [
const Hours(isOpenNow: true),
],
reviews: [
const Review(
id: 'r3',
rating: 5,
text: 'Best sushi in town. Fresh and delicious!',
user: User(
id: 'u3',
imageUrl: 'https://randomuser.me/api/portraits/men/3.jpg',
name: 'Alice Cooper',
),
),
],
location: Location(
formattedAddress: '789 Sushi St, Roll City, RC 23456',
),
),
Restaurant(
id: '400',
name: 'Taco Haven',
price: '\$',
rating: 4.2,
photos: [
'https://phantom-marca.unidadeditorial.es/3d02ae4f69cb70e76206ba49e8de0fbc/resize/828/f/jpg/assets/multimedia/imagenes/2024/02/23/17087165658783.jpg',
'https://images.unsplash.com/photo-1582960715727-4a7db5283a7f',
],
categories: [
Category(alias: 'mexican', title: 'Mexican'),
],
hours: [
const Hours(isOpenNow: true),
],
reviews: [
const Review(
id: 'r4',
rating: 4,
text: 'Tacos are great, but the service is slow.',
user: User(
id: 'u4',
imageUrl: 'https://randomuser.me/api/portraits/men/4.jpg',
name: 'Bob Brown',
),
),
],
location: Location(
formattedAddress: '321 Taco Ave, Spice City, SC 34567',
),
),
Restaurant(
id: '500',
name: 'Vegan Delight',
price: '\$\$',
rating: 4.7,
photos: [
'https://pics.filmaffinity.com/harry_potter_and_the_sorcerer_s_stone-154820574-mmed.jpg',
'https://images.unsplash.com/photo-1556914182-4ad1a5d33cfc',
],
categories: [
Category(alias: 'vegan', title: 'Vegan'),
],
hours: [
const Hours(isOpenNow: false),
],
reviews: [
const Review(
id: 'r5',
rating: 5,
text: 'Excellent vegan options. A must-visit for vegans!',
user: User(
id: 'u5',
imageUrl: 'https://randomuser.me/api/portraits/women/5.jpg',
name: 'Emma Davis',
),
),
],
location: Location(
formattedAddress: '654 Vegan Way, Herb City, HC 45678',
),
),
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import 'package:restaurant_tour/src/features/restaurant_tour/models/restaurant.dart';

abstract class RestaurantsDatasource {
Future<RestaurantQueryResult> getRestaurants();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import 'package:restaurant_tour/src/features/restaurant_tour/models/restaurant.dart';

abstract class RestaurantRepository {
Future<RestaurantQueryResult> getRestaurants();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import 'dart:convert';

import 'package:http/http.dart' as http;
import 'package:restaurant_tour/src/constants/constants.dart';
import 'package:restaurant_tour/src/constants/query.dart';
import 'package:restaurant_tour/src/features/restaurant_tour/domain/datasources/restaurants_datasource.dart';
import 'package:restaurant_tour/src/features/restaurant_tour/models/restaurant.dart';

class RestaurantApiDatasource extends RestaurantsDatasource {
static const _apiKey = apiKey;
static const _baseUrl = baseUrl;

@override
Future<RestaurantQueryResult> 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) {
final restaurantResponse = RestaurantQueryResult.fromJson(
jsonDecode(response.body)['data']['search'],
);
return restaurantResponse;
} else {
return const RestaurantQueryResult(restaurants: [], total: 0);
}
// TODO: Uncomment if you want to use the app with Mocks
// final restaurantsResponse = RestaurantQueryResult(
// restaurants: mockRestaurants,
// total: 5,
// );
// return restaurantsResponse;
} catch (e) {
print('Error fetching restaurants: $e');
rethrow;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import 'package:restaurant_tour/src/features/restaurant_tour/domain/datasources/restaurants_datasource.dart';
import 'package:restaurant_tour/src/features/restaurant_tour/domain/repositories/restaurant_repository.dart';
import 'package:restaurant_tour/src/features/restaurant_tour/models/restaurant.dart';

class RestaurantRepositoryImpl extends RestaurantRepository {
final RestaurantsDatasource datasource;

RestaurantRepositoryImpl(this.datasource);

@override
Future<RestaurantQueryResult> getRestaurants() {
return datasource.getRestaurants();
}
}
Loading