Skip to content

Commit 10d5f70

Browse files
committed
add favorite restaurant
1 parent e8d8a45 commit 10d5f70

File tree

10 files changed

+313
-12
lines changed

10 files changed

+313
-12
lines changed

lib/main.dart

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ import 'package:flutter/material.dart';
22
import 'package:provider/provider.dart';
33
import 'package:restaurant_app/constant/colors.dart';
44
import 'package:restaurant_app/data/api/api_service.dart';
5+
import 'package:restaurant_app/providers/favorite_provider.dart';
56
import 'package:restaurant_app/providers/restaurant_detail_provider.dart';
67
import 'package:restaurant_app/providers/restaurant_provider.dart';
8+
import 'package:restaurant_app/screens/favorite_restaurant.dart';
79
import 'package:restaurant_app/screens/home.dart';
810
import 'package:restaurant_app/screens/restaurant_detail.dart';
911
import 'package:restaurant_app/screens/splash_screen.dart';
@@ -58,6 +60,10 @@ class MyApp extends StatelessWidget {
5860
'/home': (context) => ChangeNotifierProvider(
5961
create: (_) => RestaurantProvider(apiService: ApiService()),
6062
child: const Home()),
63+
'/favorite': (context) => ChangeNotifierProvider(
64+
create: (_) => FavouriteProvider(),
65+
child: FavoriteRestaurant(),
66+
),
6167
RestaurantDetail.routeName: (context) => MultiProvider(
6268
providers: [
6369
ChangeNotifierProvider(
@@ -66,7 +72,9 @@ class MyApp extends StatelessWidget {
6672
id: ModalRoute.of(context)!.settings.arguments
6773
as String)),
6874
ChangeNotifierProvider(
69-
create: (_) => RestaurantProvider(apiService: ApiService()))
75+
create: (_) =>
76+
RestaurantProvider(apiService: ApiService())),
77+
ChangeNotifierProvider(create: (_) => FavouriteProvider()),
7078
],
7179
child: RestaurantDetail(
7280
articleId: ModalRoute.of(context)!.settings.arguments as String,

lib/providers/favorite_provider.dart

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:restaurant_app/data/model/list_restaurant.dart';
3+
import 'package:restaurant_app/utils/db_helper.dart';
4+
5+
enum FavoriteState { isLoading, noData, hasData, error }
6+
7+
class FavouriteProvider with ChangeNotifier {
8+
List<RestaurantElement> _favouriteList = [];
9+
List<RestaurantElement> get favouriteList => _favouriteList;
10+
11+
FavoriteState _state = FavoriteState.hasData;
12+
FavoriteState get state => _state;
13+
14+
late DatabaseHelper _dbHelper;
15+
16+
FavouriteProvider() {
17+
_dbHelper = DatabaseHelper();
18+
getFavourite();
19+
}
20+
21+
Future<void> getFavourite() async {
22+
_state = FavoriteState.isLoading;
23+
notifyListeners();
24+
25+
final result = await _dbHelper.getRestaurants();
26+
_favouriteList = result
27+
.map((e) => RestaurantElement(
28+
id: e.id,
29+
name: e.name,
30+
description: e.description,
31+
pictureId: e.pictureId,
32+
city: e.city,
33+
rating: e.rating))
34+
.toList();
35+
36+
if (_favouriteList.isEmpty) {
37+
_state = FavoriteState.noData;
38+
} else {
39+
_state = FavoriteState.hasData;
40+
}
41+
notifyListeners();
42+
}
43+
44+
Future<void> addFavorite(RestaurantElement restaurant) async {
45+
await _dbHelper.insertRestaurant(restaurant);
46+
getFavourite();
47+
}
48+
49+
Future<void> removeRestaurant(String id) async {
50+
await _dbHelper.removeRestaurant(id);
51+
getFavourite();
52+
}
53+
54+
Future<bool> isFavourite(String id) async {
55+
final result = await _dbHelper.getRestaurantById(id);
56+
return result.isNotEmpty;
57+
}
58+
}

lib/screens/favorite_restaurant.dart

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:provider/provider.dart';
3+
import 'package:restaurant_app/constant/urls.dart';
4+
import 'package:restaurant_app/providers/favorite_provider.dart';
5+
import 'package:restaurant_app/screens/restaurant_detail.dart';
6+
7+
class FavoriteRestaurant extends StatefulWidget {
8+
const FavoriteRestaurant({Key? key}) : super(key: key);
9+
10+
@override
11+
State<FavoriteRestaurant> createState() => _FavoriteRestaurantState();
12+
}
13+
14+
class _FavoriteRestaurantState extends State<FavoriteRestaurant> {
15+
@override
16+
Widget build(BuildContext context) {
17+
return Scaffold(
18+
appBar: AppBar(
19+
title: Text('Favorite Restaurant'),
20+
),
21+
body: Padding(
22+
padding: const EdgeInsets.all(8.0),
23+
child: Consumer<FavouriteProvider>(builder: (context, value, _) {
24+
if (value.state == FavoriteState.isLoading) {
25+
return const Center(
26+
child: CircularProgressIndicator(),
27+
);
28+
} else if (value.state == FavoriteState.hasData) {
29+
return ListView.builder(
30+
itemCount: value.favouriteList.length,
31+
itemBuilder: (context, index) {
32+
final restaurant = value.favouriteList[index];
33+
return Card(
34+
child: ListTile(
35+
onTap: () {
36+
Navigator.pushNamed(context, RestaurantDetail.routeName,
37+
arguments: restaurant.id);
38+
},
39+
leading: Image.network(
40+
imageMedium + restaurant.pictureId,
41+
width: 100,
42+
),
43+
title: Text(restaurant.name),
44+
subtitle: Text(restaurant.city),
45+
trailing: IconButton(
46+
onPressed: () {
47+
value.removeRestaurant(restaurant.id);
48+
},
49+
icon: const Icon(Icons.delete),
50+
),
51+
),
52+
);
53+
},
54+
);
55+
} else {
56+
return const Center(
57+
child: Text('No data'),
58+
);
59+
}
60+
}),
61+
),
62+
);
63+
}
64+
}

lib/screens/home.dart

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,12 @@ class _HomeState extends State<Home> {
2727
return Scaffold(
2828
appBar: AppBar(
2929
leading: IconButton(
30-
onPressed: () {},
30+
onPressed: () {
31+
Navigator.of(context).pushNamed('/favorite');
32+
},
3133
icon: const Icon(
32-
Icons.menu,
33-
color: Colors.black,
34+
Icons.favorite_border,
35+
color: Colors.green,
3436
),
3537
),
3638
title: const Center(

lib/screens/restaurant_detail.dart

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import 'package:flutter/material.dart';
22
import 'package:provider/provider.dart';
33
import 'package:restaurant_app/constant/urls.dart';
4+
import 'package:restaurant_app/data/model/list_restaurant.dart';
5+
import 'package:restaurant_app/providers/favorite_provider.dart';
46
import 'package:restaurant_app/providers/restaurant_detail_provider.dart';
57
import 'package:restaurant_app/providers/restaurant_provider.dart';
68
import 'package:restaurant_app/widget/detail_restaurant_menu.dart';
@@ -85,12 +87,54 @@ class _RestaurantDetailState extends State<RestaurantDetail> {
8587
),
8688
Padding(
8789
padding: const EdgeInsets.symmetric(horizontal: 12),
88-
child: Text(
89-
value.restaurantDetail.restaurant.name,
90-
style: const TextStyle(
91-
fontSize: 24,
92-
fontWeight: FontWeight.bold,
93-
),
90+
child: Row(
91+
children: [
92+
Text(
93+
value.restaurantDetail.restaurant.name,
94+
style: const TextStyle(
95+
fontSize: 24,
96+
fontWeight: FontWeight.bold,
97+
),
98+
),
99+
const Spacer(),
100+
Consumer<FavouriteProvider>(
101+
builder: (context2, value2, _) {
102+
var check = value2.favouriteList
103+
.where(
104+
(element) => element.id == widget.articleId)
105+
.isNotEmpty;
106+
return IconButton(
107+
onPressed: () async {
108+
if (check == true) {
109+
await value2
110+
.removeRestaurant(widget.articleId);
111+
showSnackBar(
112+
"Berhasil menghapus dari favorit");
113+
} else {
114+
await value2.addFavorite(RestaurantElement(
115+
id: widget.articleId,
116+
name: value
117+
.restaurantDetail.restaurant.name,
118+
description: value.restaurantDetail
119+
.restaurant.description,
120+
pictureId: value.restaurantDetail
121+
.restaurant.pictureId,
122+
city: value
123+
.restaurantDetail.restaurant.city,
124+
rating: value.restaurantDetail
125+
.restaurant.rating));
126+
showSnackBar(
127+
"Berhasil menambahkan ke favorit");
128+
}
129+
},
130+
icon: Icon(
131+
check == true
132+
? Icons.favorite
133+
: Icons.favorite_border,
134+
color: Theme.of(context).primaryColor,
135+
));
136+
})
137+
],
94138
),
95139
),
96140
Padding(

lib/screens/settings.dart

Whitespace-only changes.

lib/utils/db_helper.dart

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import 'package:path/path.dart';
2+
import 'package:restaurant_app/data/model/list_restaurant.dart';
3+
import 'package:sqflite/sqflite.dart';
4+
5+
class DatabaseHelper {
6+
static DatabaseHelper? _databaseHelper;
7+
static late Database _database;
8+
9+
DatabaseHelper._internal() {
10+
_databaseHelper = this;
11+
}
12+
13+
factory DatabaseHelper() => _databaseHelper ?? DatabaseHelper._internal();
14+
15+
Future<Database> get database async {
16+
_database = await _initializeDb();
17+
return _database;
18+
}
19+
20+
static const String _tableName = 'favorite_restaurant';
21+
22+
Future<Database> _initializeDb() async {
23+
var path = await getDatabasesPath();
24+
var db = openDatabase(
25+
join(path, 'restaurant.db'),
26+
onCreate: (db, version) async {
27+
await db.execute(
28+
'''CREATE TABLE $_tableName (
29+
id PRIMARY KEY UNIQUE NOT NULL,
30+
restaurant_id TEXT, name TEXT, pictureId TEXT, city TEXT, rating DOUBLE
31+
)''',
32+
);
33+
},
34+
version: 1,
35+
);
36+
37+
return db;
38+
}
39+
40+
Future<void> insertRestaurant(RestaurantElement restaurant) async {
41+
print("ADD RESTAURANT");
42+
final Database db = await database;
43+
await db.rawQuery('''
44+
INSERT INTO $_tableName (id, name, pictureId, city, rating)
45+
VALUES (?, ?, ?, ?, ?)
46+
''', [
47+
restaurant.id,
48+
restaurant.name,
49+
restaurant.pictureId,
50+
restaurant.city,
51+
restaurant.rating,
52+
]);
53+
}
54+
55+
Future<List<RestaurantElement>> getRestaurants() async {
56+
final Database db = await database;
57+
List<Map<String, dynamic>> results = await db.query(_tableName);
58+
print("INI RESULTS" + results.toString());
59+
var a = results
60+
.map(
61+
(res) => RestaurantElement(
62+
id: res['id'] ?? "",
63+
name: res['name'] ?? "",
64+
description: res["description"] ?? "",
65+
pictureId: res["pictureId"] ?? "",
66+
city: res["city"] ?? "",
67+
rating: 0.0),
68+
)
69+
.toList();
70+
if (a.isEmpty) {
71+
return [];
72+
} else {
73+
return a;
74+
}
75+
}
76+
77+
Future<Map<String, dynamic>> getRestaurantById(String id) async {
78+
final Database db = await database;
79+
List<Map<String, dynamic>> results = await db.query(
80+
_tableName,
81+
where: 'id = ?',
82+
whereArgs: [id],
83+
);
84+
85+
print("INI RESULTS" + results.toString());
86+
return results.first;
87+
}
88+
89+
Future<void> removeRestaurant(String id) async {
90+
final db = await database;
91+
await db.delete(
92+
_tableName,
93+
where: 'id = ?',
94+
whereArgs: [id],
95+
);
96+
}
97+
}

macos/Flutter/GeneratedPluginRegistrant.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import FlutterMacOS
66
import Foundation
77

8+
import sqflite
89

910
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
11+
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
1012
}

0 commit comments

Comments
 (0)