Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: RiverPod 적용 #38

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,6 @@ app.*.map.json
# GoogleMap api (android, ios) hidden
/android/local.properties
/ios/Runner/Storage.swift

# API
lib/services/api_constants.dart
54 changes: 26 additions & 28 deletions lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,46 +1,44 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'screen/signInUp/signIn.dart';
import 'services/product_list_api.dart';
import 'onboarding.dart';

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

class MyApp extends StatelessWidget {
class MyApp extends ConsumerWidget {
const MyApp({super.key});

@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => ItemListApi(),
child: MaterialApp(
theme: ThemeData(
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
elevation: 0,
shape: const StadiumBorder(),
minimumSize: const Size(327, 48),
backgroundColor: const Color(0xff54408C),
textStyle:
const TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
),
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
foregroundColor: const Color(0xff54408C),
textStyle: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
Widget build(BuildContext context, WidgetRef ref) {
final itemListApi = ref.watch(itemListProvider);
return MaterialApp(
theme: ThemeData(
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
elevation: 0,
shape: const StadiumBorder(),
minimumSize: const Size(327, 48),
backgroundColor: const Color(0xff54408C),
textStyle:
const TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
),
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
foregroundColor: const Color(0xff54408C),
textStyle: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
),
home: const OnBoarding(),
routes: {
'/signIn': (context) => const SignIn(),
},
),
home: const OnBoarding(),
routes: {
'/signIn': (context) => const SignIn(),
},
);
}
}
12 changes: 4 additions & 8 deletions lib/screen/home/category.dart
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
import 'package:flutter/material.dart';
import 'package:quick_drop/screen/home/item_bottom_modal.dart';
import '../../services/product_list_api.dart'; // Import your product list API
import 'package:flutter_riverpod/flutter_riverpod.dart';

class Category extends StatefulWidget {
class Category extends ConsumerWidget {
const Category({Key? key}) : super(key: key);

@override
State<Category> createState() => _CategoryState();
}

class _CategoryState extends State<Category> {
@override
Widget build(BuildContext context) {
Widget build(BuildContext context, WidgetRef ref) {
return Scaffold(
body: FutureBuilder<List<ProductInfo>>(
future: ItemListApi.fetchData(),
future: ref.watch(itemListProvider.future),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
Expand Down
142 changes: 65 additions & 77 deletions lib/screen/home/item_list.dart
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
import 'package:flutter/material.dart';
import 'item_bottom_modal.dart';
import '../../services/product_list_api.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:quick_drop/screen/home/item_bottom_modal.dart';
import 'package:quick_drop/services/product_list_api.dart';

class ItemList extends StatefulWidget {
const ItemList({Key? key}) : super(key: key);
final selectedCategoryProvider = StateProvider<String>((ref) => '');

@override
State<ItemList> createState() => _ItemListState();
}
final itemListProvider = FutureProvider.autoDispose<List<ProductInfo>>((ref) {
final category = ref.watch(selectedCategoryProvider);
return fetchData(
category: category); // Replace with your actual fetchData function
});

class _ItemListState extends State<ItemList> {
late Future<List<ProductInfo>> _productInfoList;
String _selectedCategory = ''; // Track the selected category
class ItemList extends ConsumerStatefulWidget {
const ItemList({Key? key}) : super(key: key);

@override
void initState() {
super.initState();
_productInfoList = ItemListApi.fetchData();
}
_ItemListState createState() => _ItemListState();
}

class _ItemListState extends ConsumerState<ItemList> {
@override
Widget build(BuildContext context) {
final productInfoList = ref.watch(itemListProvider);
final selectedCategory = ref.watch(selectedCategoryProvider);

return Scaffold(
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
Expand All @@ -46,66 +49,50 @@ class _ItemListState extends State<ItemList> {
),
),
Expanded(
child: FutureBuilder<List<ProductInfo>>(
future: _productInfoList,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator(),
);
} else if (snapshot.hasError) {
print(snapshot.error);
return const Center(
child: Text('Something went wrong'),
);
} else {
final List<ProductInfo> productInfoList = snapshot.data!;
// Filter the list based on selected category
final filteredList = _selectedCategory.isEmpty
? productInfoList
: productInfoList
.where((item) =>
item.category == _selectedCategory ||
_selectedCategory ==
'All') // Include 'All' category
.toList();
return ListView.builder(
itemCount: filteredList.length,
itemBuilder: (context, index) {
final productInfo = filteredList[index];
return InkWell(
onTap: () {
showModalBottomSheet<void>(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (context) {
return Container(
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(25.0),
topRight: Radius.circular(25.0),
),
child: productInfoList.when(
data: (productInfoList) {
return ListView.builder(
itemCount: productInfoList.length,
itemBuilder: (context, index) {
final productInfo = productInfoList[index];
return InkWell(
onTap: () {
showModalBottomSheet<void>(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (context) {
return Container(
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(25.0),
topRight: Radius.circular(25.0),
),
height:
MediaQuery.of(context).size.height * 0.77,
child:
ItemBottomModal(productInfo: productInfo),
);
},
);
},
child: ListTile(
title: Text(productInfo.title),
subtitle: Text(productInfo.category),
trailing: const Icon(Icons.arrow_forward),
),
);
},
);
}
),
height: MediaQuery.of(context).size.height * 0.77,
child: ItemBottomModal(
productInfo:
productInfo), // Replace with your actual ItemBottomModal widget
);
},
);
},
child: ListTile(
title: Text(productInfo.title),
subtitle: Text(productInfo.category),
trailing: const Icon(Icons.arrow_forward),
),
);
},
);
},
loading: () => const Center(
child: CircularProgressIndicator(),
),
error: (_, __) => const Center(
child: Text('Something went wrong'),
),
),
),
],
Expand All @@ -114,17 +101,18 @@ class _ItemListState extends State<ItemList> {
}

Widget buildCategoryButton(String category) {
final selectedCategory = ref.watch(selectedCategoryProvider);
return TextButton(
onPressed: () {
setState(() {
_selectedCategory = category; // Update the selected category
});
ref.watch(selectedCategoryProvider.notifier).state = category;
ref.watch(itemListProvider);
},
child: Text(
category,
style: TextStyle(
fontWeight: FontWeight.normal,
color: _selectedCategory == category ? Colors.black : Colors.grey),
fontWeight: FontWeight.normal,
color: selectedCategory == category ? Colors.black : Colors.grey,
),
),
);
}
Expand Down
70 changes: 38 additions & 32 deletions lib/screen/home/search/search_delegate.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:quick_drop/services/product_list_api.dart';

final searchQueryProvider = FutureProvider.autoDispose
.family<List<ProductInfo>, String>((ref, query) async {
if (query.isEmpty) {
return [];
} else {
return await fetchData(searchKeyword: query);
}
});

class ProductSearchDelegate extends SearchDelegate<ProductInfo?> {
ProductSearchDelegate();

Expand All @@ -16,38 +26,34 @@ class ProductSearchDelegate extends SearchDelegate<ProductInfo?> {

@override
Widget buildSuggestions(BuildContext context) {
if (query.isEmpty) {
return Container();
}

return FutureBuilder<List<ProductInfo>>(
future: ItemListApi.fetchData(searchKeyword: query),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
final results = snapshot.data!.where((productInfo) {
return productInfo.title
.toLowerCase()
.contains(query.toLowerCase());
}).toList();
return ListView.builder(
itemCount: results.length,
itemBuilder: (context, index) {
final item = results[index];
return ListTile(
title: Text(item.title),
onTap: () {
close(context, item);
},
);
},
);
}
},
);
return query.isEmpty
? Container()
: Consumer(builder: (context, ref, child) {
final searchResultsAsync = ref.watch(searchQueryProvider(query));
return searchResultsAsync.when(
data: (results) {
final filteredResults = results.where((productInfo) {
return productInfo.title
.toLowerCase()
.contains(query.toLowerCase());
}).toList();
return ListView.builder(
itemCount: filteredResults.length,
itemBuilder: (context, index) {
final item = filteredResults[index];
return ListTile(
title: Text(item.title),
onTap: () {
close(context, item);
},
);
},
);
},
loading: () => const Center(child: CircularProgressIndicator()),
error: (error, __) => Text('Error: $error'),
);
});
}

@override
Expand Down
Loading