diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..1b8bfd5 Binary files /dev/null and b/.DS_Store differ diff --git a/babymeal/assets/images/allergy_bean.png b/babymeal/assets/images/allergy_bean.png new file mode 100644 index 0000000..53e768f Binary files /dev/null and b/babymeal/assets/images/allergy_bean.png differ diff --git a/babymeal/assets/images/allergy_beef.png b/babymeal/assets/images/allergy_beef.png new file mode 100644 index 0000000..0908747 Binary files /dev/null and b/babymeal/assets/images/allergy_beef.png differ diff --git a/babymeal/assets/images/allergy_buckwheat.png b/babymeal/assets/images/allergy_buckwheat.png new file mode 100644 index 0000000..3e1a800 Binary files /dev/null and b/babymeal/assets/images/allergy_buckwheat.png differ diff --git a/babymeal/assets/images/allergy_chicken.png b/babymeal/assets/images/allergy_chicken.png new file mode 100644 index 0000000..ee04e96 Binary files /dev/null and b/babymeal/assets/images/allergy_chicken.png differ diff --git a/babymeal/assets/images/allergy_crab.png b/babymeal/assets/images/allergy_crab.png new file mode 100644 index 0000000..4176744 Binary files /dev/null and b/babymeal/assets/images/allergy_crab.png differ diff --git a/babymeal/assets/images/allergy_egg.png b/babymeal/assets/images/allergy_egg.png new file mode 100644 index 0000000..5f23566 Binary files /dev/null and b/babymeal/assets/images/allergy_egg.png differ diff --git a/babymeal/assets/images/allergy_mackerel.png b/babymeal/assets/images/allergy_mackerel.png new file mode 100644 index 0000000..0159dbc Binary files /dev/null and b/babymeal/assets/images/allergy_mackerel.png differ diff --git a/babymeal/assets/images/allergy_milk.png b/babymeal/assets/images/allergy_milk.png new file mode 100644 index 0000000..879f5a9 Binary files /dev/null and b/babymeal/assets/images/allergy_milk.png differ diff --git a/babymeal/assets/images/allergy_peach.png b/babymeal/assets/images/allergy_peach.png new file mode 100644 index 0000000..23f582a Binary files /dev/null and b/babymeal/assets/images/allergy_peach.png differ diff --git a/babymeal/assets/images/allergy_peanut.png b/babymeal/assets/images/allergy_peanut.png new file mode 100644 index 0000000..3bb67f0 Binary files /dev/null and b/babymeal/assets/images/allergy_peanut.png differ diff --git a/babymeal/assets/images/allergy_pinenut.png b/babymeal/assets/images/allergy_pinenut.png new file mode 100644 index 0000000..c91ca04 Binary files /dev/null and b/babymeal/assets/images/allergy_pinenut.png differ diff --git a/babymeal/assets/images/allergy_pork.png b/babymeal/assets/images/allergy_pork.png new file mode 100644 index 0000000..36f74c2 Binary files /dev/null and b/babymeal/assets/images/allergy_pork.png differ diff --git a/babymeal/assets/images/allergy_seaweed.png b/babymeal/assets/images/allergy_seaweed.png new file mode 100644 index 0000000..062ee59 Binary files /dev/null and b/babymeal/assets/images/allergy_seaweed.png differ diff --git a/babymeal/assets/images/allergy_shrimp.png b/babymeal/assets/images/allergy_shrimp.png new file mode 100644 index 0000000..2ec7b5d Binary files /dev/null and b/babymeal/assets/images/allergy_shrimp.png differ diff --git a/babymeal/assets/images/allergy_squid.png b/babymeal/assets/images/allergy_squid.png new file mode 100644 index 0000000..f6671dc Binary files /dev/null and b/babymeal/assets/images/allergy_squid.png differ diff --git a/babymeal/assets/images/allergy_sulfurous.png b/babymeal/assets/images/allergy_sulfurous.png new file mode 100644 index 0000000..1f1504a Binary files /dev/null and b/babymeal/assets/images/allergy_sulfurous.png differ diff --git a/babymeal/assets/images/allergy_tomato.png b/babymeal/assets/images/allergy_tomato.png new file mode 100644 index 0000000..47caba1 Binary files /dev/null and b/babymeal/assets/images/allergy_tomato.png differ diff --git a/babymeal/assets/images/allergy_walnut.png b/babymeal/assets/images/allergy_walnut.png new file mode 100644 index 0000000..f2d6182 Binary files /dev/null and b/babymeal/assets/images/allergy_walnut.png differ diff --git a/babymeal/assets/images/allergy_wheat.png b/babymeal/assets/images/allergy_wheat.png new file mode 100644 index 0000000..2128667 Binary files /dev/null and b/babymeal/assets/images/allergy_wheat.png differ diff --git a/babymeal/assets/images/level2_none.png b/babymeal/assets/images/level2_none.png new file mode 100644 index 0000000..32b1081 Binary files /dev/null and b/babymeal/assets/images/level2_none.png differ diff --git a/babymeal/assets/images/progress2.png b/babymeal/assets/images/progress2.png new file mode 100644 index 0000000..07bbc26 Binary files /dev/null and b/babymeal/assets/images/progress2.png differ diff --git a/babymeal/ios/Flutter/Debug.xcconfig b/babymeal/ios/Flutter/Debug.xcconfig index 592ceee..ec97fc6 100644 --- a/babymeal/ios/Flutter/Debug.xcconfig +++ b/babymeal/ios/Flutter/Debug.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/babymeal/ios/Flutter/Release.xcconfig b/babymeal/ios/Flutter/Release.xcconfig index 592ceee..c4855bf 100644 --- a/babymeal/ios/Flutter/Release.xcconfig +++ b/babymeal/ios/Flutter/Release.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/babymeal/ios/Podfile b/babymeal/ios/Podfile new file mode 100644 index 0000000..fdcc671 --- /dev/null +++ b/babymeal/ios/Podfile @@ -0,0 +1,44 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '11.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/babymeal/lib/model/CustomerModel.dart b/babymeal/lib/model/CustomerModel.dart new file mode 100644 index 0000000..b583b0f --- /dev/null +++ b/babymeal/lib/model/CustomerModel.dart @@ -0,0 +1,25 @@ +class Customer { + final String customerName; + final String rank; + final int myLikes; + final int myComments; + final int myPosts; + + Customer({ + required this.customerName, + required this.rank, + required this.myLikes, + required this.myComments, + required this.myPosts, + }); + + factory Customer.fromJson(Map json) { + return Customer( + customerName: json['customerName'], + rank: json['rank'], + myLikes: json['myLikes'], + myComments: json['myComments'], + myPosts: json['myPosts'], + ); + } +} diff --git a/babymeal/lib/model/FridgeRecipe.dart b/babymeal/lib/model/FridgeRecipe.dart new file mode 100644 index 0000000..4bc38a9 --- /dev/null +++ b/babymeal/lib/model/FridgeRecipe.dart @@ -0,0 +1,41 @@ +class FridgeRecipe { + int? simpleDietId; + String? dietName; + int? time; + String? difficulty; + bool? heart; + + FridgeRecipe({ + this.simpleDietId, + this.dietName, + this.time, + this.difficulty, + this.heart, + }); + + factory FridgeRecipe.fromJson(Map json) { + return FridgeRecipe( + simpleDietId: json['simpleDietId'], + dietName: json['dietName'], + time: json['time'], + difficulty: json['difficulty'], + heart: json['heart'], + ); + } + + Map toJson() { + return { + 'simpleDietId': simpleDietId, + 'dietName': dietName, + 'time': time, + 'difficulty': difficulty, + 'heart': heart, + }; + } + + @override + String toString() { + return 'FridgeRecipe(simpleDietId: $simpleDietId, dietName: $dietName, time: $time, difficulty: $difficulty, heart: $heart)'; + } + +} \ No newline at end of file diff --git a/babymeal/lib/model/RecipeDetailModel.dart b/babymeal/lib/model/RecipeDetailModel.dart new file mode 100644 index 0000000..f7b9183 --- /dev/null +++ b/babymeal/lib/model/RecipeDetailModel.dart @@ -0,0 +1,48 @@ +class RecipeDetail { + String? dietName; + String? description; + String? ingredients; + String? recipe; + int? time; + String? difficulty; + bool? heart; + + RecipeDetail({ + this.dietName, + this.description, + this.ingredients, + this.recipe, + this.time, + this.difficulty, + this.heart + }); + + factory RecipeDetail.fromJson(Map json) { + return RecipeDetail( + dietName: json['dietName'], + description: json['description'], + ingredients: json['ingredients'], + recipe: json['recipe'], + time: json['time'], + difficulty: json['difficulty'], + heart: json['heart'] + ); + } + + Map toJson() { + return { + 'dietName': dietName, + 'description': description, + 'ingredients': ingredients, + 'recipe': recipe, + 'time': time, + 'difficulty': difficulty, + 'heart': heart + }; + } + + @override + String toString() { + return 'RecipeDetail(dietName: $dietName, description: $description, ingredients: $ingredients, time: $time, difficulty: $difficulty, recipe: $recipe)'; + } +} \ No newline at end of file diff --git a/babymeal/lib/model/RecipeModel.dart b/babymeal/lib/model/RecipeModel.dart new file mode 100644 index 0000000..1577d08 --- /dev/null +++ b/babymeal/lib/model/RecipeModel.dart @@ -0,0 +1,44 @@ +class GetRecipe { + int? simpleDietId; + String? dietName; + String? description; + int? time; + String? difficulty; + bool? heart; + + GetRecipe({ + this.simpleDietId, + this.dietName, + this.description, + this.time, + this.difficulty, + this.heart, + }); + + factory GetRecipe.fromJson(Map json) { + return GetRecipe( + simpleDietId: json['simpleDietId'], + dietName: json['dietName'], + description: json['description'], + time: json['time'], + difficulty: json['difficulty'], + heart: json['heart'], + ); + } + + Map toJson() { + return { + 'simpleDietId': simpleDietId, + 'dietName': dietName, + 'description': description, + 'time': time, + 'difficulty': difficulty, + 'heart': heart, + }; + } + + @override + String toString() { + return 'GetRecipe(simpleDietId: $simpleDietId, dietName: $dietName, description: $description, time: $time, difficulty: $difficulty, heart: $heart)'; + } +} \ No newline at end of file diff --git a/babymeal/lib/pages/mypage/ChangeChildAllergy.dart b/babymeal/lib/pages/mypage/ChangeChildAllergy.dart index 50e1142..a782f71 100644 --- a/babymeal/lib/pages/mypage/ChangeChildAllergy.dart +++ b/babymeal/lib/pages/mypage/ChangeChildAllergy.dart @@ -1,5 +1,10 @@ +import 'package:babymeal/pages/mypage/ViewChildInfoPage.dart'; +import 'package:babymeal/pages/mypage/ViewMyPage.dart'; +import 'package:babymeal/services/MyPageService.dart'; import 'package:flutter/material.dart'; - +import 'dart:convert'; +import 'package:http/http.dart' as http; +import 'package:shared_preferences/shared_preferences.dart'; class ChangeChildAllergyPageWidget extends StatefulWidget { const ChangeChildAllergyPageWidget({Key? key}) : super(key: key); @@ -32,6 +37,29 @@ class _ChangeChildAllergyPageWidgetState "조개류", "잣" ]; + + List imageList = [ + 'assets/images/allergy_egg.png', + 'assets/images/allergy_milk.png', + 'assets/images/allergy_buckwheat.png', + 'assets/images/allergy_peanut.png', + 'assets/images/allergy_bean.png', + 'assets/images/allergy_wheat.png', + 'assets/images/allergy_mackerel.png', + 'assets/images/allergy_crab.png', + 'assets/images/allergy_shrimp.png', + 'assets/images/allergy_pork.png', + 'assets/images/allergy_peach.png', + 'assets/images/allergy_tomato.png', + 'assets/images/allergy_sulfurous.png', + 'assets/images/allergy_pinenut.png', + 'assets/images/allergy_chicken.png', + 'assets/images/allergy_beef.png', + 'assets/images/allergy_squid.png', + 'assets/images/allergy_seaweed.png', + 'assets/images/allergy_pork.png', +]; + List isSelected = List.generate(19, (index) => false); @override void initState() { @@ -43,6 +71,71 @@ class _ChangeChildAllergyPageWidgetState super.dispose(); } + + Future updateBabyData(String newAllergy) async { + final SharedPreferences prefs = await SharedPreferences.getInstance(); + final String? userToken = prefs.getString('accessToken'); + + MyPageService myPageService = MyPageService(); + String babyId = await myPageService.getBabyId(userToken!); + + final currentData = await myPageService.fetchCurrentBabyData(babyId); + + if (currentData == null) { + print('Failed to fetch current data'); + return; + } + + // 변경하고자 하는 필드만 새로운 값으로 업데이트합니다. + currentData['data'][0]['allergy'] = newAllergy; + print('newBabyName: $newAllergy'); + print('Current data: $currentData'); + + final babyData = currentData['data'][0]; + babyData['babyId'] = babyId; + + print('babyData: $babyData'); + + + + if (userToken == null) { + print('No token found'); + return; + } + + final response = await http.put( + Uri.parse('http://ec2-43-200-210-159.ap-northeast-2.compute.amazonaws.com:8080/customer/baby'), + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $userToken', + }, + body: jsonEncode(babyData), // 변경된 전체 데이터를 서버에 보냅니다. + + ); + + if (response.statusCode == 200) { + print('Baby data updated successfully'); + } else { + print('Failed to update baby data'); + } +} + +Future navigateFromChangeChildAllergyPage() async { + final result = await Navigator.push( + context, + MaterialPageRoute(builder: (context) => ViewChildInfoPageWidget()), + ); + + if (result == true) { + final SharedPreferences prefs = await SharedPreferences.getInstance(); + final String? userToken = prefs.getString('accessToken'); + MyPageService myPageService = MyPageService(); + String babyId = await myPageService.getBabyId(userToken!); + myPageService.fetchCurrentBabyData(babyId); + + } +} + @override Widget build(BuildContext context) { return Scaffold( @@ -52,9 +145,23 @@ class _ChangeChildAllergyPageWidgetState height: 55, child: FloatingActionButton.extended( elevation: 0, - backgroundColor: Color( - 0xFFFF5C39), ////////////////////////////////////////////////////// - onPressed: () {}, + backgroundColor: Color(0xFFFF5C39), + onPressed: () async{ + List selectedAllergies = []; + for (int i = 0; i < isSelected.length; i++) { + if (isSelected[i]) { + selectedAllergies.add(allergyList[i]); + } + } + String newAllergies = selectedAllergies.join(', '); + await updateBabyData(newAllergies); + await navigateFromChangeChildAllergyPage(); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + ViewMyPageWidget())); + }, label: Container( width: MediaQuery.of(context).size.width * 0.88, child: Row( @@ -158,6 +265,24 @@ class _ChangeChildAllergyPageWidgetState borderRadius: BorderRadius.circular(12), ), ), + child: ClipRRect( + borderRadius: BorderRadius.circular(12), + child: Stack( + children: [ + Image.asset( + imageList[index], + fit: BoxFit.cover, + ), + if (isSelected[index]) // isSelected가 true일 때만 오버레이 표시 + Container( + decoration: BoxDecoration( + color: Color(0xFFFF582C).withOpacity(0.2), // 투명한 주황색 + borderRadius: BorderRadius.circular(12), + ), + ), + ], + ), + ), ), Text( allergyList[index], diff --git a/babymeal/lib/pages/mypage/ChangeChildBirthPage.dart b/babymeal/lib/pages/mypage/ChangeChildBirthPage.dart index 0f605f3..16309b3 100644 --- a/babymeal/lib/pages/mypage/ChangeChildBirthPage.dart +++ b/babymeal/lib/pages/mypage/ChangeChildBirthPage.dart @@ -1,6 +1,11 @@ import 'package:babymeal/pages/auth/SigninEnterAllergyPage.dart'; +import 'package:babymeal/pages/mypage/ViewChildInfoPage.dart'; +import 'package:babymeal/pages/mypage/ViewMyPage.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'dart:convert'; +import 'package:http/http.dart' as http; +import 'package:shared_preferences/shared_preferences.dart'; class ChangeChildBirthPageWidget extends StatefulWidget { const ChangeChildBirthPageWidget({Key? key}) : super(key: key); @@ -26,6 +31,85 @@ class _ChangeChildBirthPageWidgetState super.dispose(); } + Future?> fetchCurrentBabyData(int babyId) async { + final SharedPreferences prefs = await SharedPreferences.getInstance(); + final String? token = prefs.getString('accessToken'); + + if (token == null) { + print('No token found'); + return null; + } + + final response = await http.get( + Uri.parse('http://ec2-43-200-210-159.ap-northeast-2.compute.amazonaws.com:8080/customer/baby'), + headers: { + 'Authorization': 'Bearer $token', + }, + ); + + if (response.statusCode == 200) { + final Map data = json.decode(utf8.decode(response.bodyBytes)); + return data; + } else { + print('Failed to fetch baby data'); + return null; + } +} + Future updateBabyData(int babyId, String newBirthday) async { + // 기존 데이터를 불러옵니다. + final currentData = await fetchCurrentBabyData(babyId); + + if (currentData == null) { + print('Failed to fetch current data'); + return; + } + + // 변경하고자 하는 필드만 새로운 값으로 업데이트합니다. + currentData['data'][0]['birth'] = newBirthday; + print('newBabyName: $newBirthday'); + print('Current data: $currentData'); + + final babyData = currentData['data'][0]; + babyData['babyId'] = babyId; + + print('babyData: $babyData'); + + final SharedPreferences prefs = await SharedPreferences.getInstance(); + final String? userToken = prefs.getString('accessToken'); + + if (userToken == null) { + print('No token found'); + return; + } + + final response = await http.put( + Uri.parse('http://ec2-43-200-210-159.ap-northeast-2.compute.amazonaws.com:8080/customer/baby'), + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $userToken', + }, + body: jsonEncode(babyData), // 변경된 전체 데이터를 서버에 보냅니다. + + ); + + if (response.statusCode == 200) { + print('Baby data updated successfully'); + } else { + print('Failed to update baby data'); + } +} + +Future navigateFromChangeChildBirthPage() async { + final result = await Navigator.push( + context, + MaterialPageRoute(builder: (context) => ViewChildInfoPageWidget()), + ); + + if (result == true) { + fetchCurrentBabyData(7); + } +} + @override Widget build(BuildContext context) { return Scaffold( @@ -43,12 +127,15 @@ class _ChangeChildBirthPageWidgetState onPressed: change_yearController!.text.length == 4 && change_monthController!.text.length == 2 && change_dayController!.text.length == 2 - ? () { + ? () async{ + final birthday = '${change_yearController!.text}-${change_monthController!.text}-${change_dayController!.text}'; + await updateBabyData(7, birthday); + await navigateFromChangeChildBirthPage(); Navigator.push( context, MaterialPageRoute( builder: (context) => - SigninEnterAllergyPageWidget())); + ViewMyPageWidget())); } : () {}, label: Container( diff --git a/babymeal/lib/pages/mypage/ChangeChildNamePage.dart b/babymeal/lib/pages/mypage/ChangeChildNamePage.dart index 094083b..68401b4 100644 --- a/babymeal/lib/pages/mypage/ChangeChildNamePage.dart +++ b/babymeal/lib/pages/mypage/ChangeChildNamePage.dart @@ -1,6 +1,10 @@ import 'package:babymeal/pages/mypage/ViewChildInfoPage.dart'; +import 'package:babymeal/pages/mypage/ViewMyPage.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'dart:convert'; +import 'package:http/http.dart' as http; +import 'package:shared_preferences/shared_preferences.dart'; class ChangeChildNamePageWidget extends StatefulWidget { const ChangeChildNamePageWidget({Key? key}) : super(key: key); @@ -32,6 +36,87 @@ class _ChangeChildNamePageWidgetState extends State { super.dispose(); } + Future?> fetchCurrentBabyData(int babyId) async { + final SharedPreferences prefs = await SharedPreferences.getInstance(); + final String? token = prefs.getString('accessToken'); + + if (token == null) { + print('No token found'); + return null; + } + + final response = await http.get( + Uri.parse('http://ec2-43-200-210-159.ap-northeast-2.compute.amazonaws.com:8080/customer/baby'), + headers: { + 'Authorization': 'Bearer $token', + }, + ); + + if (response.statusCode == 200) { + final Map data = json.decode(utf8.decode(response.bodyBytes)); + return data; + } else { + print('Failed to fetch baby data'); + return null; + } +} + Future updateBabyData(int babyId, String newBabyName) async { + // 기존 데이터를 불러옵니다. + final currentData = await fetchCurrentBabyData(babyId); + + if (currentData == null) { + print('Failed to fetch current data'); + return; + } + + // 변경하고자 하는 필드만 새로운 값으로 업데이트합니다. + currentData['data'][0]['babyName'] = newBabyName; + print('newBabyName: $newBabyName'); + print('Current data: $currentData'); + + final babyData = currentData['data'][0]; + babyData['babyId'] = babyId; + + print('babyData: $babyData'); + + final SharedPreferences prefs = await SharedPreferences.getInstance(); + final String? userToken = prefs.getString('accessToken'); + + if (userToken == null) { + print('No token found'); + return; + } + + final response = await http.put( + Uri.parse('http://ec2-43-200-210-159.ap-northeast-2.compute.amazonaws.com:8080/customer/baby'), + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $userToken', + }, + body: jsonEncode(babyData), // 변경된 전체 데이터를 서버에 보냅니다. + + ); + + if (response.statusCode == 200) { + print('Baby data updated successfully'); + } else { + print('Failed to update baby data'); + } +} + +// ViewChildInfoPageWidget에서 +Future navigateFromChangeChildNamePage() async { + final result = await Navigator.push( + context, + MaterialPageRoute(builder: (context) => ViewChildInfoPageWidget()), + ); + + if (result == true) { + fetchCurrentBabyData(7); + } +} + + @override Widget build(BuildContext context) { return Scaffold( @@ -45,11 +130,13 @@ class _ChangeChildNamePageWidgetState extends State { ? Color(0xFFFF5C39) : Color(0xFFBDBDBD), onPressed: change_nameController!.text.length > 0 - ? () { - Navigator.push( + ? () async{ + await updateBabyData(7, change_nameController!.text); + await navigateFromChangeChildNamePage(); + Navigator.push( context, MaterialPageRoute( - builder: (context) => ViewChildInfoPageWidget())); + builder: (context) => ViewMyPageWidget())); } : () {}, label: Container( diff --git a/babymeal/lib/pages/mypage/ChangeNicknamePage.dart b/babymeal/lib/pages/mypage/ChangeNicknamePage.dart index cd601fd..2d53bc4 100644 --- a/babymeal/lib/pages/mypage/ChangeNicknamePage.dart +++ b/babymeal/lib/pages/mypage/ChangeNicknamePage.dart @@ -2,6 +2,10 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:babymeal/pages/mypage/ManageMyPage.dart'; +import 'dart:convert'; +import 'package:http/http.dart' as http; +import 'package:shared_preferences/shared_preferences.dart'; + class ChangeNicknamePageWidget extends StatefulWidget { const ChangeNicknamePageWidget({super.key}); @@ -14,6 +18,7 @@ class _ChangeNicknamePageWidgetState extends State { TextEditingController? nickNameController = TextEditingController(); int _charCount = 0; bool isExist = false; + @override void initState() { super.initState(); @@ -32,6 +37,43 @@ class _ChangeNicknamePageWidgetState extends State { super.dispose(); } + Future updateNickname() async { + final SharedPreferences prefs = await SharedPreferences.getInstance(); + final String? token = prefs.getString('accessToken'); + + final String url = 'http://ec2-43-200-210-159.ap-northeast-2.compute.amazonaws.com:8080/customer/nickname'; + + if (token != null && nickNameController!.text.isNotEmpty) { + final response = await http.put( + Uri.parse(url), + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + body: jsonEncode({"customerName": nickNameController!.text}), + ); + + print(nickNameController!.text); + print(response.statusCode); + + if (response.statusCode == 200) { + final responseBody = json.decode(response.body); + if (responseBody["success"] && responseBody["data"] == true) { + // 닉네임 변경 성공 + Navigator.pop(context); + } else { + // 닉네임이 이미 존재하는 경우 + setState(() { + isExist = true; + }); + } + } else { + // 서버 에러 처리 + print("Error: ${response.body}"); + } + } + } + @override Widget build(BuildContext context) { @@ -46,7 +88,8 @@ class _ChangeNicknamePageWidgetState extends State { ? Color(0xFFFF5C39) : Color(0xFFBDBDBD), onPressed: !isExist && nickNameController!.text.length > 0 - ? () { + ? () async{ + await updateNickname(); Navigator.push( context, MaterialPageRoute( diff --git a/babymeal/lib/pages/mypage/ChangePasswordPage.dart b/babymeal/lib/pages/mypage/ChangePasswordPage.dart index 706b88f..57fb0bd 100644 --- a/babymeal/lib/pages/mypage/ChangePasswordPage.dart +++ b/babymeal/lib/pages/mypage/ChangePasswordPage.dart @@ -2,6 +2,9 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:babymeal/pages/mypage/ManageMyPage.dart'; +import 'dart:convert'; +import 'package:http/http.dart' as http; +import 'package:shared_preferences/shared_preferences.dart'; class ChagePasswordPageWidget extends StatefulWidget { const ChagePasswordPageWidget({super.key}); @@ -12,7 +15,6 @@ class ChagePasswordPageWidget extends StatefulWidget { class _ChagePasswordPageWidgetState extends State { final scaffoldKey = GlobalKey(); - String? currentPassword = 'dddd'; //TO DO //현재 비밀번호 가져오기 TextEditingController? passwordController = TextEditingController(); @@ -20,7 +22,8 @@ class _ChagePasswordPageWidgetState extends State { TextEditingController? checkpasswordController = TextEditingController(); int _charCount = 0; - bool isTrue = false; + bool isTrue = true; + bool isValidPassword = false; bool isMatch = true; @override @@ -35,16 +38,16 @@ class _ChagePasswordPageWidgetState extends State { }); } - void _truePassword(){ - if(passwordController!.text == currentPassword) - setState(() { - isTrue = true; - }); - else - setState(() { - isTrue = false; - }); - } + // void _truePassword(){ + // if(passwordController!.text == currentPassword) + // setState(() { + // isTrue = true; + // }); + // else + // setState(() { + // isTrue = false; + // }); + // } void _matchPassword(){ if(newpasswordController!.text == checkpasswordController!.text) @@ -65,6 +68,86 @@ class _ChagePasswordPageWidgetState extends State { super.dispose(); } + Future validateCurrentPassword(String inputPassword) async { + final String apiUrl = "http://ec2-43-200-210-159.ap-northeast-2.compute.amazonaws.com:8080/customer/password/validate"; + final SharedPreferences prefs = await SharedPreferences.getInstance(); + final String? userToken = prefs.getString('accessToken'); + + if (userToken == null) { + print('No user token found'); + // 사용자에게 로그인 필요 알림 처리 + return; + } + + final response = await http.post( + Uri.parse(apiUrl), + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $userToken', + }, + body: jsonEncode({ + "password": inputPassword, + }), + ); + + if (response.statusCode == 200) { + final responseBody = json.decode(response.body); + if (responseBody['success'] && responseBody['data'] == true) { + // 비밀번호 검증 성공 처리 + setState(() { + isValidPassword = true; + }); + } else { + // 비밀번호 검증 실패 처리 + setState(() { + isValidPassword = false; + }); + } + } else { + // HTTP 오류 처리 + print('Failed to validate password. Server responded with status code: ${response.statusCode}'); + } +} + + Future updatePassword() async { + final String apiUrl = "http://ec2-43-200-210-159.ap-northeast-2.compute.amazonaws.com:8080/customer/password"; + final SharedPreferences prefs = await SharedPreferences.getInstance(); + final String? userToken = prefs.getString('accessToken'); + + if (userToken == null) { + print('No user token found'); + // 사용자에게 로그인 필요 알림 처리 + return; + } + + final response = await http.put( + Uri.parse(apiUrl), + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $userToken', + }, + body: jsonEncode({ + "password": newpasswordController!.text, + }), + ); + + if (response.statusCode == 200) { + final responseBody = json.decode(response.body); + if (responseBody['success']) { + // 비밀번호 변경 성공 처리 + print('Password updated successfully'); + Navigator.pop(context); // 성공적으로 비밀번호를 변경하면 이전 화면으로 돌아갑니다. + } else { + // 서버에서 정의된 오류 메시지 표시 + print('Failed to update password: ${responseBody['message']}'); + } + } else { + // HTTP 오류 처리 + print('Failed to update password. Server responded with status code: ${response.statusCode}'); + } + } + + @override Widget build(BuildContext context) { return Scaffold( @@ -74,18 +157,23 @@ class _ChagePasswordPageWidgetState extends State { height: 55, child: FloatingActionButton.extended( elevation: 0, - backgroundColor: !isMatch && newpasswordController!.text.length > 9 && newpasswordController!.text.length < 16 + backgroundColor: isValidPassword && isMatch && newpasswordController!.text.length >= 9 && newpasswordController!.text.length < 16 ? Color(0xFFFF5C39) : Color(0xFFBDBDBD), - onPressed: !isMatch && newpasswordController!.text.length > 9 && newpasswordController!.text.length < 16 - ? () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => - ManageMyPageWidget())); - } - : () {}, + onPressed: () async { + // isMatch와 newpasswordController!.text.length 값 출력 + print('isMatch: $isMatch'); + print('newpasswordController text length: ${newpasswordController!.text.length}'); + + if (isValidPassword && isMatch && newpasswordController!.text.length >= 9 && newpasswordController!.text.length < 16) { + await updatePassword(); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + ManageMyPageWidget())); + } + }, label: Container( width: MediaQuery.of(context).size.width * 0.88, child: Row( @@ -151,7 +239,7 @@ class _ChagePasswordPageWidgetState extends State { LengthLimitingTextInputFormatter(16), ], onChanged: (value){ - _truePassword(); + validateCurrentPassword(value); }, decoration: InputDecoration( enabledBorder: UnderlineInputBorder( @@ -366,6 +454,19 @@ class _ChagePasswordPageWidgetState extends State { height: 0, letterSpacing: -0.24, ), + ) + else if(isValidPassword == false) + Text( + "현재 비밀번호가 틀렸습니다.", + textAlign: TextAlign.right, + style: TextStyle( + color: Color(0xFFFF5C39), + fontSize: 12, + fontFamily: 'Pretendard', + fontWeight: FontWeight.w400, + height: 0, + letterSpacing: -0.24, + ), ), ], ), diff --git a/babymeal/lib/pages/mypage/ManageMyPage.dart b/babymeal/lib/pages/mypage/ManageMyPage.dart index c0513a5..faf65c4 100644 --- a/babymeal/lib/pages/mypage/ManageMyPage.dart +++ b/babymeal/lib/pages/mypage/ManageMyPage.dart @@ -1,8 +1,14 @@ +import 'package:babymeal/pages/auth/SigninEnterEmailPage.dart'; import 'package:flutter/material.dart'; import 'package:babymeal/pages/mypage/ChangeNicknamePage.dart'; import 'package:babymeal/pages/mypage/ChangePasswordPage.dart'; import 'package:babymeal/pages/auth/SigninSelectEmailpage.dart'; +import 'package:http/http.dart' as http; +import 'dart:convert'; + +import 'package:shared_preferences/shared_preferences.dart'; + class ManageMyPageWidget extends StatefulWidget { const ManageMyPageWidget({Key? key}) : super(key: key); @@ -11,11 +17,94 @@ class ManageMyPageWidget extends StatefulWidget { } class _ManageMyPageWidgetState extends State { + String email = ''; + String nickname = ''; + String rank = ''; + + @override + void initState() { + super.initState(); + fetchUserInfo(); + } + +String getRankText(String? rank) { + switch (rank) { + case '초보': + return 'Lv.1 ${rank}'; + case '요리사': + return 'Lv.2 ${rank}'; + case '주방장': + return 'Lv.3 ${rank}'; + default: + return '알 수 없음'; // 기본값 + } +} + + Future fetchUserInfo() async { + final String url = 'http://ec2-43-200-210-159.ap-northeast-2.compute.amazonaws.com:8080/customer/manage'; + final SharedPreferences prefs = await SharedPreferences.getInstance(); + final String? token = prefs.getString('accessToken'); + + if (token != null) { + final response = await http.get( + Uri.parse(url), + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + ); + + if (response.statusCode == 200) { + final data = json.decode(utf8.decode(response.bodyBytes))['data']; + setState(() { + email = data['email']; + nickname = data['customerName']; + rank = data['rank']; // 서버에서 받은 등급 정보에 따라 변환하여 저장 + }); + } else { + print('Failed to load user info'); + } + } + } + + Future deleteAccount() async { + final String apiUrl = "http://ec2-43-200-210-159.ap-northeast-2.compute.amazonaws.com:8080/customer"; + final SharedPreferences prefs = await SharedPreferences.getInstance(); + final String? token = prefs.getString('accessToken'); + + if (token == null) { + print("No user token found"); + // 사용자에게 로그인이 필요함을 알림 + return; + } + + final response = await http.delete( + Uri.parse(apiUrl), + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + ); + + if (response.statusCode == 200) { + final responseBody = json.decode(response.body); + if (responseBody['success'] && responseBody['data'] == true) { + // 탈퇴 처리 성공 + print("Account deleted successfully"); + // 로그인 화면으로 이동하거나 로그아웃 처리 + Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (BuildContext context) => SigninEnterEmail()), (route) => false); + } else { + // 서버에서 정의된 오류 메시지 표시 + print("Failed to delete account: ${responseBody['message']}"); + } + } else { + // HTTP 오류 처리 + print("Failed to delete account. Server responded with status code: ${response.statusCode}"); + } +} + @override Widget build(BuildContext context) { - final email = 'mamma11@naver.com'; - final nickname = '서준맘'; - final level = 'Lv2.요리사등급'; return Scaffold( backgroundColor: Colors.white, @@ -157,7 +246,7 @@ class _ManageMyPageWidgetState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Padding( - padding: const EdgeInsets.fromLTRB(0, 0, 0, 0), + padding: const EdgeInsets.fromLTRB(0, 10, 0, 0), child: Text( '회원 등급', style: TextStyle( @@ -170,26 +259,29 @@ class _ManageMyPageWidgetState extends State { ), Row( children: [ - Text( - '$level', - style: TextStyle( - fontWeight: FontWeight.w400, - fontFamily: 'Pretendard', - fontSize: 15, - color: Color(0xFF212121), + Padding( + padding: const EdgeInsets.fromLTRB(0, 10, 15, 0), + child: Text( + getRankText(rank), + style: TextStyle( + fontWeight: FontWeight.w400, + fontFamily: 'Pretendard', + fontSize: 15, + color: Color(0xFF212121), + ), ), ), - IconButton( - onPressed: () { - //TO DO - //회원등급 페이지로 넘기기 - }, - padding: EdgeInsets.fromLTRB(0, 0, 0, 0), - icon: Icon( - Icons.arrow_forward_ios, - color: Color(0xFF616161), - size: 24, - )) + // IconButton( + // onPressed: () { + // //TO DO + // //회원등급 페이지로 넘기기 + // }, + // padding: EdgeInsets.fromLTRB(0, 0, 0, 0), + // icon: Icon( + // Icons.arrow_forward_ios, + // color: Color(0xFF616161), + // size: 24, + // )) ], ) ], @@ -199,7 +291,7 @@ class _ManageMyPageWidgetState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Padding( - padding: EdgeInsets.fromLTRB(10, 0, 0, 0), + padding: EdgeInsets.fromLTRB(10, 10, 0, 0), child: TextButton( child: Text( '계정 탈퇴', @@ -242,8 +334,7 @@ class _ManageMyPageWidgetState extends State { padding: EdgeInsets.fromLTRB(0, 0, 3, 0), child: ElevatedButton( onPressed: (){ - Navigator.pushAndRemoveUntil(context, MaterialPageRoute( - builder: (BuildContext context)=> SigninSelectEmail()),(route) => false); + deleteAccount(); }, style: ElevatedButton.styleFrom( backgroundColor: Color(0xFFBDBDBD), diff --git a/babymeal/lib/pages/mypage/MyPageComments.dart b/babymeal/lib/pages/mypage/MyPageComments.dart index e73d71f..ac5f9be 100644 --- a/babymeal/lib/pages/mypage/MyPageComments.dart +++ b/babymeal/lib/pages/mypage/MyPageComments.dart @@ -1,4 +1,7 @@ import 'package:flutter/material.dart'; +import 'dart:convert'; +import 'package:http/http.dart' as http; +import 'package:shared_preferences/shared_preferences.dart'; class MypageMyCommentsPageWidget extends StatefulWidget { const MypageMyCommentsPageWidget({super.key}); @@ -10,13 +13,48 @@ class MypageMyCommentsPageWidget extends StatefulWidget { class _MypageMyCommentsPageWidgetState extends State { - List CommentContext = [ - '좋은 글 잘 보고 가요!', - '생각해본 적 없는데 정말 좋은 방법이네요. 시도해볼게요!', - '감사합니다~' - ]; + List CommentContext = []; + List Comment_TimeContext = []; + + @override + void initState() { + super.initState(); + fetchMyComments(); + } + + Future fetchMyComments() async { + final prefs = await SharedPreferences.getInstance(); + final String? token = prefs.getString('accessToken'); + + if (token == null) { + print('Token not found'); + return; + } + + final response = await http.get( + Uri.parse('http://ec2-43-200-210-159.ap-northeast-2.compute.amazonaws.com:8080/customer/myComments'), + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + ); + + if (response.statusCode == 200) { + final data = jsonDecode(utf8.decode(response.bodyBytes)); + final comments = data['data'] as List; + + setState(() { + CommentContext = comments.map((comment) => comment['contents'] as String).toList(); + Comment_TimeContext = comments.map((comment) { + final time = DateTime.parse(comment['time']); + return '${time.toLocal()}'; // 여기서 원하는 형식으로 변환해야 할 수 있습니다. + }).toList(); + }); + } else { + print('Failed to fetch comments'); + } + } - List Comment_TimeContext = ['12시간전', '10일전', '15일전']; @override Widget build(BuildContext context) { return Scaffold( diff --git a/babymeal/lib/pages/mypage/MyPagePost.dart b/babymeal/lib/pages/mypage/MyPagePost.dart index 80bec5b..7269eaa 100644 --- a/babymeal/lib/pages/mypage/MyPagePost.dart +++ b/babymeal/lib/pages/mypage/MyPagePost.dart @@ -1,4 +1,7 @@ import 'package:flutter/material.dart'; +import 'dart:convert'; +import 'package:http/http.dart' as http; +import 'package:shared_preferences/shared_preferences.dart'; class MyPageMyPostsPageWidget extends StatefulWidget { const MyPageMyPostsPageWidget({super.key}); @@ -9,13 +12,48 @@ class MyPageMyPostsPageWidget extends StatefulWidget { } class _MyPageMyPostsPageWidgetState extends State { - List TitleContext = [ - '아이 훈육법에 대한 내 생각', - '[건대입구] 아이와 함께 가기 좋은 카페 \'웰컴베이비\' 추천합니다-메뉴,가격,주차정보', - '아이 밥 먹이는 꿀팁!!' - ]; + List TitleContext = []; + List Title_TimeContext = []; + + @override + void initState() { + super.initState(); + fetchMyPosts(); + } + + Future fetchMyPosts() async { + final prefs = await SharedPreferences.getInstance(); + final String? token = prefs.getString('accessToken'); + + if (token == null) { + print('Token not found'); + return; + } + + final response = await http.get( + Uri.parse('http://ec2-43-200-210-159.ap-northeast-2.compute.amazonaws.com:8080/customer/myPosts'), + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + ); + + if (response.statusCode == 200) { + final data = jsonDecode(utf8.decode(response.bodyBytes)); + final posts = data['data'] as List; + + setState(() { + TitleContext = posts.map((post) => post['title'] as String).toList(); + Title_TimeContext = posts.map((post) { + final updateTime = DateTime.parse(post['updateTime']); + return '${updateTime.toLocal()}'; + }).toList(); + }); + } else { + print('Failed to fetch posts'); + } + } - List Title_TimeContext = ['9시간전', '13일전', '20일전']; @override Widget build(BuildContext context) { return Scaffold( diff --git a/babymeal/lib/pages/mypage/ViewChildInfoPage.dart b/babymeal/lib/pages/mypage/ViewChildInfoPage.dart index fd9a808..a3b33ed 100644 --- a/babymeal/lib/pages/mypage/ViewChildInfoPage.dart +++ b/babymeal/lib/pages/mypage/ViewChildInfoPage.dart @@ -1,8 +1,13 @@ +import 'package:babymeal/model/BabyModel.dart'; import 'package:babymeal/pages/mypage/ChangeChildAllergy.dart'; import 'package:babymeal/pages/mypage/ChangeChildBirthPage.dart'; import 'package:babymeal/pages/mypage/ChangeChildNamePage.dart'; import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import 'dart:convert'; +import 'package:shared_preferences/shared_preferences.dart'; + class ViewChildInfoPageWidget extends StatefulWidget { const ViewChildInfoPageWidget({super.key}); @@ -12,6 +17,46 @@ class ViewChildInfoPageWidget extends StatefulWidget { } class _ViewChildInfoPageWidgetState extends State { + PostBaby? babyInfo; + + @override + void initState() { + super.initState(); + fetchBabyInfo(); + } + + Future fetchBabyInfo() async { + final SharedPreferences prefs = await SharedPreferences.getInstance(); + final String? token = prefs.getString('accessToken'); + + if (token == null) { + print('No token found'); + return; + } + + final response = await http.get( + Uri.parse('http://ec2-43-200-210-159.ap-northeast-2.compute.amazonaws.com:8080/customer/baby'), + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + ); + + if (response.statusCode == 200) { + final data = jsonDecode(utf8.decode(response.bodyBytes)); + if (data['success'] && data['data'] != null) { + setState(() { + babyInfo = PostBaby.fromJson(data['data'][0]); + }); + } + } else { + print('Failed to fetch baby info'); + } + + print(babyInfo?.babyName); + print(babyInfo?.birth); + } + @override Widget build(BuildContext context) { return Scaffold( @@ -70,7 +115,7 @@ class _ViewChildInfoPageWidgetState extends State { Padding( padding: EdgeInsets.fromLTRB(0, 0, 0, 0), child: Text( - '박서준', + babyInfo?.babyName ?? '', style: TextStyle( fontSize: 16.0, fontWeight: FontWeight.w500, @@ -117,7 +162,7 @@ class _ViewChildInfoPageWidgetState extends State { Padding( padding: EdgeInsets.fromLTRB(0, 0, 0, 0), child: Text( - '2020.12.01', + babyInfo?.birth ?? '', style: TextStyle( fontSize: 16.0, fontWeight: FontWeight.w500, @@ -158,20 +203,38 @@ class _ViewChildInfoPageWidgetState extends State { ), ), ), - IconButton( - onPressed: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => - ChangeChildAllergyPageWidget()), - ); - }, - icon: Icon( - Icons.arrow_forward_ios, - color: Color(0xFF949494), - size: 24, - )) + Padding( + padding: EdgeInsets.fromLTRB(0, 0, 0, 0), + child: Row( + children: [ + Padding( + padding: EdgeInsets.fromLTRB(0, 0, 0, 0), + child: Text( + babyInfo?.allergy ?? '', + style: TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.w500, + color: Color(0xFF212121), + ), + ), + ), + IconButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + ChangeChildAllergyPageWidget()), + ); + }, + icon: Icon( + Icons.arrow_forward_ios, + color: Color(0xFF949494), + size: 24, + )), + ], + ), + ) ], )), ]), diff --git a/babymeal/lib/pages/mypage/ViewMyPage.dart b/babymeal/lib/pages/mypage/ViewMyPage.dart index 405e582..68b5f96 100644 --- a/babymeal/lib/pages/mypage/ViewMyPage.dart +++ b/babymeal/lib/pages/mypage/ViewMyPage.dart @@ -1,9 +1,16 @@ +import 'package:babymeal/model/CustomerModel.dart'; import 'package:babymeal/pages/mypage/ManageMyPage.dart'; import 'package:babymeal/pages/mypage/MyPageComments.dart'; import 'package:babymeal/pages/mypage/MyPagePost.dart'; import 'package:babymeal/pages/mypage/ViewChildInfoPage.dart'; import 'package:flutter/material.dart'; +import 'dart:convert'; +import 'package:http/http.dart' as http; +import 'package:babymeal/model/RecipeModel.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'dart:convert' show utf8; + class ViewMyPageWidget extends StatefulWidget { const ViewMyPageWidget({Key? key}) : super(key: key); @@ -13,9 +20,12 @@ class ViewMyPageWidget extends StatefulWidget { class _ViewMyPageWidgetState extends State { final scaffoldKey = GlobalKey(); + Customer? customer; + @override void initState() { super.initState(); + fetchCustomerInfo(); } @override @@ -23,217 +33,220 @@ class _ViewMyPageWidgetState extends State { super.dispose(); } - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: Color(0xFFF4F3F0), - body: Column( - children: [ - Container( - padding: EdgeInsets.fromLTRB(20, 50, 0, 0), - color: Colors.white, - alignment: Alignment.centerLeft, - child: Text( - '마이페이지', - style: TextStyle( - color: Color(0xFF424242), - fontSize: 24, - fontFamily: 'Pretendard', - fontWeight: FontWeight.w600, - height: 0, - letterSpacing: -0.48, - ), - )), - Container( - color: Colors.white, - padding: EdgeInsets.fromLTRB(20, 32, 13, 0), - width: MediaQuery.of(context).size.width, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + Future fetchCustomerInfo() async { + final SharedPreferences prefs = await SharedPreferences.getInstance(); + final String? userToken = prefs.getString('accessToken'); + + final response = await http.get( + Uri.parse('http://ec2-43-200-210-159.ap-northeast-2.compute.amazonaws.com:8080/customer/my'), + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $userToken', + }, + ); + + if (response.statusCode == 200) { + final responseBody = json.decode(utf8.decode(response.bodyBytes)); + setState(() { + customer = Customer.fromJson(responseBody['data']); + }); + } else { + // 에러 처리 + print('Failed to load customer info'); + } + } + + String getRankText(String? rank) { + switch (rank) { + case '초보': + return 'Lv.1 ${rank}'; + case '요리사': + return 'Lv.2 ${rank}'; + case '주방장': + return 'Lv.3 ${rank}'; + default: + return '알 수 없음'; // 기본값 + } +} + + Widget rankWidget() { + if (customer?.rank == "초보") { + return Container( + padding: + EdgeInsets.only(left: 20, top: 18, right: 20, bottom: 21), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ + Text( + '회원 등급', + textAlign: TextAlign.center, + style: TextStyle( + color: Color(0xFF757575), + fontSize: 14, + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + height: 0, + letterSpacing: -0.28, + ), + ), Container( child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - Row( - children: [ - Container( - padding: EdgeInsets.only(right: 5), - child: Text( - '서준맘', - style: TextStyle( - color: Color(0xFF424242), - fontSize: 22, - fontFamily: 'Pretendard', - fontWeight: FontWeight.w700, - height: 0, - letterSpacing: -0.44, - ), - )), - Image.asset("assets/images/star.png") - ], + Transform.translate( + offset: Offset(20,0), + child: Text( + 'LEVEL 1', + textAlign: TextAlign.center, + style: TextStyle( + color: Color(0xFFFF5C39), + fontSize: 13, + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + height: 0, + letterSpacing: -0.26, + ), + ), ), Container( - padding: EdgeInsets.fromLTRB(4, 5, 0, 0), - child: Text( - 'Google 계정 연결', - style: TextStyle( - color: Color(0xFF9E9E9E), - fontSize: 12, - fontFamily: 'Pretendard', - fontWeight: FontWeight.w500, - height: 0, - letterSpacing: -0.24, - ), - )) - ], - )), - GestureDetector( - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => ManageMyPageWidget())); - }, - child: Container( - child: Row( - children: [ - Text( - '계정 관리', - textAlign: TextAlign.right, - style: TextStyle( - color: Color(0xFF616161), - fontSize: 14, - fontFamily: 'Pretendard', - fontWeight: FontWeight.w500, - height: 0, - ), - ), - Icon(Icons.keyboard_arrow_right, - color: Color(0xff616161)) - ], - ))) - ], - )), - Container( - padding: EdgeInsets.only(top: 26), - height: MediaQuery.of(context).size.height * 0.18, - color: Colors.white, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - InkWell( - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => - ViewChildInfoPageWidget())); - }, - child: Container( - padding: EdgeInsets.only(top: 18), - width: MediaQuery.of(context).size.width * 0.25, - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, + width: 88, + height: 49, + child: Stack( children: [ - Container( - padding: EdgeInsets.only(bottom: 5), - child: Image.asset("assets/images/baby.png"), + Positioned( + left: 30, + top: 49, + child: Transform( + transform: Matrix4.identity() + ..translate(0.0, 0.0) + ..rotateZ(-3.14), + child: Container( + width: 31, + height: 34, + decoration: ShapeDecoration( + color: Color(0xFFFF5C39), + shape: StarBorder.polygon( + sides: 3, + ), + ), + ), + ), ), - Text( - '아이 정보', - textAlign: TextAlign.center, - style: TextStyle( - color: Color(0xFF212121), - fontSize: 15, - fontFamily: 'Pretendard', - fontWeight: FontWeight.w500, - height: 0, - letterSpacing: -0.30, + Positioned( + left: 0, + top: 0, + child: Container( + child: Container( + padding: EdgeInsets.only(top: 16), + child: Text( + '초보', + textAlign: TextAlign.center, + style: TextStyle( + color: Colors.white, + fontSize: 18, + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + height: 0.08, + letterSpacing: -0.36, + ), + ), + ), + width: 88, + height: 33, + decoration: ShapeDecoration( + color: Color(0xFFFF5C39), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + ), ), - ) + ), ], - )), - ), - Container( - height: MediaQuery.of(context).size.height * - 0.08, // Divider의 높이 설정 - width: 1.0, // Divider의 두께 설정 - color: Color(0xffE0E0E0), // Divider의 색상 설정 - ), - InkWell( - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => - MyPageMyPostsPageWidget())); - }, - child: Container( - padding: EdgeInsets.only(top: 18), - width: MediaQuery.of(context).size.width * 0.28, - child: Column( + ), + ), + Stack( + alignment: Alignment.center, + children: [ + Stack( children: [ Container( - padding: EdgeInsets.only(bottom: 5), - child: Image.asset( - "assets/images/post_write.png"), + child: Container( + width: + MediaQuery.of(context).size.width * 0.9, + height: 18, + decoration: ShapeDecoration( + color: Color(0xFFE0E0E0), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + )), + Container( + width: + MediaQuery.of(context).size.width * 0, + height: 18, + decoration: ShapeDecoration( + color: Color(0xFFFF5C39), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(12), + bottomLeft: Radius.circular(12), + ), + ), + ), ), + ], + ), + Column( + children: [ + Image.asset("assets/images/level2_none.png"), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Image.asset("assets/images/progress_none.png") + ], + ) + ], + ), + Container( + padding: EdgeInsets.only(top: 5), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + SizedBox(width: MediaQuery.of(context).size.width * 0.15), Text( - '내 게시글', - textAlign: TextAlign.center, + 'Lv2.요리사', style: TextStyle( - color: Color(0xFF212121), - fontSize: 15, + color: Color(0xFF9E9E9E), + fontSize: 12, fontFamily: 'Pretendard', fontWeight: FontWeight.w500, height: 0, - letterSpacing: -0.30, + letterSpacing: -0.24, + ), + ), + Text( + 'Lv3.주방장', + textAlign: TextAlign.right, + style: TextStyle( + color: Color(0xFF9E9E9E), + fontSize: 12, + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + height: 0, + letterSpacing: -0.24, ), ) ], - ))), - Container( - height: MediaQuery.of(context).size.height * - 0.08, // Divider의 높이 설정 - width: 1.0, // Divider의 두께 설정 - color: Color(0xffE0E0E0), // Divider의 색상 설정 - ), - InkWell( - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => - MypageMyCommentsPageWidget())); - }, - child: Container( - padding: EdgeInsets.only(top: 10), - width: MediaQuery.of(context).size.width * 0.25, - child: Column( - children: [ - Container( - child: Image.asset( - "assets/images/comment.png", - ), - ), - Text( - '내 댓글', - textAlign: TextAlign.center, - style: TextStyle( - color: Color(0xFF212121), - fontSize: 15, - fontFamily: 'Pretendard', - fontWeight: FontWeight.w500, - height: 0, - letterSpacing: -0.30, - ), - ) - ], - )), - ) + )) + ], + )) ], - )), - Container( + )); + } else if (customer?.rank == "요리사") { + return Container( padding: EdgeInsets.only(left: 20, top: 28, right: 20, bottom: 21), child: Column( @@ -397,279 +410,676 @@ class _ViewMyPageWidgetState extends State { ], )) ], - )), - Container( - margin: EdgeInsets.only(right: 20, left: 20), - decoration: ShapeDecoration( - color: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - ), - ), - child: Column( - children: [ - Container( - padding: EdgeInsets.only(top: 25), - child: Text.rich( - TextSpan( - children: [ - TextSpan( - text: '서준맘님의 ', - style: TextStyle( - color: Color(0xFF424242), - fontSize: 15, - fontFamily: 'Pretendard', - fontWeight: FontWeight.w600, - height: 0, - letterSpacing: -0.30, - ), - ), - TextSpan( - text: 'Lv.3 주방장', + )); + } else { + return Container( + padding: + EdgeInsets.only(left: 20, top: 28, right: 20, bottom: 21), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '회원 등급', + textAlign: TextAlign.center, + style: TextStyle( + color: Color(0xFF757575), + fontSize: 14, + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + height: 0, + letterSpacing: -0.28, + ), + ), + Container( + child: Column( + children: [ + Transform.translate( + offset: Offset(145,0), + child: Text( + 'LEVEL 3', + textAlign: TextAlign.center, style: TextStyle( color: Color(0xFFFF5C39), - fontSize: 15, + fontSize: 13, fontFamily: 'Pretendard', - fontWeight: FontWeight.w600, + fontWeight: FontWeight.w700, height: 0, - letterSpacing: -0.30, + letterSpacing: -0.26, ), ), - TextSpan( - text: ' 달성률', - style: TextStyle( - color: Color(0xFF424242), - fontSize: 15, - fontFamily: 'Pretendard', - fontWeight: FontWeight.w600, - height: 0, - letterSpacing: -0.30, + ), + Padding( + padding: const EdgeInsets.fromLTRB(280,0,0,0), + child: Container( + width: 88, + height: 49, + child: Stack( + children: [ + Positioned( + left: 92, + top: 49, + child: Transform( + transform: Matrix4.identity() + ..translate(0.0, 0.0) + ..rotateZ(-3.14), + child: Container( + width: 31, + height: 34, + decoration: ShapeDecoration( + color: Color(0xFFFF5C39), + shape: StarBorder.polygon( + sides: 3, + ), + ), + ), + ), + ), + Positioned( + left: 0, + top: 0, + child: Container( + child: Container( + padding: EdgeInsets.only(top: 16), + child: Text( + '주방장', + textAlign: TextAlign.center, + style: TextStyle( + color: Colors.white, + fontSize: 18, + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + height: 0.08, + letterSpacing: -0.36, + ), + ), + ), + width: 88, + height: 33, + decoration: ShapeDecoration( + color: Color(0xFFFF5C39), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + ), + ), + ), + ], ), ), - ], - ), - textAlign: TextAlign.center, + ), + Stack( + alignment: Alignment.center, + children: [ + Stack( + children: [ + Container( + child: Container( + width: + MediaQuery.of(context).size.width * 0.9, + height: 18, + decoration: ShapeDecoration( + color: Color(0xFFE0E0E0), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + )), + Container( + width: + MediaQuery.of(context).size.width * 0.88, + height: 18, + decoration: ShapeDecoration( + color: Color(0xFFFF5C39), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(12), + bottomLeft: Radius.circular(12), + ), + ), + ), + ), + ], + ), + Image.asset("assets/images/progress.png"), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Image.asset("assets/images/progress2.png") + ], + ) + ], + ), + Container( + padding: EdgeInsets.only(top: 5), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text( + 'Lv1.초보', + style: TextStyle( + color: Color(0xFF9E9E9E), + fontSize: 12, + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + height: 0, + letterSpacing: -0.24, + ), + ), + SizedBox(width: + MediaQuery.of(context).size.width * 0.3,), + Text( + 'Lv2.요리사', + textAlign: TextAlign.center, + style: TextStyle( + color: Color(0xFF9E9E9E), + fontSize: 12, + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + height: 0, + letterSpacing: -0.24, + ), + ) + ], + )) + ], + )) + ], + )); + } +} + + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Color(0xFFF4F3F0), + body: SingleChildScrollView( + child: Column( + children: [ + Container( + padding: EdgeInsets.fromLTRB(20, 50, 0, 0), + color: Colors.white, + alignment: Alignment.centerLeft, + child: Text( + '마이페이지', + style: TextStyle( + color: Color(0xFF424242), + fontSize: 24, + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + height: 0, + letterSpacing: -0.48, + ), + )), + Container( + color: Colors.white, + padding: EdgeInsets.fromLTRB(20, 32, 13, 0), + width: MediaQuery.of(context).size.width, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Container( + child: Column( + children: [ + Row( + children: [ + Container( + padding: EdgeInsets.only(right: 5), + child: Text( + customer?.customerName ?? '회원이름', + style: TextStyle( + color: Color(0xFF424242), + fontSize: 22, + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + height: 0, + letterSpacing: -0.44, + ), + )), + Image.asset("assets/images/star.png") + ], + ), + Container( + padding: EdgeInsets.fromLTRB(4, 5, 0, 0), + child: Text( + 'Google 계정 연결', + style: TextStyle( + color: Color(0xFF9E9E9E), + fontSize: 12, + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + height: 0, + letterSpacing: -0.24, + ), + )) + ], + )), + GestureDetector( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ManageMyPageWidget())); + }, + child: Container( + child: Row( + children: [ + Text( + '계정 관리', + textAlign: TextAlign.right, + style: TextStyle( + color: Color(0xFF616161), + fontSize: 14, + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + height: 0, + ), + ), + Icon(Icons.keyboard_arrow_right, + color: Color(0xff616161)) + ], + ))) + ], + )), + Container( + padding: EdgeInsets.only(top: 26), + height: MediaQuery.of(context).size.height * 0.18, + color: Colors.white, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + InkWell( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + ViewChildInfoPageWidget())); + }, + child: Container( + padding: EdgeInsets.only(top: 18), + width: MediaQuery.of(context).size.width * 0.25, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + padding: EdgeInsets.only(bottom: 5), + child: Image.asset("assets/images/baby.png"), + ), + Text( + '아이 정보', + textAlign: TextAlign.center, + style: TextStyle( + color: Color(0xFF212121), + fontSize: 15, + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + height: 0, + letterSpacing: -0.30, + ), + ) + ], + )), ), + Container( + height: MediaQuery.of(context).size.height * + 0.08, // Divider의 높이 설정 + width: 1.0, // Divider의 두께 설정 + color: Color(0xffE0E0E0), // Divider의 색상 설정 + ), + InkWell( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + MyPageMyPostsPageWidget())); + }, + child: Container( + padding: EdgeInsets.only(top: 18), + width: MediaQuery.of(context).size.width * 0.28, + child: Column( + children: [ + Container( + padding: EdgeInsets.only(bottom: 5), + child: Image.asset( + "assets/images/post_write.png"), + ), + Text( + '내 게시글', + textAlign: TextAlign.center, + style: TextStyle( + color: Color(0xFF212121), + fontSize: 15, + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + height: 0, + letterSpacing: -0.30, + ), + ) + ], + ))), + Container( + height: MediaQuery.of(context).size.height * + 0.08, // Divider의 높이 설정 + width: 1.0, // Divider의 두께 설정 + color: Color(0xffE0E0E0), // Divider의 색상 설정 + ), + InkWell( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + MypageMyCommentsPageWidget())); + }, + child: Container( + padding: EdgeInsets.only(top: 10), + width: MediaQuery.of(context).size.width * 0.25, + child: Column( + children: [ + Container( + child: Image.asset( + "assets/images/comment.png", + ), + ), + Text( + '내 댓글', + textAlign: TextAlign.center, + style: TextStyle( + color: Color(0xFF212121), + fontSize: 15, + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + height: 0, + letterSpacing: -0.30, + ), + ) + ], + )), + ) + ], + )), + rankWidget(), + Container( + margin: EdgeInsets.only(right: 20, left: 20), + decoration: ShapeDecoration( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), ), - Container( - padding: EdgeInsets.only(top: 26), - height: MediaQuery.of(context).size.height * 0.18, - color: Colors.white, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - padding: EdgeInsets.only(top: 18), - width: MediaQuery.of(context).size.width * 0.25, - child: Column( - mainAxisAlignment: - MainAxisAlignment.spaceEvenly, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Text( - '받은 좋아요', - textAlign: TextAlign.center, - style: TextStyle( - color: Color(0xFF424242), - fontSize: 13, - fontFamily: 'Pretendard', - fontWeight: FontWeight.w500, - height: 0, - letterSpacing: -0.26, + ), + child: Column( + children: [ + Container( + padding: EdgeInsets.only(top: 25), + child: Text.rich( + TextSpan( + children: [ + TextSpan( + text: '${customer?.customerName}님의 ', + style: TextStyle( + color: Color(0xFF424242), + fontSize: 15, + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + height: 0, + letterSpacing: -0.30, + ), + ), + TextSpan( + text: getRankText(customer?.rank), + style: TextStyle( + color: Color(0xFFFF5C39), + fontSize: 15, + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + height: 0, + letterSpacing: -0.30, + ), + ), + TextSpan( + text: ' 달성률', + style: TextStyle( + color: Color(0xFF424242), + fontSize: 15, + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + height: 0, + letterSpacing: -0.30, + ), + ), + ], + ), + textAlign: TextAlign.center, + ), + ), + Container( + padding: EdgeInsets.only(top: 26), + height: MediaQuery.of(context).size.height * 0.18, + color: Colors.white, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + padding: EdgeInsets.only(top: 18), + width: MediaQuery.of(context).size.width * 0.25, + child: Column( + mainAxisAlignment: + MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + '받은 좋아요', + textAlign: TextAlign.center, + style: TextStyle( + color: Color(0xFF424242), + fontSize: 13, + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + height: 0, + letterSpacing: -0.26, + ), ), - ), - Container( - padding: EdgeInsets.only(bottom: 5), - child: Row( - crossAxisAlignment: - CrossAxisAlignment.center, - mainAxisAlignment: - MainAxisAlignment.center, - children: [ - Container( - padding: EdgeInsets.only(top: 7), - height: 30, - child: Text( - '99', - textAlign: TextAlign.right, - style: TextStyle( - color: Color(0xFFFF5C39), - fontSize: 20, - fontFamily: 'Pretendard', - fontWeight: FontWeight.w600, - height: 0.07, - ), - ), - ), - Image.asset( - "assets/images/slash_my.png", - width: 10, - height: 17), - Container( - padding: - EdgeInsets.only(top: 8), - height: 20, + Container( + padding: EdgeInsets.only(bottom: 5), + child: Row( + crossAxisAlignment: + CrossAxisAlignment.center, + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + Container( + padding: EdgeInsets.only(top: 7), + height: 30, child: Text( - '100', + customer?.myLikes.toString() ?? '', + textAlign: TextAlign.right, style: TextStyle( - color: Color(0xFF757575), - fontSize: 14, + color: Color(0xFFFF5C39), + fontSize: 20, fontFamily: 'Pretendard', fontWeight: FontWeight.w600, - height: 0.11, + height: 0.07, ), - )) - ], - )), - ], - )), - Container( - height: MediaQuery.of(context).size.height * - 0.08, // Divider의 높이 설정 - width: 1.0, // Divider의 두께 설정 - color: Color(0xffE0E0E0), // Divider의 색상 설정 - ), - Container( - padding: EdgeInsets.only(top: 18), - width: MediaQuery.of(context).size.width * 0.25, - child: Column( - mainAxisAlignment: - MainAxisAlignment.spaceEvenly, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Text( - '누른 좋아요', - textAlign: TextAlign.center, - style: TextStyle( - color: Color(0xFF424242), - fontSize: 13, - fontFamily: 'Pretendard', - fontWeight: FontWeight.w500, - height: 0, - letterSpacing: -0.26, - ), - ), - Container( - padding: EdgeInsets.only(bottom: 5), - child: Row( - crossAxisAlignment: - CrossAxisAlignment.center, - mainAxisAlignment: - MainAxisAlignment.center, - children: [ - Container( - padding: EdgeInsets.only(top: 7), - height: 30, - child: Text( - '100', - textAlign: TextAlign.right, - style: TextStyle( - color: Color(0xFFFF5C39), - fontSize: 20, - fontFamily: 'Pretendard', - fontWeight: FontWeight.w600, - height: 0.07, ), ), - ), - Image.asset( - "assets/images/slash_my.png", - width: 10, - height: 17), - Container( - padding: - EdgeInsets.only(top: 8), - height: 20, + Image.asset( + "assets/images/slash_my.png", + width: 10, + height: 17), + Container( + padding: + EdgeInsets.only(top: 8), + height: 20, + child: Text( + customer?.rank == '초보' ? '10' : + customer?.rank == '요리사' ? '50' : + customer?.rank == '주방장' ? '100' : '0', + style: TextStyle( + color: Color(0xFF757575), + fontSize: 14, + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + height: 0.11, + ), + )) + ], + )), + ], + )), + Container( + height: MediaQuery.of(context).size.height * + 0.08, // Divider의 높이 설정 + width: 1.0, // Divider의 두께 설정 + color: Color(0xffE0E0E0), // Divider의 색상 설정 + ), + Container( + padding: EdgeInsets.only(top: 18), + width: MediaQuery.of(context).size.width * 0.25, + child: Column( + mainAxisAlignment: + MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + '작성 댓글', + textAlign: TextAlign.center, + style: TextStyle( + color: Color(0xFF424242), + fontSize: 13, + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + height: 0, + letterSpacing: -0.26, + ), + ), + Container( + padding: EdgeInsets.only(bottom: 5), + child: Row( + crossAxisAlignment: + CrossAxisAlignment.center, + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + Container( + padding: EdgeInsets.only(top: 7), + height: 30, child: Text( - '20', + customer?.myComments.toString() ?? '', + textAlign: TextAlign.right, style: TextStyle( - color: Color(0xFF757575), - fontSize: 14, + color: Color(0xFFFF5C39), + fontSize: 20, fontFamily: 'Pretendard', fontWeight: FontWeight.w600, - height: 0.11, + height: 0.07, ), - )) - ], - )), - ], - )), - Container( - height: MediaQuery.of(context).size.height * - 0.08, // Divider의 높이 설정 - width: 1.0, // Divider의 두께 설정 - color: Color(0xffE0E0E0), // Divider의 색상 설정 - ), - Container( - padding: EdgeInsets.only(top: 18), - width: MediaQuery.of(context).size.width * 0.25, - child: Column( - mainAxisAlignment: - MainAxisAlignment.spaceEvenly, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Text( - '작성 게시물', - textAlign: TextAlign.center, - style: TextStyle( - color: Color(0xFF424242), - fontSize: 13, - fontFamily: 'Pretendard', - fontWeight: FontWeight.w500, - height: 0, - letterSpacing: -0.26, - ), - ), - Container( - padding: EdgeInsets.only(bottom: 5), - child: Row( - crossAxisAlignment: - CrossAxisAlignment.center, - mainAxisAlignment: - MainAxisAlignment.center, - children: [ - Container( - padding: EdgeInsets.only(top: 7), - height: 30, - child: Text( - '9', - textAlign: TextAlign.right, - style: TextStyle( - color: Color(0xFFFF5C39), - fontSize: 20, - fontFamily: 'Pretendard', - fontWeight: FontWeight.w600, - height: 0.07, ), ), - ), - Image.asset( - "assets/images/slash_my.png", - width: 10, - height: 17), - Container( - padding: - EdgeInsets.only(top: 8), - height: 20, + Image.asset( + "assets/images/slash_my.png", + width: 10, + height: 17), + Container( + padding: + EdgeInsets.only(top: 8), + height: 20, + child: Text( + customer?.rank == '초보' ? '10' : + customer?.rank == '요리사' ? '50' : + customer?.rank == '주방장' ? '100' : '0', + style: TextStyle( + color: Color(0xFF757575), + fontSize: 14, + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + height: 0.11, + ), + )) + ], + )), + ], + )), + Container( + height: MediaQuery.of(context).size.height * + 0.08, // Divider의 높이 설정 + width: 1.0, // Divider의 두께 설정 + color: Color(0xffE0E0E0), // Divider의 색상 설정 + ), + Container( + padding: EdgeInsets.only(top: 18), + width: MediaQuery.of(context).size.width * 0.25, + child: Column( + mainAxisAlignment: + MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + '작성 게시물', + textAlign: TextAlign.center, + style: TextStyle( + color: Color(0xFF424242), + fontSize: 13, + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + height: 0, + letterSpacing: -0.26, + ), + ), + Container( + padding: EdgeInsets.only(bottom: 5), + child: Row( + crossAxisAlignment: + CrossAxisAlignment.center, + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + Container( + padding: EdgeInsets.only(top: 7), + height: 30, child: Text( - '10', + customer?.myPosts.toString() ?? '', + textAlign: TextAlign.right, style: TextStyle( - color: Color(0xFF757575), - fontSize: 14, + color: Color(0xFFFF5C39), + fontSize: 20, fontFamily: 'Pretendard', fontWeight: FontWeight.w600, - height: 0.11, + height: 0.07, ), - )) - ], - )), - ], - )), - ], - )), - ], - )) - ], + ), + ), + Image.asset( + "assets/images/slash_my.png", + width: 10, + height: 17), + Container( + padding: + EdgeInsets.only(top: 8), + height: 20, + child: Text( + customer?.rank == '초보' ? '10' : + customer?.rank == '요리사' ? '50' : + customer?.rank == '주방장' ? '100' : '0', + style: TextStyle( + color: Color(0xFF757575), + fontSize: 14, + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + height: 0.11, + ), + )) + ], + )), + ], + )), + ], + )), + ], + )) + ], + ), )); } } diff --git a/babymeal/lib/pages/recommend/RecomChooseMaterialPage.dart b/babymeal/lib/pages/recommend/RecomChooseMaterialPage.dart index a9ea934..7ff40d7 100644 --- a/babymeal/lib/pages/recommend/RecomChooseMaterialPage.dart +++ b/babymeal/lib/pages/recommend/RecomChooseMaterialPage.dart @@ -1,8 +1,15 @@ import 'package:babymeal/pages/recommend/SelectKeywordPage.dart'; +import 'package:babymeal/services/FridgeContentService.dart'; import 'package:flutter/material.dart'; +import 'dart:convert'; +import 'package:http/http.dart' as http; +import 'package:shared_preferences/shared_preferences.dart'; class RecomChooseMaterialPageWidget extends StatefulWidget { - const RecomChooseMaterialPageWidget({super.key}); + final String selectedOption; + + const RecomChooseMaterialPageWidget({Key? key, required this.selectedOption}) : super(key: key); + @override State createState() => @@ -13,17 +20,7 @@ class _RecomChooseMaterialPageWidgetState extends State { final scaffoldKey = GlobalKey(); - List materialList = [ - "체다치즈", - "고등어", - "달걀", - "통밀 식빵", - "브로콜리", - "양파", - "당근", - "우유", - "토마토" - ]; + List FridgeContentsList = []; List imageList = [ "assets/images/cheese.png", @@ -47,6 +44,7 @@ class _RecomChooseMaterialPageWidgetState super.initState(); fadeInQuestion(); fadeInOption(); + loadUserTokenAndFetchFridgeContents(); } fadeInQuestion() { @@ -76,10 +74,19 @@ class _RecomChooseMaterialPageWidgetState elevation: 0, backgroundColor: Color(0xFFFF5C39), onPressed: () { + List selectedMaterials = []; + for (int i = 0; i < isSelected.length; i++) { + if (isSelected[i]) { + selectedMaterials.add(FridgeContentsList[i].ingredients); + } + } Navigator.push( context, MaterialPageRoute( - builder: (context) => SelectKeywordPageWidget())); + builder: (context) => SelectKeywordPageWidget( + selectedOption: widget.selectedOption, + selectedMaterials: selectedMaterials + ))); }, label: Container( width: MediaQuery.of(context).size.width * 0.88, @@ -224,7 +231,7 @@ class _RecomChooseMaterialPageWidgetState childAspectRatio: 4, mainAxisSpacing: 8.0, ), - itemCount: 9, // 아이템 개수 + itemCount: FridgeContentsList.length, // 아이템 개수 itemBuilder: (BuildContext context, int index) { return AnimatedOpacity( opacity: opacity2, @@ -246,14 +253,15 @@ class _RecomChooseMaterialPageWidgetState padding: EdgeInsets.fromLTRB(10, 0, 0, 0), child: Row(children: [ Padding( - padding: - EdgeInsets.fromLTRB(0, 0, 10, 0), - child: Image.asset(imageList[index]), + padding: EdgeInsets.fromLTRB(0, 0, 10, 0), + child: FridgeContentsList[index].emoticon.isNotEmpty + ? Image.asset(FridgeContentsList[index].emoticon) + : SizedBox.shrink(), // emoticon이 빈 문자열이면 아무 것도 표시하지 않음 ), RichText( textAlign: TextAlign.left, text: TextSpan( - text: materialList[index], + text: FridgeContentsList[index].ingredients, style: isSelected[index] ? TextStyle( color: Color(0xFFFF5C39), @@ -280,7 +288,7 @@ class _RecomChooseMaterialPageWidgetState shape: RoundedRectangleBorder( side: BorderSide( width: 2, - color: Color(0xFFFF5C39)), + color: Color.fromARGB(255, 141, 74, 59)), borderRadius: BorderRadius.circular(12), ), @@ -304,4 +312,61 @@ class _RecomChooseMaterialPageWidgetState ), ); } + + Future loadUserTokenAndFetchFridgeContents() async { + final prefs = await SharedPreferences.getInstance(); + final String userToken = prefs.getString('accessToken') ?? ''; // accessToken 키로 저장된 토큰을 불러옵니다. 토큰이 없으면 빈 문자열을 반환합니다. + + print('Loaded user token: $userToken'); + + if (userToken.isNotEmpty) { + fetchFridgeContents(userToken).then((contents) { + if (mounted) { // Flutter 위젯의 상태가 여전히 활성 상태인지 확인 + setState(() { + // materialList의 타입이 List로 변경되었다고 가정 + FridgeContentsList = contents; // FridgeContent 객체의 리스트를 UI에 반영 + }); + } + }).catchError((error) { + print('Error fetching fridge contents: $error'); + }); + } else { + print("No user token found."); + // 토큰이 없을 경우의 처리 로직을 여기에 추가할 수 있습니다. + } +} + + Future> fetchFridgeContents(String token) async { + final baseUrl = 'http://ec2-43-200-210-159.ap-northeast-2.compute.amazonaws.com:8080'; + final url = Uri.parse('$baseUrl/fridge/customer'); + + try { + final response = await http.get( + url, + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', // 여기서 인증 토큰을 전달 + }, + ); + + if (response.statusCode == 200) { + final String responseBody = utf8.decode(response.bodyBytes); + final Map decodedResponse = jsonDecode(responseBody); + + // 'data' 키에 해당하는 값을 List으로 추출합니다. + final List fridgeContents = decodedResponse['data']; + + // FridgeContent 객체의 리스트로 변환합니다. + List contents = fridgeContents.map((item) => FridgeContent.fromJson(item)).toList(); + + return contents; + } else { + throw Exception('Failed to load fridge contents'); + } + } catch (e) { + throw Exception('Failed to load fridge contents: $e'); + } +} + + } diff --git a/babymeal/lib/pages/recommend/RecomChooseMealPage.dart b/babymeal/lib/pages/recommend/RecomChooseMealPage.dart index 7d3bbc0..6fdae4a 100644 --- a/babymeal/lib/pages/recommend/RecomChooseMealPage.dart +++ b/babymeal/lib/pages/recommend/RecomChooseMealPage.dart @@ -65,11 +65,13 @@ class _RecomChooseMealPageWidgetState extends State { onPressed: (isSelected[0] == true && !isSelected[1] == true) || (!isSelected[0] == true && isSelected[1] == true) ? () { + int selectedOptionIndex = isSelected.indexOf(true); + String selectedValue = mealordessert[selectedOptionIndex]; Navigator.push( context, MaterialPageRoute( builder: (context) => - RecomChooseMaterialPageWidget())); + RecomChooseMaterialPageWidget(selectedOption: selectedValue))); } : () {}, label: Container( diff --git a/babymeal/lib/pages/recommend/SelectKeywordPage.dart b/babymeal/lib/pages/recommend/SelectKeywordPage.dart index 6ab6ab1..b046b59 100644 --- a/babymeal/lib/pages/recommend/SelectKeywordPage.dart +++ b/babymeal/lib/pages/recommend/SelectKeywordPage.dart @@ -3,7 +3,10 @@ import 'package:babymeal/pages/recommend/WaitRecipesPage.dart'; import 'package:flutter/material.dart'; class SelectKeywordPageWidget extends StatefulWidget { - const SelectKeywordPageWidget({Key? key}) : super(key: key); + final String selectedOption; + final List selectedMaterials; + + const SelectKeywordPageWidget({Key? key, required this.selectedOption, required this.selectedMaterials}) : super(key: key); @override _SelectKeywordPageWidgetState createState() => @@ -13,8 +16,8 @@ class SelectKeywordPageWidget extends StatefulWidget { class _SelectKeywordPageWidgetState extends State { final scaffoldKey = GlobalKey(); - List isSelected = List.generate(nutKeywords.length, (index) => false); - + List isSelected = List.generate(nutKeywords.length + genKeywords.length, (index) => false); + double opacity1 = 0.0; double opacity2 = 0.0; @@ -57,10 +60,27 @@ class _SelectKeywordPageWidgetState extends State { elevation: 0, backgroundColor: Color(0xFFFF5C39), onPressed: () { + List selectedKeywords = []; + for (int i = 0; i < isSelected.length; i++) { + if (isSelected[i]) { + selectedKeywords.add(nutKeywords[i]); + } + } + + for (int i = 0; i < genKeywords.length; i++) { + if (isSelected[i + nutKeywords.length]) { + selectedKeywords.add(genKeywords[i]); + } + } + Navigator.push( context, MaterialPageRoute( - builder: (context) => WaitRecipesPageWidget())); + builder: (context) => WaitRecipesPageWidget( + selectedOption: widget.selectedOption, + selectedMaterials: widget.selectedMaterials, + selectedKeywords: selectedKeywords, + ))); }, label: Container( width: MediaQuery.of(context).size.width * 0.88, @@ -358,16 +378,18 @@ class _SelectKeywordPageWidgetState extends State { Container( margin: EdgeInsets.fromLTRB( 0, 11, 20, 11), + child: FittedBox( + fit: BoxFit.scaleDown, // 텍스트가 컨테이너에 맞도록 크기 조정 child: Text( '${genKeywords[index]}', style: TextStyle( color: Color(0xFF212121), - fontSize: 15, + fontSize: 15, // 원하는 최대 글자 크기 설정 fontFamily: 'Pretendard', fontWeight: FontWeight.w600, - height: 0, ), ), + ), ) ], ), diff --git a/babymeal/lib/pages/recommend/ShowDetailFridgeRecipePage.dart b/babymeal/lib/pages/recommend/ShowDetailFridgeRecipePage.dart new file mode 100644 index 0000000..cddc053 --- /dev/null +++ b/babymeal/lib/pages/recommend/ShowDetailFridgeRecipePage.dart @@ -0,0 +1,459 @@ +import 'package:babymeal/model/FridgeRecipe.dart'; +import 'package:babymeal/model/RecipeDetailModel.dart'; +import 'package:flutter/material.dart'; +import 'dart:convert'; +import 'package:http/http.dart' as http; +import 'package:babymeal/model/RecipeModel.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'dart:convert' show utf8; + +class ShowDetailFridgeRecipePageWidget extends StatefulWidget { + final List selectedMaterials; + final List selectedKeywords; + final int? simpleDietId; + final List fridgeRecipes; + final Function(int, bool) onHeartChanged; + + const ShowDetailFridgeRecipePageWidget({Key? key, required this.selectedMaterials, required this.selectedKeywords, this.simpleDietId, required this.fridgeRecipes, required this.onHeartChanged}) : super(key: key); + + @override + State createState() => _ShowDetailRecipePageWidgetState(); +} + +class _ShowDetailRecipePageWidgetState extends State { + bool isScrabed = false; + bool isLoading = true; // 로딩 상태 관리 + RecipeDetail? recipeDetails; + + @override + void initState() { + super.initState(); + loadTokenAndFetchDetails(); + } + + void loadTokenAndFetchDetails() async { + final SharedPreferences prefs = await SharedPreferences.getInstance(); + final String? token = prefs.getString('accessToken'); + + String fridge = widget.selectedMaterials.join(','); // selectedMaterials를 콤마로 구분된 문자열로 변환 + String keyword = widget.selectedKeywords.join(','); + if (token != null) { + fetchRecipeDetails(token, fridge, keyword); + } else { + print('No token found'); + // 토큰이 없는 경우의 처리를 여기에 추가하세요. + } +} + + Future fetchRecipeDetails(String token, String fridge, String keyword) async { + print(widget.simpleDietId); + var url = Uri.parse('http://ec2-43-200-210-159.ap-northeast-2.compute.amazonaws.com:8080/diet/detail?simpleDietId=${widget.simpleDietId}'); + // print(url); + var body = jsonEncode({ + 'fridge': fridge, + 'keyword': keyword, + }); + + try { + var response = await http.post( + url, + body: body, + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + ); + + if (response.statusCode == 200) { + setState(() { + final responseBody = json.decode(utf8.decode(response.bodyBytes)); + recipeDetails = RecipeDetail.fromJson(responseBody['data']); + isLoading = false; + }); + } else { + // 요청 실패 처리 + print('Failed to load recipe details'); + } + } catch (e) { + print('Error fetching recipe details: $e'); + } + } + + void toggleScrab() async { + final String simpleDietId = widget.simpleDietId?.toString() ?? "기본값";; + print(simpleDietId); + final String url = 'http://ec2-43-200-210-159.ap-northeast-2.compute.amazonaws.com:8080/diet/press?simpleDietId=$simpleDietId'; + final SharedPreferences prefs = await SharedPreferences.getInstance(); + final String? userToken = prefs.getString('accessToken'); + + if (userToken == null) { + print('No user token found'); + return; + } + + try { + final response = await http.put(Uri.parse(url), headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $userToken', + }); + + if (response.statusCode == 200) { + final jsonResponse = jsonDecode(response.body); + final bool heart = jsonResponse['data']['heart']; + + setState(() { + recipeDetails?.heart = heart; // 서버 응답에 따라 isScrabed 상태 업데이트 + print("isScrabed updated to: ${recipeDetails?.heart}"); + }); + + if(widget.simpleDietId != null) { // simpleDietId가 null이 아닌 경우에만 콜백 호출 + widget.onHeartChanged(widget.simpleDietId!, heart); + } + + } else { + print('Failed to change scrab status'); + } + } catch (e) { + print('Exception occurred: $e'); + } +} + + @override + Widget build(BuildContext context) { + + return Scaffold( + backgroundColor: Color(0xFFF4F3F0), + appBar: AppBar( + backgroundColor: Color(0xFFF4F3F0), + leading: IconButton( + onPressed: () { + setState(() { + // 이전 페이지로 돌아가는 동안 변경된 Heart 정보를 반영 + widget.fridgeRecipes.forEach((recipe) { + // 변경된 Heart 정보가 반영된 경우에만 각 레시피의 정보를 업데이트합니다. + if (recipe.heart != null) { + // print(recipe.simpleDietId); + int index = widget.fridgeRecipes.indexWhere((element) => element.simpleDietId == recipe.simpleDietId); + // print(index); + // print('////'); + if (index != -1 && widget.fridgeRecipes[index].simpleDietId == widget.simpleDietId) { + // print('*****'); + // print(widget.simpleDietId); + // print('^^^^^^^'); + print(widget.fridgeRecipes[index].heart); + print(recipeDetails?.heart); + widget.fridgeRecipes[index].heart = recipeDetails?.heart; + print(widget.fridgeRecipes[index].heart); + } + } + }); + }); + // setState(() {}); + Navigator.pop(context); + }, + color: Colors.transparent, + padding: EdgeInsets.fromLTRB(20, 0, 0, 0), + icon: Icon( + Icons.arrow_back_ios, + color: Color(0xFF949494), + size: 24, + ), + ), + ), + body: isLoading + ? Center(child:CircularProgressIndicator()) + : SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.fromLTRB(20, 15, 20, 10), + child:Text( + recipeDetails?.dietName ?? '기본 레시피 이름', + style: TextStyle( + fontSize: 24, + fontWeight: FontWeight.bold, + fontFamily: 'GowunBatang', + ), + ), + ), + Padding( + padding: EdgeInsets.fromLTRB(20, 15, 20, 10), + child: Text( + recipeDetails?.description ?? '기본 레시피 설명', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + fontFamily: 'Pretendard', + ), + ), + ), + Row( + children: [ + Padding( + padding: EdgeInsets.fromLTRB(20, 15, 1, 15), + child: Container( + decoration: BoxDecoration( + color: Color(0xFFDEFCE9), + borderRadius: BorderRadius.circular(18), + ), + padding: EdgeInsets.fromLTRB(10, 3, 10, 3), + child: Text( + recipeDetails?.difficulty ?? '기본 레시피 난이도', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w400, + fontFamily: 'Pretendard', + color: Color(0xFF29CC5A), + ), + ), + ),), + SizedBox(width: 5), + Padding( + padding: EdgeInsets.fromLTRB(1, 15, 1, 15), + child: Container( + padding: EdgeInsets.fromLTRB(10, 3, 10, 3), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(18), + color: Color(0xFFFFFFFF), + ), + child: Text( + "${recipeDetails?.time?.toString() ?? '기본 레시피 시간'}분", + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w400, + fontFamily: 'Pretendard', + color: Color(0xFF616161), + ), + ), + ), + ), + SizedBox(width: 5), + Padding( + padding: EdgeInsets.fromLTRB(1, 15, 5, 15), + child: Container( + padding: EdgeInsets.fromLTRB(10, 3, 10, 3), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(18), + color: Color(0xFFFFFFFF), + ), + child: Row( + children: [ + Padding( + padding: EdgeInsets.fromLTRB(2, 2, 2, 2), + child: Icon( + Icons.tag, + color: Color(0xFF9E9E9E), + size: 16, + ), + ), + Text( + widget?.selectedKeywords.toString() ?? ' ', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w400, + fontFamily: 'Pretendard', + color: Color(0xFF616161), + ), + ), + ], + ), + ), + ), + ], + ), + Stack( + children: [ + // Container( + // color: Color(0xFFF4F3F0), + // child: Row( + // children: [ + // Padding( + // padding: EdgeInsets.fromLTRB(20, 15, 1, 15), + // child: Container( + // decoration: BoxDecoration( + // color: Color(0xFFDEFCE9), + // borderRadius: BorderRadius.circular(18), + // ), + // padding: EdgeInsets.fromLTRB(10, 3, 10, 3), + // child: Text( + // '간단해요', + // textAlign: TextAlign.center, + // style: TextStyle( + // fontSize: 14, + // fontWeight: FontWeight.w400, + // fontFamily: 'Pretendard', + // color: Color(0xFF29CC5A), + // ), + // ), + // ), + // ), + // Padding( + // padding: EdgeInsets.fromLTRB(1, 15, 1, 15), + // child: Container( + // padding: EdgeInsets.fromLTRB(10, 3, 10, 3), + // decoration: BoxDecoration( + // borderRadius: BorderRadius.circular(18), + // color: Color(0xFFFFFFFF), + // ), + // child: Text( + // '20분 소요', + // textAlign: TextAlign.center, + // style: TextStyle( + // fontSize: 14, + // fontWeight: FontWeight.w400, + // fontFamily: 'Pretendard', + // color: Color(0xFF616161), + // ), + // ), + // ), + // ), + // SizedBox(width: 5), + // Padding( + // padding: EdgeInsets.fromLTRB(1, 15, 5, 15), + // child: Container( + // padding: EdgeInsets.fromLTRB(10, 3, 10, 3), + // decoration: BoxDecoration( + // borderRadius: BorderRadius.circular(18), + // color: Color(0xFFFFFFFF), + // ), + // child: Row( + // children: [ + // Padding( + // padding: EdgeInsets.fromLTRB(2, 2, 2, 2), + // child: Icon( + // Icons.tag, + // color: Color(0xFF9E9E9E), + // size: 16, + // ), + // ), + // Text( + // '비타민이 풍부한', + // textAlign: TextAlign.center, + // style: TextStyle( + // fontSize: 14, + // fontWeight: FontWeight.w400, + // fontFamily: 'Pretendard', + // color: Color(0xFF616161), + // ), + // ), + // ], + // ), + // ), + // ), + // ], + // ), + // ), + Container( + color: Colors.white, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.fromLTRB(20, 20, 20, 0), + child: Text( + '재료', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + fontFamily: 'Pretendard', + color: Color(0xFF424242), + ), + ), + ), + Padding( + padding: EdgeInsets.fromLTRB(20, 20, 20, 20), + child: Text( + recipeDetails?.ingredients ?? '기본 레시피 재료', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + fontFamily: 'Pretendard', + color: Color(0xFF212121), + ), + ), + ), + ], + ), + ), + Positioned( + top: -18, + left: 325, + //TO DO + //Icon Button 완전히 보이기 + child: Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Colors.white, + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.15), + blurRadius: 8, + spreadRadius: 1, + ), + ], + ), + width: 45, + height: 45, + child: IconButton( + icon: Icon( + Icons.favorite, + color: recipeDetails != null && recipeDetails!.heart == true ? Color(0xFFFF5C39) : Color(0xFFDDDDDD), + ), + onPressed: () { + setState(() { + toggleScrab(); + }); + }, + ), + ), + ), + ], + ), + Container( + color: Color(0xFFF4F3F0), + height: 10, + width: double.infinity, + ), + Container( + color: Colors.white, + child: Padding( + padding: EdgeInsets.fromLTRB(20, 20, 0, 10), + child:Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '요리 순서', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + fontFamily: 'Pretendard', + color: Color(0xFF424242), + ), + ), + if (recipeDetails?.recipe != null) + ...recipeDetails!.recipe!.split('\n').map((step) => Padding( + padding: EdgeInsets.only(top: 8.0), + child: Text( + step, + style: TextStyle( + fontSize: 16, + fontFamily: 'Pretendard', + ), + ), + )).toList(), + ], + ) + ), + ), + ] + ), + )); + } +} \ No newline at end of file diff --git a/babymeal/lib/pages/recommend/ShowDetailMainFridgeRecipe.dart b/babymeal/lib/pages/recommend/ShowDetailMainFridgeRecipe.dart new file mode 100644 index 0000000..0fc1e86 --- /dev/null +++ b/babymeal/lib/pages/recommend/ShowDetailMainFridgeRecipe.dart @@ -0,0 +1,442 @@ +import 'package:babymeal/model/FridgeRecipe.dart'; +import 'package:babymeal/model/RecipeDetailModel.dart'; +import 'package:flutter/material.dart'; +import 'dart:convert'; +import 'package:http/http.dart' as http; +import 'package:babymeal/model/RecipeModel.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'dart:convert' show utf8; + +class ShowDetailMainFridgeRecipePageWidget extends StatefulWidget { + final int? simpleDietId; + final List fridgeRecipes; + final Function(int, bool) onHeartChanged; + + const ShowDetailMainFridgeRecipePageWidget({Key? key, this.simpleDietId, required this.fridgeRecipes, required this.onHeartChanged}) : super(key: key); + + @override + State createState() => _ShowDetailRecipePageWidgetState(); +} + +class _ShowDetailRecipePageWidgetState extends State { + bool isScrabed = false; + bool isLoading = true; // 로딩 상태 관리 + RecipeDetail? recipeDetails; + + @override + void initState() { + super.initState(); + loadTokenAndFetchDetails(); + } + + void loadTokenAndFetchDetails() async { + final SharedPreferences prefs = await SharedPreferences.getInstance(); + final String? token = prefs.getString('accessToken'); + + if (token != null) { + fetchRecipeDetails(token); + } else { + print('No token found'); + // 토큰이 없는 경우의 처리를 여기에 추가하세요. + } +} + + Future fetchRecipeDetails(String token) async { + print(widget.simpleDietId); + var url = Uri.parse('http://ec2-43-200-210-159.ap-northeast-2.compute.amazonaws.com:8080/diet/fridge/detail?simpleDietId=${widget.simpleDietId}'); + // print(url); + + try { + var response = await http.post( + url, + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + ); + + if (response.statusCode == 200) { + setState(() { + final responseBody = json.decode(utf8.decode(response.bodyBytes)); + recipeDetails = RecipeDetail.fromJson(responseBody['data']); + isLoading = false; + }); + } else { + // 요청 실패 처리 + print('Failed to load recipe details'); + } + } catch (e) { + print('Error fetching recipe details: $e'); + } + } + + void toggleScrab() async { + final String simpleDietId = widget.simpleDietId?.toString() ?? "기본값";; + print(simpleDietId); + final String url = 'http://ec2-43-200-210-159.ap-northeast-2.compute.amazonaws.com:8080/diet/press?simpleDietId=$simpleDietId'; + final SharedPreferences prefs = await SharedPreferences.getInstance(); + final String? userToken = prefs.getString('accessToken'); + + if (userToken == null) { + print('No user token found'); + return; + } + + try { + final response = await http.put(Uri.parse(url), headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $userToken', + }); + + if (response.statusCode == 200) { + final jsonResponse = jsonDecode(response.body); + final bool heart = jsonResponse['data']['heart']; + + setState(() { + recipeDetails?.heart = heart; // 서버 응답에 따라 isScrabed 상태 업데이트 + print("isScrabed updated to: ${recipeDetails?.heart}"); + }); + + if(widget.simpleDietId != null) { // simpleDietId가 null이 아닌 경우에만 콜백 호출 + widget.onHeartChanged(widget.simpleDietId!, heart); + } + + } else { + print('Failed to change scrab status'); + } + } catch (e) { + print('Exception occurred: $e'); + } +} + + @override + Widget build(BuildContext context) { + + return Scaffold( + backgroundColor: Color(0xFFF4F3F0), + appBar: AppBar( + backgroundColor: Color(0xFFF4F3F0), + leading: IconButton( + onPressed: () { + setState(() { + // 이전 페이지로 돌아가는 동안 변경된 Heart 정보를 반영 + widget.fridgeRecipes.forEach((recipe) { + // 변경된 Heart 정보가 반영된 경우에만 각 레시피의 정보를 업데이트합니다. + if (recipe.heart != null) { + // print(recipe.simpleDietId); + int index = widget.fridgeRecipes.indexWhere((element) => element.simpleDietId == recipe.simpleDietId); + // print(index); + // print('////'); + if (index != -1 && widget.fridgeRecipes[index].simpleDietId == widget.simpleDietId) { + // print('*****'); + // print(widget.simpleDietId); + // print('^^^^^^^'); + print(widget.fridgeRecipes[index].heart); + print(recipeDetails?.heart); + widget.fridgeRecipes[index].heart = recipeDetails?.heart; + print(widget.fridgeRecipes[index].heart); + } + } + }); + }); + // setState(() {}); + Navigator.pop(context); + }, + color: Colors.transparent, + padding: EdgeInsets.fromLTRB(20, 0, 0, 0), + icon: Icon( + Icons.arrow_back_ios, + color: Color(0xFF949494), + size: 24, + ), + ), + ), + body: isLoading + ? Center(child:CircularProgressIndicator()) + : SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.fromLTRB(20, 15, 20, 10), + child:Text( + recipeDetails?.dietName ?? '기본 레시피 이름', + style: TextStyle( + fontSize: 24, + fontWeight: FontWeight.bold, + fontFamily: 'GowunBatang', + ), + ), + ), + Padding( + padding: EdgeInsets.fromLTRB(20, 15, 20, 10), + child: Text( + recipeDetails?.description ?? '기본 레시피 설명', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + fontFamily: 'Pretendard', + ), + ), + ), + Row( + children: [ + Padding( + padding: EdgeInsets.fromLTRB(20, 15, 1, 15), + child: Container( + decoration: BoxDecoration( + color: Color(0xFFDEFCE9), + borderRadius: BorderRadius.circular(18), + ), + padding: EdgeInsets.fromLTRB(10, 3, 10, 3), + child: Text( + recipeDetails?.difficulty ?? '기본 레시피 난이도', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w400, + fontFamily: 'Pretendard', + color: Color(0xFF29CC5A), + ), + ), + ),), + SizedBox(width: 5), + Padding( + padding: EdgeInsets.fromLTRB(1, 15, 1, 15), + child: Container( + padding: EdgeInsets.fromLTRB(10, 3, 10, 3), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(18), + color: Color(0xFFFFFFFF), + ), + child: Text( + "${recipeDetails?.time?.toString() ?? '기본 레시피 시간'}분", + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w400, + fontFamily: 'Pretendard', + color: Color(0xFF616161), + ), + ), + ), + ), + SizedBox(width: 5), + Padding( + padding: EdgeInsets.fromLTRB(1, 15, 5, 15), + child: Container( + padding: EdgeInsets.fromLTRB(10, 3, 10, 3), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(18), + color: Color(0xFFFFFFFF), + ), + child: Row( + children: [ + Padding( + padding: EdgeInsets.fromLTRB(2, 2, 2, 2), + child: Icon( + Icons.tag, + color: Color(0xFF9E9E9E), + size: 16, + ), + ), + + ], + ), + ), + ), + ], + ), + Stack( + children: [ + // Container( + // color: Color(0xFFF4F3F0), + // child: Row( + // children: [ + // Padding( + // padding: EdgeInsets.fromLTRB(20, 15, 1, 15), + // child: Container( + // decoration: BoxDecoration( + // color: Color(0xFFDEFCE9), + // borderRadius: BorderRadius.circular(18), + // ), + // padding: EdgeInsets.fromLTRB(10, 3, 10, 3), + // child: Text( + // '간단해요', + // textAlign: TextAlign.center, + // style: TextStyle( + // fontSize: 14, + // fontWeight: FontWeight.w400, + // fontFamily: 'Pretendard', + // color: Color(0xFF29CC5A), + // ), + // ), + // ), + // ), + // Padding( + // padding: EdgeInsets.fromLTRB(1, 15, 1, 15), + // child: Container( + // padding: EdgeInsets.fromLTRB(10, 3, 10, 3), + // decoration: BoxDecoration( + // borderRadius: BorderRadius.circular(18), + // color: Color(0xFFFFFFFF), + // ), + // child: Text( + // '20분 소요', + // textAlign: TextAlign.center, + // style: TextStyle( + // fontSize: 14, + // fontWeight: FontWeight.w400, + // fontFamily: 'Pretendard', + // color: Color(0xFF616161), + // ), + // ), + // ), + // ), + // SizedBox(width: 5), + // Padding( + // padding: EdgeInsets.fromLTRB(1, 15, 5, 15), + // child: Container( + // padding: EdgeInsets.fromLTRB(10, 3, 10, 3), + // decoration: BoxDecoration( + // borderRadius: BorderRadius.circular(18), + // color: Color(0xFFFFFFFF), + // ), + // child: Row( + // children: [ + // Padding( + // padding: EdgeInsets.fromLTRB(2, 2, 2, 2), + // child: Icon( + // Icons.tag, + // color: Color(0xFF9E9E9E), + // size: 16, + // ), + // ), + // Text( + // '비타민이 풍부한', + // textAlign: TextAlign.center, + // style: TextStyle( + // fontSize: 14, + // fontWeight: FontWeight.w400, + // fontFamily: 'Pretendard', + // color: Color(0xFF616161), + // ), + // ), + // ], + // ), + // ), + // ), + // ], + // ), + // ), + Container( + color: Colors.white, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.fromLTRB(20, 20, 20, 0), + child: Text( + '재료', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + fontFamily: 'Pretendard', + color: Color(0xFF424242), + ), + ), + ), + Padding( + padding: EdgeInsets.fromLTRB(20, 20, 20, 20), + child: Text( + recipeDetails?.ingredients ?? '기본 레시피 재료', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + fontFamily: 'Pretendard', + color: Color(0xFF212121), + ), + ), + ), + ], + ), + ), + Positioned( + top: -18, + left: 325, + //TO DO + //Icon Button 완전히 보이기 + child: Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Colors.white, + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.15), + blurRadius: 8, + spreadRadius: 1, + ), + ], + ), + width: 45, + height: 45, + child: IconButton( + icon: Icon( + Icons.favorite, + color: recipeDetails != null && recipeDetails!.heart == true ? Color(0xFFFF5C39) : Color(0xFFDDDDDD), + ), + onPressed: () { + setState(() { + toggleScrab(); + }); + }, + ), + ), + ), + ], + ), + Container( + color: Color(0xFFF4F3F0), + height: 10, + width: double.infinity, + ), + Container( + color: Colors.white, + child: Padding( + padding: EdgeInsets.fromLTRB(20, 20, 0, 10), + child:Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '요리 순서', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + fontFamily: 'Pretendard', + color: Color(0xFF424242), + ), + ), + if (recipeDetails?.recipe != null) + ...recipeDetails!.recipe!.split('\n').map((step) => Padding( + padding: EdgeInsets.only(top: 8.0), + child: Text( + step, + style: TextStyle( + fontSize: 16, + fontFamily: 'Pretendard', + ), + ), + )).toList(), + ], + ) + ), + ), + ] + ), + )); + } +} + diff --git a/babymeal/lib/pages/recommend/ShowDetailRecipePage.dart b/babymeal/lib/pages/recommend/ShowDetailRecipePage.dart index c185f78..3101903 100644 --- a/babymeal/lib/pages/recommend/ShowDetailRecipePage.dart +++ b/babymeal/lib/pages/recommend/ShowDetailRecipePage.dart @@ -1,7 +1,19 @@ +import 'package:babymeal/model/RecipeDetailModel.dart'; import 'package:flutter/material.dart'; +import 'dart:convert'; +import 'package:http/http.dart' as http; +import 'package:babymeal/model/RecipeModel.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'dart:convert' show utf8; class ShowDetailRecipePageWidget extends StatefulWidget { - const ShowDetailRecipePageWidget({Key? key}) : super(key: key); + final List selectedMaterials; + final List selectedKeywords; + final int? simpleDietId; + final List recipes; + final Function(int, bool) onHeartChanged; + + const ShowDetailRecipePageWidget({Key? key, required this.selectedMaterials, required this.selectedKeywords, this.simpleDietId, required this.recipes, required this.onHeartChanged}) : super(key: key); @override State createState() => _ShowDetailRecipePageWidgetState(); @@ -9,18 +21,101 @@ class ShowDetailRecipePageWidget extends StatefulWidget { class _ShowDetailRecipePageWidgetState extends State { bool isScrabed = false; - List> cookorder = [ - {1 : '볼에 계란 2개를 깨뜨린 후 소금과 후추로 간을 해줍니다.\n잘 풀어서 섞습니다.'}, - {2 : '토스터나 팬에 토스트 빵을 약간 바삭하게 구워줍니다.'}, - {3 : '중불에 팬을 올린 후 버터를 녹입니다. 버터가 녹으면 계란물을 부어줍니다. 중불에서 부드럽게 계란을 젓습니다.계란이 반죽 상태가 되면 불을 끄고 팬에서 떼어줍니다.'}, - {4 : '햄이나 베이컨을 팬에 약간 구워 주고, 원하는 야채 (예: 토마토나 양상추)를 준비합니다.'}, - ]; + bool isLoading = true; // 로딩 상태 관리 + RecipeDetail? recipeDetails; @override void initState() { super.initState(); + loadTokenAndFetchDetails(); + } + + void loadTokenAndFetchDetails() async { + final SharedPreferences prefs = await SharedPreferences.getInstance(); + final String? token = prefs.getString('accessToken'); + + String fridge = widget.selectedMaterials.join(','); // selectedMaterials를 콤마로 구분된 문자열로 변환 + String keyword = widget.selectedKeywords.join(','); + if (token != null) { + fetchRecipeDetails(token, fridge, keyword); + } else { + print('No token found'); + // 토큰이 없는 경우의 처리를 여기에 추가하세요. + } +} + + Future fetchRecipeDetails(String token, String fridge, String keyword) async { + print(widget.simpleDietId); + var url = Uri.parse('http://ec2-43-200-210-159.ap-northeast-2.compute.amazonaws.com:8080/diet/detail?simpleDietId=${widget.simpleDietId}'); + // print(url); + var body = jsonEncode({ + 'fridge': fridge, + 'keyword': keyword, + }); + + try { + var response = await http.post( + url, + body: body, + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + ); + + if (response.statusCode == 200) { + setState(() { + final responseBody = json.decode(utf8.decode(response.bodyBytes)); + recipeDetails = RecipeDetail.fromJson(responseBody['data']); + isLoading = false; + }); + } else { + // 요청 실패 처리 + print('Failed to load recipe details'); + } + } catch (e) { + print('Error fetching recipe details: $e'); + } } + void toggleScrab() async { + final String simpleDietId = widget.simpleDietId?.toString() ?? "기본값";; + print(simpleDietId); + final String url = 'http://ec2-43-200-210-159.ap-northeast-2.compute.amazonaws.com:8080/diet/press?simpleDietId=$simpleDietId'; + final SharedPreferences prefs = await SharedPreferences.getInstance(); + final String? userToken = prefs.getString('accessToken'); + + if (userToken == null) { + print('No user token found'); + return; + } + + try { + final response = await http.put(Uri.parse(url), headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $userToken', + }); + + if (response.statusCode == 200) { + final jsonResponse = jsonDecode(response.body); + final bool heart = jsonResponse['data']['heart']; + + setState(() { + recipeDetails?.heart = heart; // 서버 응답에 따라 isScrabed 상태 업데이트 + print("isScrabed updated to: ${recipeDetails?.heart}"); + }); + + if(widget.simpleDietId != null) { // simpleDietId가 null이 아닌 경우에만 콜백 호출 + widget.onHeartChanged(widget.simpleDietId!, heart); + } + + } else { + print('Failed to change scrab status'); + } + } catch (e) { + print('Exception occurred: $e'); + } +} @override Widget build(BuildContext context) { @@ -30,7 +125,29 @@ class _ShowDetailRecipePageWidgetState extends State appBar: AppBar( backgroundColor: Color(0xFFF4F3F0), leading: IconButton( - onPressed: ()async{ + onPressed: () { + setState(() { + // 이전 페이지로 돌아가는 동안 변경된 Heart 정보를 반영 + widget.recipes.forEach((recipe) { + // 변경된 Heart 정보가 반영된 경우에만 각 레시피의 정보를 업데이트합니다. + if (recipe.heart != null) { + // print(recipe.simpleDietId); + int index = widget.recipes.indexWhere((element) => element.simpleDietId == recipe.simpleDietId); + // print(index); + // print('////'); + if (index != -1 && widget.recipes[index].simpleDietId == widget.simpleDietId) { + // print('*****'); + // print(widget.simpleDietId); + // print('^^^^^^^'); + print(widget.recipes[index].heart); + print(recipeDetails?.heart); + widget.recipes[index].heart = recipeDetails?.heart; + print(widget.recipes[index].heart); + } + } + }); + }); + // setState(() {}); Navigator.pop(context); }, color: Colors.transparent, @@ -42,7 +159,9 @@ class _ShowDetailRecipePageWidgetState extends State ), ), ), - body: SingleChildScrollView( + body: isLoading + ? Center(child:CircularProgressIndicator()) + : SingleChildScrollView( child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, @@ -50,7 +169,7 @@ class _ShowDetailRecipePageWidgetState extends State Padding( padding: EdgeInsets.fromLTRB(20, 15, 20, 10), child:Text( - '통새우 아보카도 샌드위치', + recipeDetails?.dietName ?? '기본 레시피 이름', style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, @@ -61,7 +180,7 @@ class _ShowDetailRecipePageWidgetState extends State Padding( padding: EdgeInsets.fromLTRB(20, 15, 20, 10), child: Text( - '계란을 스크램블해서 만든 부드러운 계란 스크램블을 식빵 사이에 넣어 샌드위치를 만듭니다.', + recipeDetails?.description ?? '기본 레시피 설명', style: TextStyle( fontSize: 14, fontWeight: FontWeight.w500, @@ -80,7 +199,7 @@ class _ShowDetailRecipePageWidgetState extends State ), padding: EdgeInsets.fromLTRB(10, 3, 10, 3), child: Text( - '간단해요', + recipeDetails?.difficulty ?? '기본 레시피 난이도', textAlign: TextAlign.center, style: TextStyle( fontSize: 14, @@ -100,7 +219,7 @@ class _ShowDetailRecipePageWidgetState extends State color: Color(0xFFFFFFFF), ), child: Text( - '20분 소요', + "${recipeDetails?.time?.toString() ?? '기본 레시피 시간'}분", textAlign: TextAlign.center, style: TextStyle( fontSize: 14, @@ -131,7 +250,7 @@ class _ShowDetailRecipePageWidgetState extends State ), ), Text( - '비타민이 풍부한', + widget?.selectedKeywords.toString() ?? ' ', textAlign: TextAlign.center, style: TextStyle( fontSize: 14, @@ -148,86 +267,86 @@ class _ShowDetailRecipePageWidgetState extends State ), Stack( children: [ - Container( - color: Color(0xFFF4F3F0), - child: Row( - children: [ - Padding( - padding: EdgeInsets.fromLTRB(20, 15, 1, 15), - child: Container( - decoration: BoxDecoration( - color: Color(0xFFDEFCE9), - borderRadius: BorderRadius.circular(18), - ), - padding: EdgeInsets.fromLTRB(10, 3, 10, 3), - child: Text( - '간단해요', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w400, - fontFamily: 'Pretendard', - color: Color(0xFF29CC5A), - ), - ), - ), - ), - Padding( - padding: EdgeInsets.fromLTRB(1, 15, 1, 15), - child: Container( - padding: EdgeInsets.fromLTRB(10, 3, 10, 3), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(18), - color: Color(0xFFFFFFFF), - ), - child: Text( - '20분 소요', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w400, - fontFamily: 'Pretendard', - color: Color(0xFF616161), - ), - ), - ), - ), - SizedBox(width: 5), - Padding( - padding: EdgeInsets.fromLTRB(1, 15, 5, 15), - child: Container( - padding: EdgeInsets.fromLTRB(10, 3, 10, 3), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(18), - color: Color(0xFFFFFFFF), - ), - child: Row( - children: [ - Padding( - padding: EdgeInsets.fromLTRB(2, 2, 2, 2), - child: Icon( - Icons.tag, - color: Color(0xFF9E9E9E), - size: 16, - ), - ), - Text( - '비타민이 풍부한', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w400, - fontFamily: 'Pretendard', - color: Color(0xFF616161), - ), - ), - ], - ), - ), - ), - ], - ), - ), + // Container( + // color: Color(0xFFF4F3F0), + // child: Row( + // children: [ + // Padding( + // padding: EdgeInsets.fromLTRB(20, 15, 1, 15), + // child: Container( + // decoration: BoxDecoration( + // color: Color(0xFFDEFCE9), + // borderRadius: BorderRadius.circular(18), + // ), + // padding: EdgeInsets.fromLTRB(10, 3, 10, 3), + // child: Text( + // '간단해요', + // textAlign: TextAlign.center, + // style: TextStyle( + // fontSize: 14, + // fontWeight: FontWeight.w400, + // fontFamily: 'Pretendard', + // color: Color(0xFF29CC5A), + // ), + // ), + // ), + // ), + // Padding( + // padding: EdgeInsets.fromLTRB(1, 15, 1, 15), + // child: Container( + // padding: EdgeInsets.fromLTRB(10, 3, 10, 3), + // decoration: BoxDecoration( + // borderRadius: BorderRadius.circular(18), + // color: Color(0xFFFFFFFF), + // ), + // child: Text( + // '20분 소요', + // textAlign: TextAlign.center, + // style: TextStyle( + // fontSize: 14, + // fontWeight: FontWeight.w400, + // fontFamily: 'Pretendard', + // color: Color(0xFF616161), + // ), + // ), + // ), + // ), + // SizedBox(width: 5), + // Padding( + // padding: EdgeInsets.fromLTRB(1, 15, 5, 15), + // child: Container( + // padding: EdgeInsets.fromLTRB(10, 3, 10, 3), + // decoration: BoxDecoration( + // borderRadius: BorderRadius.circular(18), + // color: Color(0xFFFFFFFF), + // ), + // child: Row( + // children: [ + // Padding( + // padding: EdgeInsets.fromLTRB(2, 2, 2, 2), + // child: Icon( + // Icons.tag, + // color: Color(0xFF9E9E9E), + // size: 16, + // ), + // ), + // Text( + // '비타민이 풍부한', + // textAlign: TextAlign.center, + // style: TextStyle( + // fontSize: 14, + // fontWeight: FontWeight.w400, + // fontFamily: 'Pretendard', + // color: Color(0xFF616161), + // ), + // ), + // ], + // ), + // ), + // ), + // ], + // ), + // ), Container( color: Colors.white, child: Column( @@ -249,7 +368,7 @@ class _ShowDetailRecipePageWidgetState extends State Padding( padding: EdgeInsets.fromLTRB(20, 20, 20, 20), child: Text( - '계란 2개, 소금 약간, 후추 약간, 설탕 1 큰 술, 버터 1 큰 술, 토스트 빵 2조각', + recipeDetails?.ingredients ?? '기본 레시피 재료', style: TextStyle( fontSize: 16, fontWeight: FontWeight.w500, @@ -283,12 +402,12 @@ class _ShowDetailRecipePageWidgetState extends State child: IconButton( icon: Icon( Icons.favorite, - color: isScrabed ? Color(0xFFFF5C39) : Color(0xFFDDDDDD), + color: recipeDetails != null && recipeDetails!.heart == true ? Color(0xFFFF5C39) : Color(0xFFDDDDDD), ), onPressed: () { setState(() { - isScrabed = !isScrabed; - }); + toggleScrab(); + }); }, ), ), @@ -317,11 +436,17 @@ class _ShowDetailRecipePageWidgetState extends State color: Color(0xFF424242), ), ), - for (Map order in cookorder) - showOrderWidget( - order: order.keys.first, - cookorder: order.values.first, - ), + if (recipeDetails?.recipe != null) + ...recipeDetails!.recipe!.split('\n').map((step) => Padding( + padding: EdgeInsets.only(top: 8.0), + child: Text( + step, + style: TextStyle( + fontSize: 16, + fontFamily: 'Pretendard', + ), + ), + )).toList(), ], ) ), @@ -331,53 +456,4 @@ class _ShowDetailRecipePageWidgetState extends State )); } } -class showOrderWidget extends StatelessWidget { - - final int order; - final String cookorder; - - showOrderWidget({ - required this.order, - required this.cookorder, - Key? key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return Padding( - padding: EdgeInsets.fromLTRB(0, 10, 0, 10), - child: Row( - children: [ - Container( - color: Color(0xFFFFFFFF), - child: Text( - '$order', - style: TextStyle( - fontSize: 13, - fontWeight: FontWeight.bold, - fontFamily: 'GowunBatang', - color: Color(0xFF616161), - ), - ), - ), - SizedBox(width: 10), - Expanded( - child: Padding( - padding: EdgeInsets.fromLTRB(5, 0, 20, 0), - child: Text( - '$cookorder', - style: TextStyle( - fontSize: 15, - fontFamily: 'Pretendard', - fontWeight: FontWeight.w500, - ), - ), - ), - ), - ], - ), - ); - } -} - diff --git a/babymeal/lib/pages/recommend/ShowRecipesPage.dart b/babymeal/lib/pages/recommend/ShowRecipesPage.dart index 20fa78b..7f164e3 100644 --- a/babymeal/lib/pages/recommend/ShowRecipesPage.dart +++ b/babymeal/lib/pages/recommend/ShowRecipesPage.dart @@ -1,9 +1,24 @@ import 'package:babymeal/NavigationPage.dart'; +import 'package:babymeal/model/FridgeRecipe.dart'; +import 'package:babymeal/model/RecipeModel.dart'; +import 'package:babymeal/pages/recommend/ShowDetailFridgeRecipePage.dart'; import 'package:babymeal/pages/recommend/ShowDetailRecipePage.dart'; +import 'package:babymeal/pages/recommend/WaitRecipesPage.dart'; import 'package:flutter/material.dart'; +import 'dart:convert'; +import 'package:http/http.dart' as http; +import 'package:babymeal/model/RecipeModel.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'dart:convert' show utf8; + class ShowRecipesPageWidget extends StatefulWidget { - const ShowRecipesPageWidget({Key? key}) : super(key: key); + final String selectedOption; + final List selectedMaterials; + final List selectedKeywords; + final List recipes; + final List fridgeRecipes; + const ShowRecipesPageWidget({Key? key, required this.selectedOption, required this.selectedMaterials, required this.selectedKeywords, required this.recipes, required this.fridgeRecipes}) : super(key: key); @override _ShowRecipesPageWidgetState createState() => _ShowRecipesPageWidgetState(); @@ -11,18 +26,100 @@ class ShowRecipesPageWidget extends StatefulWidget { class _ShowRecipesPageWidgetState extends State { final scaffoldKey = GlobalKey(); + Future>? refrigeratorRecipesFuture; - List likeStates = [false, false, false]; + void changeRecipeLike(int index) async { + final String simpleDietId = widget.recipes[index].simpleDietId.toString(); - void changeLike(int index) { - setState(() { - likeStates[index] = !likeStates[index]; + final String url = 'http://ec2-43-200-210-159.ap-northeast-2.compute.amazonaws.com:8080/diet/press?simpleDietId=$simpleDietId'; + + final SharedPreferences prefs = await SharedPreferences.getInstance(); + final String? userToken = prefs.getString('accessToken'); + + if (userToken == null) { + print('No user token found'); + return; + } + + try { + final response = await http.put(Uri.parse(url), headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $userToken', + }); + + if (response.statusCode == 200) { + final jsonResponse = jsonDecode(response.body); + final bool heart = jsonResponse['data']['heart']; + setState(() { + widget.recipes[index].heart = heart; // 서버 응답에 따라 상태 업데이트 + print("[$index] updated to: ${widget.recipes[index].heart}"); + + }); + } else { + print('Failed to change like status'); + } + } catch (e) { + print('Exception occurred: $e'); + } +} + +void changeFridgeRecipeLike(int index) async { + final String simpleDietId = widget.fridgeRecipes[index].simpleDietId.toString(); + final String url = 'http://ec2-43-200-210-159.ap-northeast-2.compute.amazonaws.com:8080/diet/press?simpleDietId=$simpleDietId'; + + final SharedPreferences prefs = await SharedPreferences.getInstance(); + final String? userToken = prefs.getString('accessToken'); + + if (userToken == null) { + print('No user token found'); + return; + } + + try { + final response = await http.put(Uri.parse(url), headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $userToken', }); + + if (response.statusCode == 200) { + final jsonResponse = jsonDecode(response.body); + final bool heart = jsonResponse['data']['heart']; + setState(() { + widget.fridgeRecipes[index].heart = heart; // 서버 응답에 따라 상태 업데이트 + print("[$index] updated to: ${widget.fridgeRecipes[index].heart}"); + + }); + } else { + print('Failed to change like status'); + } + } catch (e) { + print('Exception occurred: $e'); } +} + +void onHeartChangedRecipe(int? simpleDietId, bool newHeartValue) { + setState(() { + final recipeIndex = widget.recipes.indexWhere((recipe) => recipe.simpleDietId == simpleDietId); + if (recipeIndex != -1) { + widget.recipes[recipeIndex].heart = newHeartValue; + } + }); +} + +void onHeartChangedFridgeRecipe(int? simpleDietId, bool newHeartValue) { + setState(() { + final recipeIndex = widget.fridgeRecipes.indexWhere((recipe) => recipe.simpleDietId == simpleDietId); + if (recipeIndex != -1) { + widget.fridgeRecipes[recipeIndex].heart = newHeartValue; + } + }); +} + @override void initState() { super.initState(); + // loadUserTokenAndFetchRecipes(); } @override @@ -30,6 +127,19 @@ class _ShowRecipesPageWidgetState extends State { super.dispose(); } + // void loadUserTokenAndFetchRecipes() async { + // final SharedPreferences prefs = await SharedPreferences.getInstance(); + // final String? userToken = prefs.getString('accessToken'); + // if (userToken != null) { + // // babyId 처리 + + // //refrigeratorRecipesFuture = fetchRefrigeratorRecipes(userToken, 6); + // } else { + // // 처리: 토큰이 없을 경우, 예를 들어 로그인 화면으로 이동 + // print('User token not found, please login.'); + // } + // } + @override Widget build(BuildContext context) { return Scaffold( @@ -38,7 +148,7 @@ class _ShowRecipesPageWidgetState extends State { children: [ Container( alignment: Alignment.centerLeft, - margin: EdgeInsets.only(left: 20, top: 62), + margin: EdgeInsets.only(left: 20, top: 40), child: Text( 'AI 유아식 추천', style: TextStyle( @@ -51,9 +161,22 @@ class _ShowRecipesPageWidgetState extends State { ), )), Container( - margin: EdgeInsets.fromLTRB(0, 21, 20, 11), + margin: EdgeInsets.fromLTRB(0, 0, 20, 0), child: Row( mainAxisAlignment: MainAxisAlignment.end, + children:[ + GestureDetector( + onTap: () { + // Navigator를 사용하여 WaitRecipesPageWidget으로 이동 + Navigator.pushReplacement( + context, + MaterialPageRoute(builder: (context) => WaitRecipesPageWidget( + selectedOption: widget.selectedOption, + selectedMaterials: widget.selectedMaterials, + selectedKeywords: widget.selectedKeywords, + )), + ); + },child: Row( children: [ Image.asset("assets/images/autorenew.png"), Text( @@ -68,61 +191,45 @@ class _ShowRecipesPageWidgetState extends State { ), ) ], - )), - Container( - margin: EdgeInsets.only(bottom: 14), - child: Column( - children: [ - Row(children: [ - GestureDetector( - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => - ShowDetailRecipePageWidget())); - }, - child: AIRecipe(), + )),],),), + ListView.builder( + shrinkWrap: true, // Column 내부에 ListView를 넣을 때 필요 + physics: NeverScrollableScrollPhysics(), // Column 스크롤과의 충돌 방지 + itemCount: widget.recipes.length, // 레시피 개수 + itemBuilder: (context, index) { + return Container( + margin: EdgeInsets.only(bottom: 7), // 여기에 마진 추가 + child: Row( + children: [ + Expanded( + child: AIRecipe( + recipe: widget.recipes[index], + selectedMaterials: widget.selectedMaterials, // 이렇게 넘겨줌 + selectedKeywords: widget.selectedKeywords, + recipes: widget.recipes, + onHeartChanged: onHeartChangedRecipe, + ), ), GestureDetector( - onTap: () { - changeLike(0); - }, - child: ImageIcon( - AssetImage(likeStates[0] - ? "assets/images/like_sel.png" - : "assets/images/like.png"), - color: Color(0xFFCE4040), - )) - ]), - Row(children: [ - AIRecipe(), - GestureDetector( - onTap: () { - changeLike(0); + onTap: () { + setState(() { + changeRecipeLike(index); + }); }, + child: Padding( + padding: EdgeInsets.only(left: 5, right: 15), child: ImageIcon( - AssetImage(likeStates[0] - ? "assets/images/like_sel.png" - : "assets/images/like.png"), - color: Color(0xFFCE4040), - )) - ]), - Row(children: [ - AIRecipe(), - GestureDetector( - onTap: () { - changeLike(0); - }, - child: ImageIcon( - AssetImage(likeStates[0] - ? "assets/images/like_sel.png" - : "assets/images/like.png"), - color: Color(0xFFCE4040), - )) - ]), - ], - )), + AssetImage("assets/images/like.png"), + color: widget.recipes[index].heart ?? false ? Colors.red : Colors.grey, + ), + ), + ) + ], + ), + ); + }, + ), + ElevatedButton( style: ElevatedButton.styleFrom( minimumSize: Size(160, 55), @@ -150,12 +257,12 @@ class _ShowRecipesPageWidgetState extends State { ), )), Container( - margin: EdgeInsets.only(left: 22, top: 34, bottom: 14), + margin: EdgeInsets.only(left: 22, top: 24, bottom: 0), child: Column( children: [ Container( alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 14), + margin: EdgeInsets.only(bottom: 0), child: Text( '냉장고 재료 기반, 빠른 추천', style: TextStyle( @@ -167,51 +274,107 @@ class _ShowRecipesPageWidgetState extends State { letterSpacing: -0.36, ), )), - Container( - child: Column( - children: [ - Row(children: [ - RefrigeratorRecipe(), - GestureDetector( - onTap: () { - changeLike(0); - }, - child: ImageIcon( - AssetImage(likeStates[0] - ? "assets/images/like_sel.png" - : "assets/images/like.png"), - color: Color(0xFFCE4040), - )) - ]), - Row(children: [ - RefrigeratorRecipe(), - GestureDetector( + ListView.builder( + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), // 스크롤이 가능하도록 설정 + itemCount: widget.fridgeRecipes.length, // 아이템 개수는 fridgeRecipes 리스트의 길이 + itemBuilder: (context, index) { + FridgeRecipe fridgeRecipe = widget.fridgeRecipes[index]; // 현재 인덱스의 레시피 + return Container( + margin: EdgeInsets.only(bottom: 14), + child: Row( + children: [ + Expanded( + child: RefrigeratorRecipe( + fridgeRecipe: fridgeRecipe, + selectedMaterials: widget.selectedMaterials, // 이렇게 넘겨줌 + selectedKeywords: widget.selectedKeywords, + fridgeRecipes: widget.fridgeRecipes, + onHeartChanged: onHeartChangedFridgeRecipe,), // 레시피 위젯 + ), + GestureDetector( onTap: () { - changeLike(0); + changeFridgeRecipeLike(index); }, - child: ImageIcon( - AssetImage(likeStates[0] - ? "assets/images/like_sel.png" - : "assets/images/like.png"), - color: Color(0xFFCE4040), - )) - ]), - ], - )) + child: Padding( + padding: EdgeInsets.only(left: 5, right: 15), + child: ImageIcon( + AssetImage("assets/images/like.png"), + color: widget.fridgeRecipes[index].heart ?? false ? Colors.red : Colors.grey, + ), + ), + ), + ], + ), + ); + }, + ), ], )) ], )); } + + } class AIRecipe extends StatelessWidget { - AIRecipe({super.key}); + final GetRecipe recipe; + final List selectedMaterials; + final List selectedKeywords; + final List recipes; + final Function(int? simpleDietId, bool newHeartStatus) onHeartChanged; + // GetRecipe 객체를 받기 위한 변수 추가 + AIRecipe({Key? key, required this.recipe, required this.selectedMaterials, required this.selectedKeywords, required this.recipes, required this.onHeartChanged,}) : super(key: key); // 생성자 수정 + bool isLiked = false; + + Color getDifficultyTextColor(String? difficulty) { + switch (difficulty) { + case '간단': + return Color(0xFF28CC59); // 초록색 + case '보통': + return Color(0xFFFFA726); // 주황색 + case '복잡': + return Color(0xFFEF5350); // 빨간색 + default: + return Color(0xFF9E9E9E); // 기본 색상 (회색) + } +} + Color getDifficultyBackgroundColor(String? difficulty) { + switch (difficulty) { + case '간단': + return Color(0xFFDEFCE9); // 초록색 + case '보통': + return Color(0xFFFFE8CC); // 주황색 + case '복잡': + return Color(0xFFFFE5DF); // 빨간색 + default: + return Color(0xFF9E9E9E); // 기본 색상 (회색) + } +} + @override Widget build(BuildContext context) { - return Container( + return GestureDetector( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ShowDetailRecipePageWidget( + selectedMaterials: selectedMaterials, + selectedKeywords: selectedKeywords, + simpleDietId: recipe.simpleDietId, + recipes: recipes, + onHeartChanged: (simpleDietId, newHeartStatus) { + // 상위 위젯의 onHeartChanged 콜백을 호출합니다. + onHeartChanged(simpleDietId, newHeartStatus); + },), + ), + ); + }, + child: Container( margin: EdgeInsets.fromLTRB(20, 0, 12, 10), height: MediaQuery.of(context).size.height * 0.14, width: MediaQuery.of(context).size.width * 0.8, @@ -229,7 +392,8 @@ class AIRecipe extends StatelessWidget { children: [ Container( child: Text( - '스크램블 에그 샌드위치', + recipe.dietName ?? '', + overflow: TextOverflow.ellipsis, style: TextStyle( color: Color(0xFF212121), fontSize: 18, @@ -247,16 +411,16 @@ class AIRecipe extends StatelessWidget { horizontal: 8, vertical: 2), clipBehavior: Clip.antiAlias, decoration: ShapeDecoration( - color: Color(0xFFDEFCE9), + color: getDifficultyBackgroundColor(recipe.difficulty), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(17.12), ), ), child: Text( - '간단', + recipe.difficulty ?? '', textAlign: TextAlign.center, style: TextStyle( - color: Color(0xFF28CC59), + color: getDifficultyTextColor(recipe.difficulty), fontSize: 12, fontFamily: 'Pretendard', fontWeight: FontWeight.w600, @@ -278,7 +442,7 @@ class AIRecipe extends StatelessWidget { ), ), child: Text( - '20분', + '${recipe.time?.toString() ?? '0'}분', textAlign: TextAlign.center, style: TextStyle( color: Color(0xFF757575), @@ -295,9 +459,9 @@ class AIRecipe extends StatelessWidget { Container( margin: EdgeInsets.only(left: 21, right: 20), child: Text( + recipe.description ?? '', overflow: TextOverflow.ellipsis, maxLines: 2, - '계란을 스크램블해서 만든 부드러운 계란 스크램블을 식빵 사이에 넣어 샌드위치를 만듭니다.', style: TextStyle( color: Color(0xFF616161), fontSize: 13, @@ -308,100 +472,138 @@ class AIRecipe extends StatelessWidget { ), )) ], - )); + )), + ); + } } class RefrigeratorRecipe extends StatelessWidget { - const RefrigeratorRecipe({super.key}); + final FridgeRecipe fridgeRecipe; + final List selectedMaterials; + final List selectedKeywords; + final List fridgeRecipes; + final Function(int? simpleDietId, bool newHeartStatus) onHeartChanged; + const RefrigeratorRecipe({Key? key, required this.fridgeRecipe, required this.selectedMaterials, required this.selectedKeywords, required this.fridgeRecipes, required this.onHeartChanged}) : super(key: key); + + Color getDifficultyTextColor(String? difficulty) { + switch (difficulty) { + case '간단': + return Color(0xFF28CC59); // 초록색 + case '보통': + return Color(0xFFFFA726); // 주황색 + case '복잡': + return Color(0xFFEF5350); // 빨간색 + default: + return Color(0xFF9E9E9E); // 기본 색상 (회색) + } +} + +Color getDifficultyBackgroundColor(String? difficulty) { + switch (difficulty) { + case '간단': + return Color(0xFFDEFCE9); // 초록색 + case '보통': + return Color(0xFFFFE8CC); // 주황색 + case '복잡': + return Color(0xFFFFE5DF); // 빨간색 + default: + return Color(0xFF9E9E9E); // 기본 색상 (회색) + } +} @override Widget build(BuildContext context) { - return Container( - margin: EdgeInsets.only(right: 12, bottom: 8), - height: MediaQuery.of(context).size.height * 0.06, - width: MediaQuery.of(context).size.width * 0.8, - decoration: ShapeDecoration( - color: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), + return GestureDetector( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ShowDetailFridgeRecipePageWidget( + selectedMaterials: selectedMaterials, + selectedKeywords: selectedKeywords, + simpleDietId: fridgeRecipe.simpleDietId, + fridgeRecipes: fridgeRecipes, + onHeartChanged: (simpleDietId, newHeartStatus) { + onHeartChanged(simpleDietId, newHeartStatus); + },), ), - ), - child: Row( - children: [ - Container( - margin: EdgeInsets.only(left: 9, right: 8), - child: Text( - '🍞', - textAlign: TextAlign.center, - style: TextStyle( - color: Colors.black, - fontSize: 26, - fontFamily: 'Pretendard', - fontWeight: FontWeight.w500, - height: 0, - ), - )), - Container( - margin: EdgeInsets.only(right: 8), - child: Text( - '미니 치즈 피자', - style: TextStyle( - color: Color(0xFF212121), - fontSize: 15, - fontFamily: 'Pretendard', - fontWeight: FontWeight.w600, - height: 0, - ), - )), - Container( - margin: EdgeInsets.only(right: 8), - width: 37, - height: 18, - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), - clipBehavior: Clip.antiAlias, - decoration: ShapeDecoration( - color: Color(0x33FF8A00), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(17.12), - ), - ), - child: Text( - '보통', - textAlign: TextAlign.center, - style: TextStyle( - color: Color(0xFFFF8900), - fontSize: 12, - fontFamily: 'Pretendard', - fontWeight: FontWeight.w600, - height: 0, - letterSpacing: -0.24, - ), - )), - Container( - width: 42, - height: 18, - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), - clipBehavior: Clip.antiAlias, - decoration: ShapeDecoration( - color: Color(0xFFF4F3F0), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(17.12), + ); + }, + child: Container( + margin: EdgeInsets.only(right: 12, bottom: 0), + height: MediaQuery.of(context).size.height * 0.06, + width: MediaQuery.of(context).size.width * 0.8, + decoration: ShapeDecoration( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + ), + child: Row( + children: [ + + Container( + margin: EdgeInsets.only(left: 8), + child: Text( + fridgeRecipe.dietName ?? '', + style: TextStyle( + color: Color(0xFF212121), + fontSize: 15, + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + height: 0, + ), + )), + Container( + margin: EdgeInsets.only(right: 8), + width: 37, + height: 18, + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), + clipBehavior: Clip.antiAlias, + decoration: ShapeDecoration( + color: getDifficultyBackgroundColor(fridgeRecipe.difficulty), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(17.12), + ), ), - ), - child: Text( - '40분', - textAlign: TextAlign.center, - style: TextStyle( - color: Color(0xFF757575), - fontSize: 12, - fontFamily: 'Pretendard', - fontWeight: FontWeight.w600, - height: 0, - letterSpacing: -0.24, + child: Text( + fridgeRecipe.difficulty ?? '', + textAlign: TextAlign.center, + style: TextStyle( + color: getDifficultyTextColor(fridgeRecipe.difficulty), + fontSize: 12, + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + height: 0, + letterSpacing: -0.24, + ), + )), + Container( + width: 42, + height: 18, + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), + clipBehavior: Clip.antiAlias, + decoration: ShapeDecoration( + color: Color(0xFFF4F3F0), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(17.12), + ), ), - )) - ], - )); + child: Text( + '${fridgeRecipe.time?.toString() ?? '0'}분', + textAlign: TextAlign.center, + style: TextStyle( + color: Color(0xFF757575), + fontSize: 12, + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + height: 0, + letterSpacing: -0.24, + ), + )) + ], + )), + ); } } diff --git a/babymeal/lib/pages/recommend/ViewRecommendPage.dart b/babymeal/lib/pages/recommend/ViewRecommendPage.dart index 90cbe35..1bce33f 100644 --- a/babymeal/lib/pages/recommend/ViewRecommendPage.dart +++ b/babymeal/lib/pages/recommend/ViewRecommendPage.dart @@ -1,7 +1,18 @@ import 'package:babymeal/NavigationPage.dart'; +import 'package:babymeal/model/FridgeRecipe.dart'; import 'package:babymeal/pages/recommend/RecomChooseMealPage.dart'; +import 'package:babymeal/pages/recommend/ShowDetailFridgeRecipePage.dart'; +import 'package:babymeal/pages/recommend/ShowDetailMainFridgeRecipe.dart'; +import 'package:babymeal/services/DietService.dart'; +import 'package:babymeal/services/MyPageService.dart'; import 'package:flutter/material.dart'; +import 'dart:convert'; +import 'package:http/http.dart' as http; +import 'package:babymeal/model/RecipeModel.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'dart:convert' show utf8; + class ViewRecommendPageWidget extends StatefulWidget { const ViewRecommendPageWidget({Key? key}) : super(key: key); @@ -13,10 +24,12 @@ class ViewRecommendPageWidget extends StatefulWidget { class _ViewRecommendPageWidgetState extends State { final scaffoldKey = GlobalKey(); List scrab = [false, false]; + List fridgeRecipes = []; @override void initState() { super.initState(); + _loadRecipes(); } @override @@ -24,6 +37,76 @@ class _ViewRecommendPageWidgetState extends State { super.dispose(); } +Future _loadRecipes() async { + DietService dietService = DietService(); + MyPageService myPageService = MyPageService(); + final SharedPreferences prefs = await SharedPreferences.getInstance(); + final String? userToken = prefs.getString('accessToken'); + if (userToken == null) { + print('No user token found'); + return; + } + + try { + String babyId = await myPageService.getBabyId(userToken); + var tempRecipes = await dietService.fetchRefrigeratorRecipes(babyId); // 여기서 메소드 호출 + print("fridgeRecipes: $tempRecipes"); + if (mounted) { + setState(() { + fridgeRecipes = tempRecipes; + }); + } + } catch (e) { + print("Error fetching fridge recipes: $e"); + // 에러 핸들링 로직 추가 가능 + } +} + + +Future onHeartChangedFridgeRecipe(int? simpleDietId, bool newHeartValue) async { + final recipeIndex = fridgeRecipes.indexWhere((recipe) => recipe.simpleDietId == simpleDietId); + + if (recipeIndex != -1) { + setState(() { + fridgeRecipes[recipeIndex].heart = newHeartValue; + }); + } +} + +void changeFridgeRecipeLike(int index) async { + final String simpleDietId = fridgeRecipes[index].simpleDietId.toString(); + final String url = 'http://ec2-43-200-210-159.ap-northeast-2.compute.amazonaws.com:8080/diet/press?simpleDietId=$simpleDietId'; + + final SharedPreferences prefs = await SharedPreferences.getInstance(); + final String? userToken = prefs.getString('accessToken'); + + if (userToken == null) { + print('No user token found'); + return; + } + + try { + final response = await http.put(Uri.parse(url), headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $userToken', + }); + + if (response.statusCode == 200) { + final jsonResponse = jsonDecode(response.body); + final bool heart = jsonResponse['data']['heart']; + setState(() { + fridgeRecipes[index].heart = heart; // 서버 응답에 따라 상태 업데이트 + print("[$index] updated to: ${fridgeRecipes[index].heart}"); + + }); + } else { + print('Failed to change like status'); + } + } catch (e) { + print('Exception occurred: $e'); + } +} + @override Widget build(BuildContext context) { return Scaffold( @@ -87,110 +170,187 @@ class _ViewRecommendPageWidgetState extends State { letterSpacing: -0.50, ))), ])), - Padding( - padding: EdgeInsetsDirectional.fromSTEB(30, 130, 0, 0), - child: RichText( - text: TextSpan(children: [ - TextSpan( - text: '냉장고 재료 기반, 빠른 추천', - style: TextStyle( - color: Color(0xFF424242), - fontSize: 18, - fontFamily: 'Pretendard', - fontWeight: FontWeight.w700, - height: 0, - letterSpacing: -0.50, - ), - ) - ]))), - Row(children: [ - Padding( - padding: EdgeInsetsDirectional.fromSTEB(30, 15, 0, 0), - child: Container( - height: 48.0, - width: 315.0, - child: Row(children: [ - Padding( - padding: EdgeInsets.fromLTRB(15, 0, 0, 0), - child: Image.asset("assets/images/bread.png"), + Container( + margin: EdgeInsets.only(left: 22, top: 24, bottom: 0), + child: Column( + children: [ + Container( + alignment: Alignment.centerLeft, + margin: EdgeInsets.only(top: 100, bottom: 20), + child: Text( + '냉장고 재료 기반, 빠른 추천', + style: TextStyle( + color: Color(0xFF424242), + fontSize: 18, + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + height: 0, + letterSpacing: -0.36, + ), + )), + ListView.builder( + shrinkWrap: true, + itemCount: fridgeRecipes.length, // fridgeRecipes 리스트의 길이로 아이템 개수 설정 + itemBuilder: (context, index) { + FridgeRecipe fridgeRecipe = fridgeRecipes[index]; // 현재 인덱스의 레시피 객체 + return Container( + margin: EdgeInsets.only(bottom: 14), + child: Row( + children: [ + Expanded( + child: RefrigeratorRecipe( + fridgeRecipe: fridgeRecipe, + fridgeRecipes: fridgeRecipes, + onHeartChanged: onHeartChangedFridgeRecipe, + ), ), - Padding( - padding: EdgeInsets.fromLTRB(10, 0, 0, 0), - child: RichText( - textAlign: TextAlign.left, - text: TextSpan( - text: '미니 치즈 피자', - style: TextStyle( - color: Color(0xFF212121), - fontSize: 15, - fontFamily: 'Pretendard', - fontWeight: FontWeight.w700, - height: 0, - letterSpacing: -0.50, - )))), - ]), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(10.0))), - ), - Padding( - padding: EdgeInsets.fromLTRB(15, 10, 0, 0), - child: GestureDetector( - onTap: () { - setState(() { - scrab[0] = !scrab[0]; - }); - }, - child: scrab[0] - ? Image.asset("assets/images/scrab_full.png") - : Image.asset("assets/images/scrab_empty.png"), - )), - ]), - Row(children: [ - Padding( - padding: EdgeInsetsDirectional.fromSTEB(30, 10, 0, 0), - child: Container( - height: 48.0, - width: 315.0, - child: Row(children: [ - Padding( - padding: EdgeInsets.fromLTRB(15, 0, 0, 0), - child: Image.asset("assets/images/onion.png"), + GestureDetector( + onTap: () { + changeFridgeRecipeLike(index); + }, + child: Padding( + padding: EdgeInsets.only(left: 5, right: 15), + child: ImageIcon( + AssetImage("assets/images/like.png"), + color: fridgeRecipe.heart ?? false ? Colors.red : Colors.grey, + ), + ), ), - Padding( - padding: EdgeInsets.fromLTRB(10, 0, 0, 0), - child: RichText( - textAlign: TextAlign.left, - text: TextSpan( - text: '어니언 스프', - style: TextStyle( - color: Color(0xFF212121), - fontSize: 15, - fontFamily: 'Pretendard', - fontWeight: FontWeight.w700, - height: 0, - letterSpacing: -0.50, - )))), - ]), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(10.0))), - ), - Padding( - padding: EdgeInsets.fromLTRB(15, 10, 0, 0), - child: GestureDetector( - onTap: () { - setState(() { - scrab[1] = !scrab[1]; - }); - }, - child: scrab[1] - ? Image.asset("assets/images/scrab_full.png") - : Image.asset("assets/images/scrab_empty.png"), - )), - ]), + ], + ), + ); + }, + ), + ], + )) + ], + )), + ); + } +} + +class RefrigeratorRecipe extends StatelessWidget { + final FridgeRecipe fridgeRecipe; + final List fridgeRecipes; + final Function(int? simpleDietId, bool newHeartStatus) onHeartChanged; + const RefrigeratorRecipe({Key? key, required this.fridgeRecipe, required this.fridgeRecipes, required this.onHeartChanged}) : super(key: key); + + Color getDifficultyTextColor(String? difficulty) { + switch (difficulty) { + case '간단': + return Color(0xFF28CC59); // 초록색 + case '보통': + return Color(0xFFFFA726); // 주황색 + case '복잡': + return Color(0xFFEF5350); // 빨간색 + default: + return Color(0xFF9E9E9E); // 기본 색상 (회색) + } +} + +Color getDifficultyBackgroundColor(String? difficulty) { + switch (difficulty) { + case '간단': + return Color(0xFFDEFCE9); // 초록색 + case '보통': + return Color(0xFFFFE8CC); // 주황색 + case '복잡': + return Color(0xFFFFE5DF); // 빨간색 + default: + return Color(0xFF9E9E9E); // 기본 색상 (회색) + } +} + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ShowDetailMainFridgeRecipePageWidget( + simpleDietId: fridgeRecipe.simpleDietId, + fridgeRecipes: fridgeRecipes, + onHeartChanged: (simpleDietId, newHeartStatus) { + onHeartChanged(simpleDietId, newHeartStatus); + },), + ), + ); + }, + child: Container( + margin: EdgeInsets.only(right: 12, bottom: 0), + height: MediaQuery.of(context).size.height * 0.06, + width: MediaQuery.of(context).size.width * 0.8, + decoration: ShapeDecoration( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + ), + child: Row( + children: [ + Container( + margin: EdgeInsets.only(left: 8), + child: Text( + fridgeRecipe.dietName ?? '', + style: TextStyle( + color: Color(0xFF212121), + fontSize: 15, + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + height: 0, + ), + )), + Container( + margin: EdgeInsets.only(right: 8), + width: 37, + height: 18, + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), + clipBehavior: Clip.antiAlias, + decoration: ShapeDecoration( + color: getDifficultyBackgroundColor(fridgeRecipe.difficulty), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(17.12), + ), + ), + child: Text( + fridgeRecipe.difficulty ?? '', + textAlign: TextAlign.center, + style: TextStyle( + color: getDifficultyTextColor(fridgeRecipe.difficulty), + fontSize: 12, + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + height: 0, + letterSpacing: -0.24, + ), + )), + Container( + width: 42, + height: 18, + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), + clipBehavior: Clip.antiAlias, + decoration: ShapeDecoration( + color: Color(0xFFF4F3F0), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(17.12), + ), + ), + child: Text( + '${fridgeRecipe.time?.toString() ?? '0'}분', + textAlign: TextAlign.center, + style: TextStyle( + color: Color(0xFF757575), + fontSize: 12, + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + height: 0, + letterSpacing: -0.24, + ), + )) ], )), ); } } + diff --git a/babymeal/lib/pages/recommend/WaitRecipesPage.dart b/babymeal/lib/pages/recommend/WaitRecipesPage.dart index 51bcd10..0733267 100644 --- a/babymeal/lib/pages/recommend/WaitRecipesPage.dart +++ b/babymeal/lib/pages/recommend/WaitRecipesPage.dart @@ -1,12 +1,24 @@ import 'dart:async'; import 'dart:math'; +import 'package:babymeal/model/FridgeRecipe.dart'; +import 'package:babymeal/services/DietService.dart'; +import 'package:babymeal/services/MyPageService.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import 'package:babymeal/etc/tips.dart'; +import 'package:babymeal/model/RecipeModel.dart'; import 'package:babymeal/pages/recommend/ShowRecipesPage.dart'; import 'package:flutter/material.dart'; +import 'dart:convert'; +import 'package:http/http.dart' as http; +import 'dart:convert' show utf8; class WaitRecipesPageWidget extends StatefulWidget { - const WaitRecipesPageWidget({Key? key}) : super(key: key); + final String selectedOption; + final List selectedMaterials; + final List selectedKeywords; + + const WaitRecipesPageWidget({Key? key, required this.selectedOption, required this.selectedMaterials, required this.selectedKeywords}) : super(key: key); @override _WaitRecipesPageWidgetState createState() => _WaitRecipesPageWidgetState(); @@ -41,6 +53,118 @@ class _WaitRecipesPageWidgetState extends State }); } + + Future> fetchRecipes(String token, String babyId, String type, String fridge, String keyword) async { + var url = Uri.parse('http://ec2-43-200-210-159.ap-northeast-2.compute.amazonaws.com:8080/diet/simple?babyId=$babyId'); + + var body = jsonEncode({ + 'type': type, + 'fridge': fridge, + 'keyword': keyword, + }); + + try { + var response = await http.post(url, + body: body, + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', // 여기서 인증 토큰을 전달 + }, + ); + var responsecode = response.statusCode; + print("fetchRecipe response.statusCode: $responsecode"); + + if (response.statusCode == 200) { + // UTF-8로 명시적으로 디코딩 + var responseBody = utf8.decode(response.bodyBytes); + var jsonResponse = jsonDecode(responseBody); + + if (jsonResponse['data'] != null) { + // 'data' 키 아래의 리스트를 GetRecipe 객체의 리스트로 변환 + var recipesList = List>.from(jsonResponse['data']) + .map((recipeJson) => GetRecipe.fromJson(recipeJson)) + .toList(); + return recipesList; + + } else { + throw Exception('Data key not found'); + } + } else { + // 오류 처리 + throw Exception('Failed to load recipes'); + } + } catch (e) { + // 네트워크 오류 처리 + throw Exception('Failed to load recipes: $e'); + } +} + Future> fetchRefrigeratorRecipes(String token, String babyId) async { + + var url = Uri.parse('http://ec2-43-200-210-159.ap-northeast-2.compute.amazonaws.com:8080/diet/fridge?babyId=$babyId'); + + try { + var response = await http.post(url, + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', // 여기서 인증 토큰을 전달 + }, + ); + var responsecode = response.statusCode; + print("fetchRefrigeratorRecipes response.statusCode: $responsecode"); + + if (response.statusCode == 200) { + // 서버로부터 받은 JSON 데이터를 파싱 + var responseBody = utf8.decode(response.bodyBytes); + var jsonResponse = jsonDecode(responseBody); + var fridgeRecipesList = List>.from(jsonResponse['data']).map((fridgeRecipe) => FridgeRecipe.fromJson(fridgeRecipe)).toList(); + + return fridgeRecipesList; + + } else { + // 오류 처리 + throw Exception('Failed to load recipes'); + } + } catch (e) { + // 네트워크 오류 처리 + throw Exception('Failed to load recipes: $e'); + } +} + +void changeRecipeLike(List recipes, int index) async { + final String simpleDietId = recipes[index].simpleDietId.toString(); + // print(simpleDietId); + final String url = 'http://ec2-43-200-210-159.ap-northeast-2.compute.amazonaws.com:8080/diet/press?simpleDietId=$simpleDietId'; + + final SharedPreferences prefs = await SharedPreferences.getInstance(); + final String? userToken = prefs.getString('accessToken'); + + if (userToken == null) { + print('No user token found'); + return; + } + + try { + final response = await http.put(Uri.parse(url), headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $userToken', + }); + + if (response.statusCode == 200) { + final jsonResponse = jsonDecode(response.body); + final bool heart = jsonResponse['data']['heart']; + setState(() { + recipes[index].heart = heart; // 서버 응답에 따라 상태 업데이트 + print("[$index] updated to: ${recipes[index].heart}"); + + }); + } else { + print('Failed to change like status'); + } + } catch (e) { + print('Exception occurred: $e'); + } +} + String getRandomItem() { // 랜덤한 인덱스 생성 int randomIndex = random.nextInt(tips.length); @@ -48,12 +172,51 @@ class _WaitRecipesPageWidgetState extends State return tips[randomIndex]; } - void navigateToNextScreen(BuildContext context) { - // TODO : 식단 가져오면 다음 화면으로 넘어가도록 수정 + void navigateToNextScreen(BuildContext context) async { + final SharedPreferences prefs = await SharedPreferences.getInstance(); + final String? userToken = prefs.getString('accessToken'); + + // 설정된 변수와 SharedPreferences에서 token 가져오기 + String type = widget.selectedOption; + String fridge = widget.selectedMaterials.join(','); + String keyword = widget.selectedKeywords.join(','); + + if (userToken == null) { + print('No user token found'); + return; + } + + MyPageService myPageService = MyPageService(); + + try { + String babyId = await myPageService.getBabyId(userToken); + final List recipes = await fetchRecipes(userToken, babyId as String, type, fridge, keyword); + for (var recipe in recipes) { + print(recipe.toString()); // 혹은 단순히 print(recipe); 라고 해도 됩니다. + } + final List fridgeRecipes = await fetchRefrigeratorRecipes(userToken, babyId as String); + for (var fetchRecipe in fridgeRecipes) { + print(fetchRecipe.toString()); // 혹은 단순히 print(recipe); 라고 해도 됩니다. + } + + // 화면 전환 Navigator.of(context).pushReplacement( - MaterialPageRoute(builder: (context) => ShowRecipesPageWidget()), + MaterialPageRoute( + builder: (context) => ShowRecipesPageWidget( + selectedOption: type, + selectedMaterials: widget.selectedMaterials, + selectedKeywords: widget.selectedKeywords, + recipes: recipes, + fridgeRecipes: fridgeRecipes, + ), + ), ); + } catch (e) { + print("Error fetching data: $e"); + // 오류 처리 로직, 예: 사용자에게 오류 메시지 표시 } +} + @override void dispose() { @@ -198,6 +361,7 @@ class _WaitRecipesPageWidgetState extends State ], )); } + } class WaitingCard extends StatelessWidget { @@ -230,4 +394,6 @@ class WaitingCard extends StatelessWidget { ), ))); } + + } diff --git a/babymeal/lib/services/DietService.dart b/babymeal/lib/services/DietService.dart new file mode 100644 index 0000000..7d84170 --- /dev/null +++ b/babymeal/lib/services/DietService.dart @@ -0,0 +1,45 @@ +import 'package:babymeal/model/FridgeRecipe.dart'; +import 'package:babymeal/model/RecipeModel.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; +import 'dart:convert'; +import 'package:http/http.dart' as http; +import 'package:babymeal/model/RecipeModel.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'dart:convert' show utf8; + +class DietService extends ChangeNotifier { + +Future> fetchRefrigeratorRecipes(String babyId) async { + final SharedPreferences prefs = await SharedPreferences.getInstance(); + final String? userToken = prefs.getString('accessToken'); + var url = Uri.parse('http://ec2-43-200-210-159.ap-northeast-2.compute.amazonaws.com:8080/diet/fridge?babyId=$babyId'); + + try { + var response = await http.post(url, + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $userToken', // 여기서 인증 토큰을 전달 + }, + ); + + if (response.statusCode == 200) { + // 서버로부터 받은 JSON 데이터를 파싱 + var responseBody = utf8.decode(response.bodyBytes); + var jsonResponse = jsonDecode(responseBody); + print(jsonResponse); + var fridgeRecipesList = List>.from(jsonResponse['data']).map((fridgeRecipe) => FridgeRecipe.fromJson(fridgeRecipe)).toList(); + print('fridgeRecipesList: $fridgeRecipesList'); + return fridgeRecipesList; + + } else { + // 오류 처리 + throw Exception('Failed to load recipes'); + } + } catch (e) { + // 네트워크 오류 처리 + throw Exception('Failed to load recipes: $e'); + } +} + +} \ No newline at end of file diff --git a/babymeal/lib/services/FridgeContentService.dart b/babymeal/lib/services/FridgeContentService.dart new file mode 100644 index 0000000..427df43 --- /dev/null +++ b/babymeal/lib/services/FridgeContentService.dart @@ -0,0 +1,13 @@ +class FridgeContent { + final String ingredients; + final String emoticon; + + FridgeContent({required this.ingredients, required this.emoticon}); + + factory FridgeContent.fromJson(Map json) { + return FridgeContent( + ingredients: json['ingredients'], + emoticon: json['emoticon'] ?? '', + ); + } +} \ No newline at end of file diff --git a/babymeal/lib/services/MyPageService.dart b/babymeal/lib/services/MyPageService.dart new file mode 100644 index 0000000..8144aae --- /dev/null +++ b/babymeal/lib/services/MyPageService.dart @@ -0,0 +1,70 @@ +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; +import 'dart:convert'; +import 'package:http/http.dart' as http; +import 'package:shared_preferences/shared_preferences.dart'; +import 'dart:convert' show utf8; + +class MyPageService extends ChangeNotifier { + + Future getBabyId(String token) async { + var url = Uri.parse('http://ec2-43-200-210-159.ap-northeast-2.compute.amazonaws.com:8080/customer/baby'); + + final String? userToken = token; // 매개변수로 전달된 token 사용 + + if (userToken == null) { + print('No user token found'); + return Future.error('No user token found'); // 에러 반환 + } + + try { + var response = await http.get(url, headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $userToken', + }); + + if (response.statusCode == 200) { + var responseBody = utf8.decode(response.bodyBytes); + var jsonResponse = jsonDecode(responseBody); + + if (jsonResponse['data'][0] != null) { + var newBabyId = jsonResponse['data'][0]['babyId'].toString(); // int를 String으로 변환 + print("newBabyId: $newBabyId"); + return newBabyId; + } else { + throw Exception('Data key not found'); + } + } else { + throw Exception('Failed to load babyId with status code ${response.statusCode}'); + } + } catch (e) { + print('Failed to load babyId: $e'); + return Future.error('Failed to load babyId: $e'); // 수정된 에러 처리 + } +} + +Future?> fetchCurrentBabyData(String babyId) async { + final SharedPreferences prefs = await SharedPreferences.getInstance(); + final String? token = prefs.getString('accessToken'); + + if (token == null) { + print('No token found'); + return null; + } + + final response = await http.get( + Uri.parse('http://ec2-43-200-210-159.ap-northeast-2.compute.amazonaws.com:8080/customer/baby'), + headers: { + 'Authorization': 'Bearer $token', + }, + ); + + if (response.statusCode == 200) { + final Map data = json.decode(utf8.decode(response.bodyBytes)); + return data; + } else { + print('Failed to fetch baby data'); + return null; + } +} +} \ No newline at end of file diff --git a/babymeal/macos/Flutter/Flutter-Debug.xcconfig b/babymeal/macos/Flutter/Flutter-Debug.xcconfig index c2efd0b..4b81f9b 100644 --- a/babymeal/macos/Flutter/Flutter-Debug.xcconfig +++ b/babymeal/macos/Flutter/Flutter-Debug.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig" diff --git a/babymeal/macos/Flutter/Flutter-Release.xcconfig b/babymeal/macos/Flutter/Flutter-Release.xcconfig index c2efd0b..5caa9d1 100644 --- a/babymeal/macos/Flutter/Flutter-Release.xcconfig +++ b/babymeal/macos/Flutter/Flutter-Release.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig" diff --git a/babymeal/macos/Podfile b/babymeal/macos/Podfile new file mode 100644 index 0000000..c795730 --- /dev/null +++ b/babymeal/macos/Podfile @@ -0,0 +1,43 @@ +platform :osx, '10.14' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/babymeal/macos/Podfile.lock b/babymeal/macos/Podfile.lock new file mode 100644 index 0000000..1fa14d2 --- /dev/null +++ b/babymeal/macos/Podfile.lock @@ -0,0 +1,35 @@ +PODS: + - emoji_picker_flutter (0.0.1): + - FlutterMacOS + - FlutterMacOS (1.0.0) + - shared_preferences_foundation (0.0.1): + - Flutter + - FlutterMacOS + - url_launcher_macos (0.0.1): + - FlutterMacOS + +DEPENDENCIES: + - emoji_picker_flutter (from `Flutter/ephemeral/.symlinks/plugins/emoji_picker_flutter/macos`) + - FlutterMacOS (from `Flutter/ephemeral`) + - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) + - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) + +EXTERNAL SOURCES: + emoji_picker_flutter: + :path: Flutter/ephemeral/.symlinks/plugins/emoji_picker_flutter/macos + FlutterMacOS: + :path: Flutter/ephemeral + shared_preferences_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin + url_launcher_macos: + :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos + +SPEC CHECKSUMS: + emoji_picker_flutter: 533634326b1c5de9a181ba14b9758e6dfe967a20 + FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 + shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126 + url_launcher_macos: d2691c7dd33ed713bf3544850a623080ec693d95 + +PODFILE CHECKSUM: 236401fc2c932af29a9fcf0e97baeeb2d750d367 + +COCOAPODS: 1.14.3 diff --git a/babymeal/macos/Runner.xcodeproj/project.pbxproj b/babymeal/macos/Runner.xcodeproj/project.pbxproj index 029514c..1b60047 100644 --- a/babymeal/macos/Runner.xcodeproj/project.pbxproj +++ b/babymeal/macos/Runner.xcodeproj/project.pbxproj @@ -21,12 +21,14 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ + 102F20C02D303FE430690372 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 91B132E896C8CFFD56277D6A /* Pods_RunnerTests.framework */; }; 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + 4836F922322FD53D14FE761A /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00817BA04B60FA5C6FD7F141 /* Pods_Runner.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -60,11 +62,13 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 00817BA04B60FA5C6FD7F141 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; - 33CC10ED2044A3C60003C045 /* babymeal.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "babymeal.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 33C48699D9355887F1FE3541 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* babymeal.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = babymeal.app; sourceTree = BUILT_PRODUCTS_DIR; }; 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; @@ -76,8 +80,14 @@ 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 5E03AFDE6E2F7807E5C4CC7B /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 91B132E896C8CFFD56277D6A /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + A48AAE98936A410F9DF348C1 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + C7BEB6D375625D2F9F1153FF /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + D3F4E5C49A322D3731AB38FA /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + E1A1AB733B555392774DCE07 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -85,6 +95,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 102F20C02D303FE430690372 /* Pods_RunnerTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -92,12 +103,27 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 4836F922322FD53D14FE761A /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 094D55E48C80A7A6740422C6 /* Pods */ = { + isa = PBXGroup; + children = ( + D3F4E5C49A322D3731AB38FA /* Pods-Runner.debug.xcconfig */, + A48AAE98936A410F9DF348C1 /* Pods-Runner.release.xcconfig */, + 5E03AFDE6E2F7807E5C4CC7B /* Pods-Runner.profile.xcconfig */, + 33C48699D9355887F1FE3541 /* Pods-RunnerTests.debug.xcconfig */, + C7BEB6D375625D2F9F1153FF /* Pods-RunnerTests.release.xcconfig */, + E1A1AB733B555392774DCE07 /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; 331C80D6294CF71000263BE5 /* RunnerTests */ = { isa = PBXGroup; children = ( @@ -125,6 +151,7 @@ 331C80D6294CF71000263BE5 /* RunnerTests */, 33CC10EE2044A3C60003C045 /* Products */, D73912EC22F37F3D000D13A0 /* Frameworks */, + 094D55E48C80A7A6740422C6 /* Pods */, ); sourceTree = ""; }; @@ -175,6 +202,8 @@ D73912EC22F37F3D000D13A0 /* Frameworks */ = { isa = PBXGroup; children = ( + 00817BA04B60FA5C6FD7F141 /* Pods_Runner.framework */, + 91B132E896C8CFFD56277D6A /* Pods_RunnerTests.framework */, ); name = Frameworks; sourceTree = ""; @@ -186,6 +215,7 @@ isa = PBXNativeTarget; buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( + B11D248F91FEE86BD597093E /* [CP] Check Pods Manifest.lock */, 331C80D1294CF70F00263BE5 /* Sources */, 331C80D2294CF70F00263BE5 /* Frameworks */, 331C80D3294CF70F00263BE5 /* Resources */, @@ -204,11 +234,13 @@ isa = PBXNativeTarget; buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( + EA26A047EFA396673BCF8133 /* [CP] Check Pods Manifest.lock */, 33CC10E92044A3C60003C045 /* Sources */, 33CC10EA2044A3C60003C045 /* Frameworks */, 33CC10EB2044A3C60003C045 /* Resources */, 33CC110E2044A8840003C045 /* Bundle Framework */, 3399D490228B24CF009A79C7 /* ShellScript */, + 68554F309DDE5843A807DCD1 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -328,6 +360,67 @@ shellPath = /bin/sh; shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; }; + 68554F309DDE5843A807DCD1 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + B11D248F91FEE86BD597093E /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + EA26A047EFA396673BCF8133 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -379,6 +472,7 @@ /* Begin XCBuildConfiguration section */ 331C80DB294CF71000263BE5 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 33C48699D9355887F1FE3541 /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; @@ -393,6 +487,7 @@ }; 331C80DC294CF71000263BE5 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = C7BEB6D375625D2F9F1153FF /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; @@ -407,6 +502,7 @@ }; 331C80DD294CF71000263BE5 /* Profile */ = { isa = XCBuildConfiguration; + baseConfigurationReference = E1A1AB733B555392774DCE07 /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; diff --git a/babymeal/macos/Runner.xcworkspace/contents.xcworkspacedata b/babymeal/macos/Runner.xcworkspace/contents.xcworkspacedata index 1d526a1..21a3cc1 100644 --- a/babymeal/macos/Runner.xcworkspace/contents.xcworkspacedata +++ b/babymeal/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -4,4 +4,7 @@ + + diff --git a/babymeal/pubspec.lock b/babymeal/pubspec.lock index cf79812..f24552a 100644 --- a/babymeal/pubspec.lock +++ b/babymeal/pubspec.lock @@ -192,22 +192,6 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.2" - leak_tracker: - dependency: transitive - description: - name: leak_tracker - sha256: "04be76c4a4bb50f14904e64749237e541e7c7bcf7ec0b196907322ab5d2fc739" - url: "https://pub.dev" - source: hosted - version: "9.0.16" - leak_tracker_testing: - dependency: transitive - description: - name: leak_tracker_testing - sha256: b06739349ec2477e943055aea30172c5c7000225f79dad4702e2ec0eda79a6ff - url: "https://pub.dev" - source: hosted - version: "1.0.5" lints: dependency: transitive description: @@ -236,18 +220,18 @@ packages: dependency: transitive description: name: material_color_utilities - sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.5.0" meta: dependency: transitive description: name: meta - sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 + sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.10.0" path: dependency: transitive description: @@ -297,7 +281,7 @@ packages: source: hosted version: "2.1.6" shared_preferences: - dependency: transitive + dependency: "direct main" description: name: shared_preferences sha256: "81429e4481e1ccfb51ede496e916348668fd0921627779233bd24cc3ff6abd02" @@ -485,22 +469,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" - vm_service: - dependency: transitive - description: - name: vm_service - sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 - url: "https://pub.dev" - source: hosted - version: "13.0.0" web: dependency: transitive description: name: web - sha256: edc8a9573dd8c5a83a183dae1af2b6fd4131377404706ca4e5420474784906fa + sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 url: "https://pub.dev" source: hosted - version: "0.4.0" + version: "0.3.0" win32: dependency: transitive description: diff --git a/babymeal/pubspec.yaml b/babymeal/pubspec.yaml index f3b1a65..4c8a3c7 100644 --- a/babymeal/pubspec.yaml +++ b/babymeal/pubspec.yaml @@ -15,6 +15,7 @@ dependencies: flutter_screenutil: ^5.9.0 emoji_picker_flutter: ^1.6.3 flutter_keyboard_visibility: ^5.4.1 + shared_preferences: ^2.2.2 dev_dependencies: flutter_test: @@ -58,3 +59,6 @@ flutter: - assets/images/scrab_full.png - assets/images/rectangle.png - assets/images/google.png + - assets/images/like.png + - assets/images/like_sel.png +