Skip to content
This repository was archived by the owner on Aug 9, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
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
6 changes: 4 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,7 @@ app.*.map.json
/android/app/profile
/android/app/release

# fvm
.fvm/flutter_sdk
# FVM Version Cache
.fvm/
/.fvmrc
/assets/secrets.json
6 changes: 3 additions & 3 deletions android/build.gradle
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
buildscript {
ext.kotlin_version = '1.3.50'
ext.kotlin_version = '1.7.10'
repositories {
google()
mavenCentral()
}

dependencies {
classpath 'com.android.tools.build:gradle:4.1.0'
classpath 'com.android.tools.build:gradle:7.3.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
Expand All @@ -26,6 +26,6 @@ subprojects {
project.evaluationDependsOn(':app')
}

task clean(type: Delete) {
tasks.register("clean", Delete) {
delete rootProject.buildDir
}
2 changes: 1 addition & 1 deletion android/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-all.zip
15 changes: 15 additions & 0 deletions lib/data/datasources/restaurant_local_service.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
class RestaurantLocalService {
final Map<String, bool> _storage = <String, bool>{};

bool favoriteRestaurant(
String id, {
required bool favorite,
}) {
_storage[id] = favorite;
return favorite;
}

bool checkFavoriteRestaurant(String id) {
return _storage[id] ?? false;
}
}
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:restaurantour/models/restaurant.dart';
import 'package:restaurantour/data/models/restaurant.dart';

const _apiKey = '<PUT YOUR API KEY HERE>';

class YelpRepository {
class RestaurantRemoteService {
late Dio dio;
final String apiKey;

YelpRepository({
RestaurantRemoteService({
@visibleForTesting Dio? dio,
required this.apiKey,
}) : dio = dio ??
Dio(
BaseOptions(
baseUrl: 'https://api.yelp.com',
headers: {
'Authorization': 'Bearer $_apiKey',
'Content-Type': 'application/graphql',
},
),
);
Dio(
BaseOptions(
baseUrl: 'https://api.yelp.com',
headers: {
'Authorization': 'Bearer $apiKey',
'Content-Type': 'application/graphql',
},
),
);

/// Returns a response in this shape
/// {
Expand Down Expand Up @@ -84,6 +84,7 @@ query getRestaurants {
reviews {
id
rating
text
user {
id
image_url
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,13 @@ class Review {
final String? id;
final int? rating;
final User? user;
final String? text;

const Review({
this.id,
this.rating,
this.user,
this.text,
});

factory Review.fromJson(Map<String, dynamic> json) => _$ReviewFromJson(json);
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 25 additions & 0 deletions lib/data/repositories/restaurant_repository.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import 'package:restaurantour/data/datasources/restaurant_local_service.dart';
import 'package:restaurantour/data/datasources/restaurant_remote_service.dart';
import 'package:restaurantour/data/models/restaurant.dart';

class RestaurantRepository {
const RestaurantRepository(this._remoteService, this._localService);

final RestaurantRemoteService _remoteService;
final RestaurantLocalService _localService;

Future<List<Restaurant>?> fetchRestaurants() async {
final query = await _remoteService.getRestaurants();
return query?.restaurants;
}
bool favoriteRestaurant(
String id, {
required bool favorite,
}) {
return _localService.favoriteRestaurant(id, favorite: favorite);
}

bool checkFavoriteRestaurant(String id) {
return _localService.checkFavoriteRestaurant(id);
}
}
60 changes: 20 additions & 40 deletions lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,57 +1,37 @@
import 'package:flutter/material.dart';
import 'package:restaurantour/repositories/yelp_repository.dart';
import 'package:restaurantour/presentation/restaurantour.dart';
import 'package:restaurantour/secrets.dart';

void main() {
runApp(const Restaurantour());
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Secrets.init();
runApp(const RestaurantourApp());
}

class Restaurantour extends StatelessWidget {
class RestaurantourApp extends StatelessWidget {
// This widget is the root of your application.
const Restaurantour({Key? key}) : super(key: key);
const RestaurantourApp({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'RestauranTour',
theme: ThemeData(
useMaterial3: true,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: const HomePage(),
);
}
}

class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('Restaurantour'),
ElevatedButton(
child: const Text('Fetch Restaurants'),
onPressed: () async {
final yelpRepo = YelpRepository();

try {
final result = await yelpRepo.getRestaurants();
if (result != null) {
print('Fetched ${result.restaurants!.length} restaurants');
} else {
print('No restaurants fetched');
}
} catch (e) {
print('Failed to fetch restaurants: $e');
}
},
),
],
appBarTheme: const AppBarTheme(
iconTheme: IconThemeData(color: Colors.black),
color: Colors.white,
titleTextStyle: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.black,
overflow: TextOverflow.ellipsis,
),
centerTitle: true,
),
),
home: const RestaurantourProvider(child: Restaurantour()),
);
}
}
28 changes: 28 additions & 0 deletions lib/presentation/components/address.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import 'package:flutter/material.dart';
import 'package:restaurantour/data/models/restaurant.dart';

class Address extends StatelessWidget {
const Address({Key? key, required this.location}) : super(key: key);

final Location? location;

@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Address',
style: TextStyle(
fontSize: 12,
),
),
const SizedBox(height: 20),
Text(
location?.formattedAddress ?? '',
style: const TextStyle(fontWeight: FontWeight.w500),
),
],
);
}
}
32 changes: 32 additions & 0 deletions lib/presentation/components/open_closed.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import 'package:flutter/material.dart';

class OpenClosed extends StatelessWidget {
const OpenClosed({Key? key, required this.open}) : super(key: key);

final bool open;

@override
Widget build(BuildContext context) {
return Row(
children: [
Text(
open ? 'Open Now' : 'Closed',
style: const TextStyle(
fontStyle: FontStyle.italic,
fontSize: 12,
),
),
const SizedBox(width: 4),
DecoratedBox(
decoration: BoxDecoration(
color: open ? Colors.green : Colors.red,
shape: BoxShape.circle,
),
child: const SizedBox.square(
dimension: 7,
),
),
],
);
}
}
40 changes: 40 additions & 0 deletions lib/presentation/components/overall_rating.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import 'package:flutter/material.dart';

class OverallRating extends StatelessWidget {
const OverallRating({Key? key, this.rating}) : super(key: key);

final double? rating;

@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Overall Rating',
style: TextStyle(
fontStyle: FontStyle.italic,
fontSize: 12,
),
),
const SizedBox(height: 15),
Row(
children: [
Text(
(rating ?? 0.0).toString(),
style: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
const Icon(
Icons.star,
color: Colors.amber,
size: 16,
),
],
),
],
);
}
}
20 changes: 20 additions & 0 deletions lib/presentation/components/price_category.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import 'package:flutter/material.dart';

class PriceCategory extends StatelessWidget {
const PriceCategory({
Key? key,
this.price,
required this.category,
}) : super(key: key);

final String? price;
final String category;

@override
Widget build(BuildContext context) {
return Text(
'${price ?? ''} $category',
style: const TextStyle(fontSize: 12),
);
}
}
23 changes: 23 additions & 0 deletions lib/presentation/components/rating_stars.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import 'dart:math';

import 'package:flutter/material.dart';

class RatingStars extends StatelessWidget {
const RatingStars({Key? key, required this.rating}) : super(key: key);

final double? rating;

@override
Widget build(BuildContext context) {
return Row(
children: [
for (var i = 0; i < min(rating?.round() ?? 0, 5); i++)
const Icon(
Icons.star,
color: Colors.amber,
size: 16,
),
],
);
}
}
Loading