diff --git a/.fvm/fvm_config.json b/.fvm/fvm_config.json deleted file mode 100644 index d8abe1b9..00000000 --- a/.fvm/fvm_config.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "flutterSdkVersion": "3.13.9", - "flavors": {} -} \ No newline at end of file diff --git a/.fvmrc b/.fvmrc new file mode 100644 index 00000000..05b430ce --- /dev/null +++ b/.fvmrc @@ -0,0 +1,3 @@ +{ + "flutter": "3.13.9" +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 1be2d875..7040cb04 100644 --- a/.gitignore +++ b/.gitignore @@ -46,4 +46,6 @@ app.*.map.json /android/app/release # fvm -.fvm/flutter_sdk \ No newline at end of file + +# FVM Version Cache +.fvm/ \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index f285aa4a..7578bf48 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.13.9", + "search.exclude": { + "**/.fvm": true + }, + "files.watcherExclude": { + "**/.fvm": true + } } \ No newline at end of file diff --git a/android/build.gradle b/android/build.gradle index 24047dce..fd59c3d1 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,12 +1,12 @@ buildscript { - ext.kotlin_version = '1.3.50' + ext.kotlin_version = '1.9.22' repositories { google() mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:4.1.0' + classpath 'com.android.tools.build:gradle:7.3.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } @@ -26,6 +26,6 @@ subprojects { project.evaluationDependsOn(':app') } -task clean(type: Delete) { +tasks.register("clean", Delete) { delete rootProject.buildDir } diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index bc6a58af..6b665338 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -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.5-all.zip diff --git a/lib/main.dart b/lib/main.dart index c6ce7473..66d06eb2 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,12 +1,18 @@ import 'package:flutter/material.dart'; -import 'package:restaurantour/repositories/yelp_repository.dart'; +import 'package:provider/provider.dart'; +import 'package:restaurantour/providers/restaurantProvider.dart'; +import 'package:restaurantour/screens/homeScreen.dart'; void main() { - runApp(const Restaurantour()); + runApp( + ChangeNotifierProvider( + create: (context) => RestaurantProvider(), + child: const Restaurantour(), + ), + ); } class Restaurantour extends StatelessWidget { - // This widget is the root of your application. const Restaurantour({Key? key}) : super(key: key); @override @@ -14,44 +20,50 @@ class Restaurantour extends StatelessWidget { return MaterialApp( title: 'RestauranTour', theme: ThemeData( - 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'); - } - }, - ), - ], + brightness: Brightness.light, + primaryColor: Colors.white, // Color de fondo de la barra de aplicación + appBarTheme: AppBarTheme( + color: Colors.white, + toolbarTextStyle: ThemeData.light() + .textTheme + .copyWith( + titleLarge: const TextStyle( + color: Colors + .black, // Color del texto del título de la barra de aplicación + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ) + .bodyMedium, + titleTextStyle: ThemeData.light() + .textTheme + .copyWith( + titleLarge: const TextStyle( + color: Colors + .black, // Color del texto del título de la barra de aplicación + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ) + .titleLarge, + ), + colorScheme: const ColorScheme( + // Configuración de colores general + primary: Colors.black, + secondary: Colors.black, + brightness: Brightness.light, + onBackground: Colors.white, + onPrimary: Colors.black, + surface: Colors.white, + onSurface: Colors.white, + error: Colors.white, + onError: Colors.white, + onSecondary: Colors.white, + background: Colors.white, ), + visualDensity: VisualDensity.adaptivePlatformDensity, ), + home: const HomeScreen(), ); } } diff --git a/lib/providers/restaurantProvider.dart b/lib/providers/restaurantProvider.dart new file mode 100644 index 00000000..403c531b --- /dev/null +++ b/lib/providers/restaurantProvider.dart @@ -0,0 +1,39 @@ +import 'package:flutter/material.dart'; +import 'package:restaurantour/models/restaurant.dart'; +import 'package:restaurantour/repositories/yelp_repository.dart'; + +class RestaurantProvider extends ChangeNotifier { + final YelpRepository _repository = YelpRepository(); + List? _restaurants; + Set _favorites = {}; + + List? get restaurants => _restaurants; + + Set get favorites => _favorites; + + Future fetchRestaurants() async { + print('Fetching restaurants...'); + final result = await _repository.getRestaurants(); + if (result != null) { + _restaurants = result.restaurants; + notifyListeners(); + } + } + + List getFavoriteRestaurants() { + return _restaurants?.where((restaurant) { + return _favorites.contains(restaurant.id); + }).toList() ?? + []; + } + + void toggleFavorite(String restaurantId, bool isFavorite) { + if (isFavorite) { + _favorites.add(restaurantId); + } else { + _favorites.remove(restaurantId); + } + + notifyListeners(); + } +} diff --git a/lib/repositories/yelp_repository.dart b/lib/repositories/yelp_repository.dart index f251d7b4..27cb92c6 100644 --- a/lib/repositories/yelp_repository.dart +++ b/lib/repositories/yelp_repository.dart @@ -2,7 +2,8 @@ import 'package:dio/dio.dart'; import 'package:flutter/foundation.dart'; import 'package:restaurantour/models/restaurant.dart'; -const _apiKey = ''; +const _apiKey = + 'xPkMA-zzjOcUpYI7PV4lcnjJNCklJ38n9L7Dg7AAG3PUiA9eHbNpcgUJP5qxTCemRufUBC-MtlMxwzpEIpxGGOYcuhliCYWsQwJg_1KCMNjVEiJ7Nmu0fp_gJqPTZXYx'; class YelpRepository { late Dio dio; @@ -73,8 +74,8 @@ class YelpRepository { String _getQuery(int offset) { return ''' query getRestaurants { - search(location: "Las Vegas", limit: 20, offset: $offset) { - total + search(location: "Miami", limit: 20, offset: $offset) { + total business { id name @@ -89,6 +90,7 @@ query getRestaurants { image_url name } + text } categories { title diff --git a/lib/screens/homeScreen.dart b/lib/screens/homeScreen.dart new file mode 100644 index 00000000..122d8361 --- /dev/null +++ b/lib/screens/homeScreen.dart @@ -0,0 +1,47 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:restaurantour/providers/restaurantProvider.dart'; +import 'package:restaurantour/widgets/home/allRestaurantTab.dart'; +import 'package:restaurantour/widgets/home/myFavoritesTab.dart'; + +class HomeScreen extends StatefulWidget { + const HomeScreen({Key? key}) : super(key: key); + + @override + _HomeScreenState createState() => _HomeScreenState(); +} + +class _HomeScreenState extends State { + @override + void initState() { + super.initState(); + final restaurantProvider = + Provider.of(context, listen: false); + restaurantProvider.fetchRestaurants(); + } + + @override + Widget build(BuildContext context) { + return DefaultTabController( + length: 2, + child: Scaffold( + appBar: AppBar( + centerTitle: true, + title: const Text('RestauranTour'), + bottom: const TabBar( + tabs: [ + Tab(text: 'All Restaurants'), + Tab(text: 'My Favorites'), + ], + ), + ), + body: const TabBarView( + children: [ + AllRestaurantsTab(), + MyFavoritesTab(), + ], + ), + ), + ); + } +} diff --git a/lib/screens/restaurantDetailScreen.dart b/lib/screens/restaurantDetailScreen.dart new file mode 100644 index 00000000..175a2378 --- /dev/null +++ b/lib/screens/restaurantDetailScreen.dart @@ -0,0 +1,155 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:restaurantour/models/restaurant.dart'; +import 'package:restaurantour/providers/restaurantProvider.dart'; +import 'package:restaurantour/widgets/restaurantDetail/addressWidget.dart'; +import 'package:restaurantour/widgets/myDivider.dart'; +import 'package:restaurantour/widgets/restaurantDetail/ratingWidget.dart'; +import 'package:restaurantour/widgets/restaurantDetail/restaurantStatus.dart'; +import 'package:restaurantour/widgets/restaurantDetail/reviewWidget.dart'; + +class RestaurantDetailScreen extends StatefulWidget { + final Restaurant restaurant; + + const RestaurantDetailScreen({Key? key, required this.restaurant}) + : super(key: key); + + @override + _RestaurantDetailScreenState createState() => _RestaurantDetailScreenState(); +} + +class _RestaurantDetailScreenState extends State { + bool isFavorite = false; + + @override + void initState() { + super.initState(); + + final restaurantProvider = + Provider.of(context, listen: false); + + isFavorite = restaurantProvider.favorites.contains(widget.restaurant.id); + } + + @override + Widget build(BuildContext context) { + final restaurantProvider = + Provider.of(context, listen: false); + return Scaffold( + appBar: AppBar( + title: Text(widget.restaurant.name ?? ''), + actions: [ + IconButton( + icon: Icon( + isFavorite ? Icons.favorite : Icons.favorite_border, + color: Colors.black, + ), + onPressed: () { + setState(() { + isFavorite = !isFavorite; + }); + + restaurantProvider.toggleFavorite( + widget.restaurant.id!, + isFavorite, + ); + + final snackBar = SnackBar( + content: Text( + isFavorite ? 'Saved as favorite' : 'Removed from favorites', + style: const TextStyle(color: Colors.white), + ), + backgroundColor: isFavorite + ? const Color(0xCC5FC95F) + : const Color.fromRGBO( + 252, + 76, + 76, + 0.8, + ), + ); + ScaffoldMessenger.of(context).showSnackBar(snackBar); + }, + ), + ], + ), + body: ListView( + children: [ + if (widget.restaurant.photos != null && + widget.restaurant.photos!.isNotEmpty) + Image.network( + widget.restaurant.photos!.first, + width: double.infinity, + height: 400.0, + fit: BoxFit.cover, + ), + Padding( + padding: const EdgeInsets.all(16.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + widget.restaurant.price ?? '', + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16.0, + ), + ), + const SizedBox(height: 8.0), + Text( + ' ${widget.restaurant.categories?.first.title ?? ''}', + style: const TextStyle( + fontWeight: FontWeight.normal, + fontSize: 16.0, + ), + ), + ], + ), + RestaurantStatus( + isOpen: widget.restaurant.hours != null && + widget.restaurant.isOpen), + ], + ), + ), + myDivider(), + Padding( + padding: const EdgeInsets.all(16.0), + child: AddressWidget( + address: widget.restaurant.location!.formattedAddress ?? ''), + ), + myDivider(), + Padding( + padding: const EdgeInsets.all(16.0), + child: RatingWidget(rating: widget.restaurant.rating!), + ), + myDivider(), + Padding( + padding: const EdgeInsets.all(16.0), + child: Text( + '${widget.restaurant.reviews!.length} reviews', + style: const TextStyle( + fontWeight: FontWeight.normal, + fontSize: 16.0, + ), + ), + ), + if (widget.restaurant.reviews != null) + Column( + children: [ + for (var i = 0; i < widget.restaurant.reviews!.length; i++) + Column( + children: [ + if (i > 0) myDivider(), + ReviewWidget(review: widget.restaurant.reviews![i]), + ], + ), + ], + ), + ], + ), + ); + } +} diff --git a/lib/widgets/home/allRestaurantTab.dart b/lib/widgets/home/allRestaurantTab.dart new file mode 100644 index 00000000..e81be574 --- /dev/null +++ b/lib/widgets/home/allRestaurantTab.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:restaurantour/providers/restaurantProvider.dart'; +import 'package:restaurantour/widgets/home/restaurantCard.dart'; + +class AllRestaurantsTab extends StatelessWidget { + const AllRestaurantsTab({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Consumer( + builder: (context, restaurantProvider, child) { + final restaurants = restaurantProvider.restaurants; + + if (restaurants != null) { + return ListView.builder( + itemCount: restaurants.length, + itemBuilder: (context, index) { + final restaurant = restaurants[index]; + return RestaurantCard(restaurant: restaurant); + }, + ); + } else { + return const Center(child: CircularProgressIndicator()); + } + }, + ); + } +} diff --git a/lib/widgets/home/myFavoritesTab.dart b/lib/widgets/home/myFavoritesTab.dart new file mode 100644 index 00000000..1958fc74 --- /dev/null +++ b/lib/widgets/home/myFavoritesTab.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:restaurantour/providers/restaurantProvider.dart'; +import 'package:restaurantour/widgets/home/restaurantCard.dart'; + +class MyFavoritesTab extends StatelessWidget { + const MyFavoritesTab({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Consumer( + builder: (context, restaurantProvider, child) { + final favoriteRestaurants = restaurantProvider.getFavoriteRestaurants(); + + if (favoriteRestaurants.isNotEmpty) { + return ListView.builder( + itemCount: favoriteRestaurants.length, + itemBuilder: (context, index) { + final restaurant = favoriteRestaurants[index]; + return RestaurantCard(restaurant: restaurant); + }, + ); + } else { + return const Center(child: Text('No favorite restaurants yet.')); + } + }, + ); + } +} diff --git a/lib/widgets/home/restaurantCard.dart b/lib/widgets/home/restaurantCard.dart new file mode 100644 index 00000000..c67874c3 --- /dev/null +++ b/lib/widgets/home/restaurantCard.dart @@ -0,0 +1,85 @@ +import 'package:flutter/material.dart'; +import 'package:restaurantour/models/restaurant.dart'; +import 'package:restaurantour/screens/restaurantDetailScreen.dart'; +import 'package:restaurantour/widgets/restaurantDetail/ratingStars.dart'; +import 'package:restaurantour/widgets/restaurantDetail/restaurantStatus.dart'; + +class RestaurantCard extends StatelessWidget { + final Restaurant restaurant; + + const RestaurantCard({Key? key, required this.restaurant}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Card( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15.0), + ), + child: GestureDetector( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + RestaurantDetailScreen(restaurant: restaurant), + ), + ); + }, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (restaurant.photos != null && restaurant.photos!.isNotEmpty) + ClipRRect( + borderRadius: BorderRadius.circular(15.0), + child: Image.network( + restaurant.photos!.first, + width: 100.0, + height: 100.0, + fit: BoxFit.cover, + ), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.only(left: 8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + restaurant.name ?? '', + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 18.0, + ), + ), + Row( + children: [ + Text(restaurant.price ?? ''), + const SizedBox(width: 8.0), + Text( + restaurant.categories?.first.title ?? '', + style: const TextStyle( + fontWeight: FontWeight.bold, + ), + ), + ], + ), + RatingStars(rating: restaurant.rating?.round() ?? 0), + Padding( + padding: const EdgeInsets.only(top: 8.0), + child: RestaurantStatus( + isOpen: restaurant.hours != null && restaurant.isOpen, + ), + ), + ], + ), + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/widgets/myDivider.dart b/lib/widgets/myDivider.dart new file mode 100644 index 00000000..0f9d383c --- /dev/null +++ b/lib/widgets/myDivider.dart @@ -0,0 +1,15 @@ +import 'package:flutter/material.dart'; + +class myDivider extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(16.0), + child: Container( + width: double.infinity, + height: 0.5, + color: const Color.fromARGB(255, 213, 213, 213), + ), + ); + } +} diff --git a/lib/widgets/restaurantDetail/addressWidget.dart b/lib/widgets/restaurantDetail/addressWidget.dart new file mode 100644 index 00000000..5863e1ab --- /dev/null +++ b/lib/widgets/restaurantDetail/addressWidget.dart @@ -0,0 +1,31 @@ +import 'package:flutter/material.dart'; + +class AddressWidget extends StatelessWidget { + final String address; + + const AddressWidget({Key? key, required this.address}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Address', + style: TextStyle( + fontWeight: FontWeight.normal, + fontSize: 16.0, + ), + ), + const SizedBox(height: 8.0), + Text( + address, + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 18.0, + ), + ), + ], + ); + } +} diff --git a/lib/widgets/restaurantDetail/ratingStars.dart b/lib/widgets/restaurantDetail/ratingStars.dart new file mode 100644 index 00000000..6efab654 --- /dev/null +++ b/lib/widgets/restaurantDetail/ratingStars.dart @@ -0,0 +1,20 @@ +import 'package:flutter/material.dart'; + +class RatingStars extends StatelessWidget { + final int rating; + + const RatingStars({Key? key, required this.rating}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Row( + children: List.generate( + rating, + (index) => const Icon( + Icons.star, + color: Colors.amber, + ), + ), + ); + } +} diff --git a/lib/widgets/restaurantDetail/ratingWidget.dart b/lib/widgets/restaurantDetail/ratingWidget.dart new file mode 100644 index 00000000..31e3ebf5 --- /dev/null +++ b/lib/widgets/restaurantDetail/ratingWidget.dart @@ -0,0 +1,41 @@ +import 'package:flutter/material.dart'; + +class RatingWidget extends StatelessWidget { + final double rating; + + const RatingWidget({Key? key, required this.rating}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Overall Rating', + style: TextStyle( + fontWeight: FontWeight.normal, + fontSize: 16.0, + ), + ), + const SizedBox(height: 8.0), + Row( + children: [ + Text( + rating.toString(), + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 24.0, + ), + ), + const SizedBox(width: 3.0), + const Icon( + Icons.star, + color: Colors.amber, + size: 16.0, + ), + ], + ), + ], + ); + } +} diff --git a/lib/widgets/restaurantDetail/restaurantStatus.dart b/lib/widgets/restaurantDetail/restaurantStatus.dart new file mode 100644 index 00000000..ac064549 --- /dev/null +++ b/lib/widgets/restaurantDetail/restaurantStatus.dart @@ -0,0 +1,32 @@ +import 'package:flutter/material.dart'; + +class RestaurantStatus extends StatelessWidget { + final bool isOpen; + + const RestaurantStatus({Key? key, required this.isOpen}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Text( + isOpen ? 'Open Now' : 'Closed', + style: const TextStyle( + fontStyle: FontStyle.italic, + color: Colors.black, + ), + ), + const SizedBox(width: 8.0), + Container( + width: 10.0, + height: 10.0, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: isOpen ? Colors.green : Colors.red, + ), + ), + ], + ); + } +} diff --git a/lib/widgets/restaurantDetail/reviewWidget.dart b/lib/widgets/restaurantDetail/reviewWidget.dart new file mode 100644 index 00000000..3db4bb1f --- /dev/null +++ b/lib/widgets/restaurantDetail/reviewWidget.dart @@ -0,0 +1,55 @@ +import 'package:flutter/material.dart'; +import 'package:restaurantour/models/restaurant.dart'; +import 'package:restaurantour/widgets/restaurantDetail/ratingStars.dart'; + +class ReviewWidget extends StatelessWidget { + final Review review; + + const ReviewWidget({ + Key? key, + required this.review, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [RatingStars(rating: review.rating!)], + ), + const SizedBox(height: 8.0), + const Text( + 'Feel free to share your thoughts and experiences about this restaurant. Your feedback is valuable to us and helps other diners make informed choices. Unfortunately, the current repository doesnt include specific comments.', + style: TextStyle( + fontSize: 16.0, + ), + ), + const SizedBox(height: 8.0), + Row( + children: [ + review.user?.imageUrl != null + ? CircleAvatar( + backgroundImage: NetworkImage(review.user!.imageUrl!), + ) + : const Icon( + Icons.person, + size: 40.0, // Ajusta el tamaño según sea necesario + ), + const SizedBox(width: 8.0), + Text( + review.user?.name ?? '', + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16.0, + ), + ), + ], + ), + ], + ), + ); + } +} diff --git a/pubspec.lock b/pubspec.lock index 0b052c68..48bfca29 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -105,6 +105,30 @@ packages: url: "https://pub.dev" source: hosted version: "8.1.4" + cached_network_image: + dependency: "direct main" + description: + name: cached_network_image + sha256: "28ea9690a8207179c319965c13cd8df184d5ee721ae2ce60f398ced1219cea1f" + url: "https://pub.dev" + source: hosted + version: "3.3.1" + cached_network_image_platform_interface: + dependency: transitive + description: + name: cached_network_image_platform_interface + sha256: "9e90e78ae72caa874a323d78fa6301b3fb8fa7ea76a8f96dc5b5bf79f283bf2f" + url: "https://pub.dev" + source: hosted + version: "4.0.0" + cached_network_image_web: + dependency: transitive + description: + name: cached_network_image_web + sha256: "42a835caa27c220d1294311ac409a43361088625a4f23c820b006dd9bffb3316" + url: "https://pub.dev" + source: hosted + version: "1.1.1" characters: dependency: transitive description: @@ -149,10 +173,10 @@ packages: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.17.2" convert: dependency: transitive description: @@ -201,14 +225,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.1" + ffi: + dependency: transitive + description: + name: ffi + sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" + url: "https://pub.dev" + source: hosted + version: "2.1.0" file: dependency: transitive description: name: file - sha256: b69516f2c26a5bcac4eee2e32512e1a5205ab312b3536c1c1227b2b942b5f9ad + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" url: "https://pub.dev" source: hosted - version: "6.1.2" + version: "6.1.4" fixnum: dependency: transitive description: @@ -222,6 +254,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_cache_manager: + dependency: transitive + description: + name: flutter_cache_manager + sha256: "8207f27539deb83732fdda03e259349046a39a4c767269285f449ade355d54ba" + url: "https://pub.dev" + source: hosted + version: "3.3.1" flutter_lints: dependency: "direct dev" description: @@ -243,6 +283,11 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" frontend_server_client: dependency: transitive description: @@ -267,6 +312,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.1" + http: + dependency: transitive + description: + name: http + sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525" + url: "https://pub.dev" + source: hosted + version: "1.1.0" http_multi_server: dependency: transitive description: @@ -295,10 +348,10 @@ packages: dependency: transitive description: name: js - sha256: d9bdfd70d828eeb352390f81b18d6a354ef2044aa28ef25682079797fa7cd174 + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 url: "https://pub.dev" source: hosted - version: "0.6.3" + version: "0.6.7" json_annotation: dependency: "direct main" description: @@ -351,10 +404,10 @@ packages: dependency: transitive description: name: meta - sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.9.1" mime: dependency: transitive description: @@ -363,6 +416,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.1" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + octo_image: + dependency: transitive + description: + name: octo_image + sha256: "45b40f99622f11901238e18d48f5f12ea36426d8eced9f4cbf58479c7aa2430d" + url: "https://pub.dev" + source: hosted + version: "2.0.0" package_config: dependency: transitive description: @@ -387,14 +456,78 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.1" + path_provider: + dependency: transitive + description: + name: path_provider + sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668" + url: "https://pub.dev" + source: hosted + version: "2.2.2" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 + url: "https://pub.dev" + source: hosted + version: "2.2.1" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" + url: "https://pub.dev" + source: hosted + version: "2.2.1" petitparser: dependency: transitive description: name: petitparser - sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 + sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750 + url: "https://pub.dev" + source: hosted + version: "5.4.0" + platform: + dependency: transitive + description: + name: platform + sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" + url: "https://pub.dev" + source: hosted + version: "3.1.4" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" url: "https://pub.dev" source: hosted - version: "6.0.2" + version: "2.1.8" pool: dependency: transitive description: @@ -403,6 +536,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.0" + provider: + dependency: "direct main" + description: + name: provider + sha256: "9a96a0a19b594dbc5bf0f1f27d2bc67d5f95957359b461cd9feb44ed6ae75096" + url: "https://pub.dev" + source: hosted + version: "6.1.1" pub_semver: dependency: transitive description: @@ -419,6 +560,70 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" + rxdart: + dependency: transitive + description: + name: rxdart + sha256: "0c7c0cedd93788d996e33041ffecda924cc54389199cde4e6a34b440f50044cb" + url: "https://pub.dev" + source: hosted + version: "0.27.7" + shared_preferences: + dependency: "direct main" + description: + name: shared_preferences + sha256: "81429e4481e1ccfb51ede496e916348668fd0921627779233bd24cc3ff6abd02" + url: "https://pub.dev" + source: hosted + version: "2.2.2" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + sha256: "8568a389334b6e83415b6aae55378e158fbc2314e074983362d20c562780fb06" + url: "https://pub.dev" + source: hosted + version: "2.2.1" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c" + url: "https://pub.dev" + source: hosted + version: "2.3.5" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: "9f2cbcf46d4270ea8be39fa156d86379077c8a5228d9dfdb1164ae0bb93f1faa" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + sha256: "22e2ecac9419b4246d7c22bfbbda589e3acf5c0351137d87dd2939d984d37c3b" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + sha256: d762709c2bbe80626ecc819143013cc820fa49ca5e363620ee20a8b15a3e3daf + url: "https://pub.dev" + source: hosted + version: "2.2.1" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: "841ad54f3c8381c480d0c9b508b89a34036f512482c407e6df7a9c4aa2ef8f59" + url: "https://pub.dev" + source: hosted + version: "2.3.2" shelf: dependency: transitive description: @@ -464,22 +669,46 @@ packages: url: "https://pub.dev" source: hosted version: "1.10.0" + sprintf: + dependency: transitive + description: + name: sprintf + sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" + url: "https://pub.dev" + source: hosted + version: "7.0.0" + sqflite: + dependency: transitive + description: + name: sqflite + sha256: a9016f495c927cb90557c909ff26a6d92d9bd54fc42ba92e19d4e79d61e798c6 + url: "https://pub.dev" + source: hosted + version: "2.3.2" + sqflite_common: + dependency: transitive + description: + name: sqflite_common + sha256: "28d8c66baee4968519fb8bd6cdbedad982d6e53359091f0b74544a9f32ec72d5" + url: "https://pub.dev" + source: hosted + version: "2.5.3" stack_trace: dependency: transitive description: name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.11.0" stream_channel: dependency: transitive description: name: stream_channel - sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.1" stream_transform: dependency: transitive description: @@ -496,6 +725,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" + synchronized: + dependency: transitive + description: + name: synchronized + sha256: "539ef412b170d65ecdafd780f924e5be3f60032a1128df156adad6c5b373d558" + url: "https://pub.dev" + source: hosted + version: "3.1.0+1" term_glyph: dependency: transitive description: @@ -508,10 +745,10 @@ packages: dependency: transitive description: name: test_api - sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" url: "https://pub.dev" source: hosted - version: "0.6.1" + version: "0.6.0" timing: dependency: transitive description: @@ -528,6 +765,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.0" + uuid: + dependency: transitive + description: + name: uuid + sha256: "22c94e5ad1e75f9934b766b53c742572ee2677c56bc871d850a57dad0f82127f" + url: "https://pub.dev" + source: hosted + version: "4.2.2" vector_graphics: dependency: transitive description: @@ -572,10 +817,10 @@ packages: dependency: transitive description: name: web - sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 + sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 url: "https://pub.dev" source: hosted - version: "0.3.0" + version: "0.1.4-beta" web_socket_channel: dependency: transitive description: @@ -584,14 +829,30 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.0" + win32: + dependency: transitive + description: + name: win32 + sha256: b0f37db61ba2f2e9b7a78a1caece0052564d1bc70668156cf3a29d676fe4e574 + url: "https://pub.dev" + source: hosted + version: "5.1.1" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d + url: "https://pub.dev" + source: hosted + version: "1.0.4" xml: dependency: transitive description: name: xml - sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + sha256: "5bc72e1e45e941d825fd7468b9b4cc3b9327942649aeb6fc5cdbf135f0a86e84" url: "https://pub.dev" source: hosted - version: "6.5.0" + version: "6.3.0" yaml: dependency: transitive description: @@ -601,5 +862,5 @@ packages: source: hosted version: "3.1.0" sdks: - dart: ">=3.2.0 <4.0.0" - flutter: ">=3.7.0-0" + dart: ">=3.1.0 <4.0.0" + flutter: ">=3.10.0" diff --git a/pubspec.yaml b/pubspec.yaml index be3055e0..08d5c018 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,6 +16,9 @@ dependencies: dio: ^5.4.0 json_annotation: ^4.8.1 flutter_svg: ^2.0.9 + provider: ^6.1.1 + shared_preferences: ^2.2.2 + cached_network_image: ^3.3.1 dev_dependencies: flutter_test: diff --git a/test/stateManagement/provider_test.dart b/test/stateManagement/provider_test.dart new file mode 100644 index 00000000..50d33d7e --- /dev/null +++ b/test/stateManagement/provider_test.dart @@ -0,0 +1,17 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:restaurantour/providers/restaurantProvider.dart'; + +void main() { + group('RestaurantProvider', () { + test('fetchRestaurants should update restaurants list', () async { + final restaurantProvider = RestaurantProvider(); + + // Act + await restaurantProvider.fetchRestaurants(); + + // Assert + expect(restaurantProvider.restaurants, isNotNull); + expect(restaurantProvider.restaurants!.isNotEmpty, true); + }); + }); +} diff --git a/test/widget_test.dart b/test/widget_test.dart deleted file mode 100644 index 83fbeae4..00000000 --- a/test/widget_test.dart +++ /dev/null @@ -1,20 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility that Flutter provides. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:flutter_test/flutter_test.dart'; - -import 'package:restaurantour/main.dart'; - -void main() { - testWidgets('Page loads', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(const Restaurantour()); - - // Verify that tests will run - expect(find.text('Fetch Restaurants'), findsOneWidget); - }); -} diff --git a/test/widgets/address_test.dart b/test/widgets/address_test.dart new file mode 100644 index 00000000..df2edb8b --- /dev/null +++ b/test/widgets/address_test.dart @@ -0,0 +1,20 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:restaurantour/widgets/restaurantDetail/addressWidget.dart'; + +void main() { + testWidgets('AddressWidget should render correctly', + (WidgetTester tester) async { + // Arrange + const address = '123 Main St, City, Country'; + await tester.pumpWidget( + const MaterialApp( + home: AddressWidget(address: address), + ), + ); + + // Assert + expect(find.text('Address'), findsOneWidget); + expect(find.text(address), findsOneWidget); + }); +}