From 66cbeb50f23ed422f92246450a2c734b7d3ab2d2 Mon Sep 17 00:00:00 2001 From: gw282 Date: Sun, 10 Dec 2023 16:09:30 +0900 Subject: [PATCH 01/11] =?UTF-8?q?:sparkles:=20Feat:=20postFamilyIntereacti?= =?UTF-8?q?on=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 상호작용 보내는 flow 적용 --- assets/images/son.png | Bin 14425 -> 14056 bytes ...oller.dart => interaction_controller.dart} | 0 lib/main.dart | 2 +- lib/pages/home_page.dart | 276 ++++++++++-------- 4 files changed, 156 insertions(+), 122 deletions(-) rename lib/controllers/{user_controller.dart => interaction_controller.dart} (100%) diff --git a/assets/images/son.png b/assets/images/son.png index ec6bc52db11781fd6e73bd3f06139f27aa2962f0..6bbc0e666eb60f75232b3a4658dfed6c2ce9f6eb 100644 GIT binary patch literal 14056 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 CPD>R4 literal 14425 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 diff --git a/lib/controllers/user_controller.dart b/lib/controllers/interaction_controller.dart similarity index 100% rename from lib/controllers/user_controller.dart rename to lib/controllers/interaction_controller.dart diff --git a/lib/main.dart b/lib/main.dart index dbb169b..51b21fa 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -80,7 +80,7 @@ class FamStory extends StatelessWidget { routes: { // TODO: 로딩에서 가족 여부 체크 - '/': (context) => const LoadingScreen(), + '/': (context) => const RootPage(), // '/': (context) => const FamilyJoinPage(), diff --git a/lib/pages/home_page.dart b/lib/pages/home_page.dart index 1793b70..18c1005 100644 --- a/lib/pages/home_page.dart +++ b/lib/pages/home_page.dart @@ -2,10 +2,15 @@ import 'package:flutter/material.dart'; import 'package:fam_story_frontend/style.dart'; import 'package:flutter/services.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import '../models/family_member_model.dart'; import 'setting_page.dart'; import 'alarm_page.dart'; import 'package:fam_story_frontend/models/family_model.dart'; import 'package:fam_story_frontend/models/user_model.dart'; +import 'package:fam_story_frontend/models/family_interaction_model.dart'; +import 'package:fam_story_frontend/services/family_interaction_api_service.dart'; +import 'package:fam_story_frontend/services/family_member_api_service.dart'; + enum Interaction { thumbUp, thumbDown, heart, poke } @@ -21,6 +26,47 @@ class _HomePageState extends State { final TextEditingController _textEditingController = TextEditingController(); String myState = ''; + var myFamilyMemberId = 1; + + List familyMembers = [ + FamilyMemberModel( + familyMemberId: 2, + name: 'Jane Doe', + nickname: 'Janie', + role: 1, + pokeCount: 3, + talkCount: 8, + ), + FamilyMemberModel( + familyMemberId: 3, + name: 'Alice Doe', + nickname: 'Ally', + role: 2, + pokeCount: 2, + talkCount: 5, + ), + FamilyMemberModel( + familyMemberId: 4, + name: 'Bob Doe', + nickname: 'Bobby', + role: 3, + pokeCount: 4, + talkCount: 7, + ), + FamilyMemberModel( + familyMemberId: 4, + name: 'Bob Doe', + nickname: 'Bobby', + role: 4, + pokeCount: 4, + talkCount: 7, + ), + // Add more members as needed + ]; + + + + void interaction(Interaction data) { if (data == Interaction.thumbUp) { ScaffoldMessenger.of(context).showSnackBar(const SnackBar( @@ -116,7 +162,7 @@ class _HomePageState extends State { @override Widget build(BuildContext context) { - // family 수를 여기에 저장 + //familyId를 통해 받아온 list.length를 저장 int familyMember = 5; return SafeArea( @@ -181,72 +227,81 @@ class _HomePageState extends State { Container( width: 300, height: 300, - color: AppColor.swatchColor, - ), - - //FamilyMember round - if (familyMember == 5) ...[ - Positioned( - top: -120, - left: 170, - child: DragTarget( - builder: (context, candidateData, rejectedData) { - return FamilyMemberButton( - buttonSize: 0.28, - imageSize: 50, - memberImage: 'assets/images/mom.png', - onTap: () {}, - ); - }, - onAccept: (data) { - interaction(data); - }, + decoration: BoxDecoration( + color: AppColor.swatchColor, + borderRadius: BorderRadius.circular(15), + border: Border.all( + color: Colors.brown[200]!, // Adjust the color as needed + width: 3, // Adjust the width as needed ), ), - Positioned( - top: -120, - left: 30, - child: DragTarget( - builder: (context, candidateData, rejectedData) { - return FamilyMemberButton( - buttonSize: 0.28, - imageSize: 50, - memberImage: 'assets/images/dad.png', - onTap: () {}, - ); - }, - onAccept: (data) { - interaction(data); - }, + ), + + + + //familyId -> + // 0번 리스트 + Visibility( + visible: familyMember >= 2, + child: Positioned( + top: -120, + left: 30, + child: DragTarget( + builder: (context, candidateData, rejectedData) { + return FamilyMemberButton( + buttonSize: 0.28, + imageSize: 50, + memberImage: 'assets/images/dad.png', + onTap: () async { + int check = await FamilyInteractionApiService.postFamilyInteraction(familyMembers[0].familyMemberId,myFamilyMemberId,1); + }, + ); + }, + onAccept: (data) { + interaction(data); + }, + ), ), ), - Positioned( - top: 10, - left: -40, - child: DragTarget( - builder: (context, candidateData, rejectedData) { - return FamilyMemberButton( - buttonSize: 0.28, - imageSize: 50, - memberImage: 'assets/images/grandmother.png', - onTap: () {}, - ); - }, - onAccept: (data) { - interaction(data); - }, + // 1번 리스트 + Visibility( + visible: familyMember >= 3, + child: Positioned( + top: 10, + left: -40, + child: DragTarget( + builder: (context, candidateData, rejectedData) { + return FamilyMemberButton( + buttonSize: 0.28, + imageSize: 50, + memberImage: 'assets/images/grandmother.png', + onTap: () async { + }, + ); + }, + onAccept: (data) async { + interaction(data); + int check = await FamilyInteractionApiService.postFamilyInteraction(familyMembers[1].familyMemberId,myFamilyMemberId,1); + print('ho'); + }, + ), ), ), - Positioned( - top: 150, - left: -40, + // 2번 리스트 + Visibility( + visible: familyMember >= 4, + child: Positioned( + top: -120, + left: 170, child: DragTarget( builder: (context, candidateData, rejectedData) { return FamilyMemberButton( buttonSize: 0.28, imageSize: 50, - memberImage: 'assets/images/daughter.png', - onTap: () {}, + memberImage: 'assets/images/mom.png', + onTap: () async { + int check = await FamilyInteractionApiService.postFamilyInteraction(familyMembers[2].familyMemberId,myFamilyMemberId,1); + }, ); }, onAccept: (data) { @@ -254,82 +309,43 @@ class _HomePageState extends State { }, ), ), - ] else if (familyMember == 4) ...[ - Positioned( - top: -120, - left: 170, - child: FamilyMemberButton( - buttonSize: 0.36, - imageSize: 90, - memberImage: 'assets/images/son.png', - onTap: () {}, - ), - ), - Positioned( - top: -120, - left: 20, - child: FamilyMemberButton( - buttonSize: 0.36, - imageSize: 90, - memberImage: 'assets/images/son.png', - onTap: () {}, - ), - ), - Positioned( - top: 40, - left: -40, - child: FamilyMemberButton( - buttonSize: 0.32, - imageSize: 90, - memberImage: 'assets/images/son.png', - onTap: () {}, - ), - ), - ] else if (familyMember == 3) ...[ - Positioned( - top: -120, - left: 100, - child: FamilyMemberButton( - buttonSize: 0.36, - imageSize: 90, - memberImage: 'assets/images/son.png', - onTap: () {}, - ), - ), - Positioned( - top: 10, - left: -40, - child: FamilyMemberButton( - buttonSize: 0.36, - imageSize: 90, - memberImage: 'assets/images/son.png', - onTap: () {}, - ), - ), - ] else if (familyMember == 2) ...[ - Positioned( - top: -120, - left: -20, - child: FamilyMemberButton( - buttonSize: 0.4, - imageSize: 90, - memberImage: 'assets/images/son.png', - onTap: () {}, + ), + // 3번 리스트 + Visibility( + visible: familyMember >= 5, + child: Positioned( + top: 150, + left: -40, + child: DragTarget( + builder: (context, candidateData, rejectedData) { + return FamilyMemberButton( + buttonSize: 0.28, + imageSize: 50, + memberImage: 'assets/images/daughter.png', + onTap: () async { + int check = await FamilyInteractionApiService.postFamilyInteraction(familyMembers[3].familyMemberId,myFamilyMemberId,1); + print(familyMembers[3].familyMemberId); + print(myFamilyMemberId); + }, + ); + }, + onAccept: (data) { + interaction(data); + }, + ), ), ), - ] else - ...[], - //Me round Positioned( top: 100, left: 180, child: FamilyMemberButton( buttonSize: 0.4, imageSize: 90, - memberImage: 'assets/images/son.png', + memberImage: 'assets/images/mom.png', onTap: () { myStateDialog(context); + }, ), ), @@ -541,3 +557,21 @@ class SpeechBubble extends CustomPainter { return true; } } + +class FamilyMemberModel { + int familyMemberId; + String name; + String nickname; + int role; + int pokeCount; + int talkCount; + + FamilyMemberModel({ + required this.familyMemberId, + required this.name, + required this.nickname, + required this.role, + required this.pokeCount, + required this.talkCount, + }); +} \ No newline at end of file From 39be66252bbfeae1e3de64512fbccc354a3f8c6f Mon Sep 17 00:00:00 2001 From: Nam Jin Date: Mon, 11 Dec 2023 02:10:45 +0900 Subject: [PATCH 02/11] =?UTF-8?q?:sparkles:=20Feat=20:=20Provider=20?= =?UTF-8?q?=EB=B3=80=EC=88=98=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit feat : Provider 변수 적용 --- lib/di/provider/id_provider.dart | 16 +-- lib/main.dart | 3 +- lib/pages/home_page.dart | 223 +++++++++++++++++++----------- lib/pages/login_sign_up_page.dart | 16 ++- lib/pages/post_page.dart | 1 + lib/root_page.dart | 4 + pubspec.lock | 26 ++-- 7 files changed, 181 insertions(+), 108 deletions(-) diff --git a/lib/di/provider/id_provider.dart b/lib/di/provider/id_provider.dart index bc3aa48..a5a62d3 100644 --- a/lib/di/provider/id_provider.dart +++ b/lib/di/provider/id_provider.dart @@ -18,23 +18,23 @@ class IdProvider with ChangeNotifier { notifyListeners(); } - void setRole(int role) { - role = role; + void setRole(int ro) { + role = ro; notifyListeners(); } - void setName(String name) { - name = name; + void setName(String nam) { + name = nam; notifyListeners(); } - void setNicKName(String nickname) { - nickname = nickname; + void setNicKName(String nick) { + nickname = nick; notifyListeners(); } - void setIntroMessage(String introMessage) { - introMessage = introMessage; + void setIntroMessage(String message) { + introMessage = message; notifyListeners(); } } diff --git a/lib/main.dart b/lib/main.dart index 00e2dfe..eded89d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -83,8 +83,7 @@ class FamStory extends StatelessWidget { routes: { // TODO: 로딩에서 가족 여부 체크 - - '/': (context) => const RootPage(), + '/': (context) => const LoadingScreen(), // '/': (context) => const FamilyJoinPage(), diff --git a/lib/pages/home_page.dart b/lib/pages/home_page.dart index 8b3dddd..e474cd7 100644 --- a/lib/pages/home_page.dart +++ b/lib/pages/home_page.dart @@ -1,7 +1,10 @@ +import 'package:fam_story_frontend/pages/alarm_page.dart'; import 'package:flutter/material.dart'; import 'package:fam_story_frontend/style.dart'; import 'package:flutter/services.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:provider/provider.dart'; +import '../di/provider/id_provider.dart'; import '../models/family_member_model.dart'; import '../services/family_member_api_service.dart'; @@ -12,8 +15,19 @@ import 'package:fam_story_frontend/models/family_interaction_model.dart'; import 'package:fam_story_frontend/services/family_interaction_api_service.dart'; import 'package:fam_story_frontend/services/family_member_api_service.dart'; - -enum Interaction { thumbUp, thumbDown, heart, poke } +enum Interaction { + thumbUp, + thumbDown, + heart, + poke; + + int get title => const { + Interaction.thumbUp: 1, + Interaction.thumbDown: 2, + Interaction.heart: 3, + Interaction.poke: 4, + }[this]!; +} class HomePage extends StatefulWidget { const HomePage({super.key}); @@ -26,16 +40,35 @@ class _HomePageState extends State { final _formKey = GlobalKey(); final TextEditingController _textEditingController = TextEditingController(); String myState = ''; - - var myFamilyMemberId = 1; + late Future> _allFamilyMember; + int familyId = 0; + int familyMemberID = 0; + int familyMemberNum = 0; List familyMembers = [ - // Add more members as needed ]; + @override + void initState() { + super.initState(); + _initData(); + } - + Future _initData() async { + familyId = context.read().familyId; + familyMemberID = context.read().familyMemberId; + + _allFamilyMember = FamilyMemberApiService.getAllFamilyMember(familyId); + _allFamilyMember.then((value) { + setState(() { + familyMembers = value; + familyMembers + .removeWhere((element) => element.familyMemberId == familyMemberID); + familyMemberNum = familyMembers.length; + }); + }); + } void interaction(Interaction data) { if (data == Interaction.thumbUp) { @@ -57,6 +90,25 @@ class _HomePageState extends State { } } + String getRoleImage(int role) { + switch (role) { + case 1: + return 'assets/images/grandfather.png'; + case 2: + return 'assets/images/dad.png'; + case 3: + return 'assets/images/son.png'; + case 4: + return 'assets/images/grandmother.png'; + case 5: + return 'assets/images/mom.png'; + case 6: + return 'assets/images/daughter.png'; + default: + return 'assets/images/son.png'; + } + } + void myStateDialog(BuildContext context) async { await showDialog( context: context, @@ -132,9 +184,6 @@ class _HomePageState extends State { @override Widget build(BuildContext context) { - //familyId를 통해 받아온 list.length를 저장 - int familyMember = 5; - return SafeArea( child: Center( child: Column( @@ -161,7 +210,13 @@ class _HomePageState extends State { Row( children: [ IconButton( - onPressed: () {}, + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => AlarmPage()), + ); + }, icon: const Icon(Icons.alarm_on), color: AppColor.swatchColor, iconSize: 35), @@ -198,64 +253,69 @@ class _HomePageState extends State { borderRadius: BorderRadius.circular(15), border: Border.all( color: Colors.brown[200]!, // Adjust the color as needed - width: 3, // Adjust the width as needed + width: 5, // Adjust the width as needed ), ), ), - - //familyId -> // 0번 리스트 Visibility( - visible: familyMember >= 2, - child: Positioned( - top: -120, - left: 30, - child: DragTarget( - builder: (context, candidateData, rejectedData) { - return FamilyMemberButton( - buttonSize: 0.28, - imageSize: 50, - memberImage: 'assets/images/dad.png', - onTap: () async { - int check = await FamilyInteractionApiService.postFamilyInteraction(familyMembers[0].familyMemberId,myFamilyMemberId,1); - }, - ); - }, - onAccept: (data) { - interaction(data); - }, - ), + visible: familyMemberNum >= 1, + child: Positioned( + top: -120, + left: 30, + child: DragTarget( + builder: (context, candidateData, rejectedData) { + return FamilyMemberButton( + buttonSize: 0.28, + imageSize: 50, + memberImage: getRoleImage(familyMembers[0].role), + onTap: () async { + int check = await FamilyInteractionApiService + .postFamilyInteraction( + familyMembers[0].familyMemberId, + familyMemberID, + 1); + }, + ); + }, + onAccept: (data) { + interaction(data); + }, ), ), + ), // 1번 리스트 Visibility( - visible: familyMember >= 3, - child: Positioned( - top: 10, - left: -40, - child: DragTarget( - builder: (context, candidateData, rejectedData) { - return FamilyMemberButton( - buttonSize: 0.28, - imageSize: 50, - memberImage: 'assets/images/grandmother.png', - onTap: () async { - }, - ); - }, - onAccept: (data) async { - interaction(data); - int check = await FamilyInteractionApiService.postFamilyInteraction(familyMembers[1].familyMemberId,myFamilyMemberId,1); - print('ho'); - }, - ), + visible: familyMemberNum >= 2, + child: Positioned( + top: 10, + left: -40, + child: DragTarget( + builder: (context, candidateData, rejectedData) { + return FamilyMemberButton( + buttonSize: 0.28, + imageSize: 50, + memberImage: getRoleImage(familyMembers[1].role), + onTap: () async {}, + ); + }, + onAccept: (data) async { + interaction(data); + int check = await FamilyInteractionApiService + .postFamilyInteraction( + familyMembers[1].familyMemberId, + familyMemberID, + 1); + print('ho'); + }, ), ), + ), // 2번 리스트 Visibility( - visible: familyMember >= 4, + visible: familyMemberNum >= 3, child: Positioned( top: -120, left: 170, @@ -264,9 +324,13 @@ class _HomePageState extends State { return FamilyMemberButton( buttonSize: 0.28, imageSize: 50, - memberImage: 'assets/images/mom.png', + memberImage: getRoleImage(familyMembers[2].role), onTap: () async { - int check = await FamilyInteractionApiService.postFamilyInteraction(familyMembers[2].familyMemberId,myFamilyMemberId,1); + int check = await FamilyInteractionApiService + .postFamilyInteraction( + familyMembers[2].familyMemberId, + familyMemberID, + 1); //FamilyMemberApi 테스트 /* @@ -297,29 +361,33 @@ class _HomePageState extends State { ), // 3번 리스트 Visibility( - visible: familyMember >= 5, - child: Positioned( - top: 150, - left: -40, - child: DragTarget( - builder: (context, candidateData, rejectedData) { - return FamilyMemberButton( - buttonSize: 0.28, - imageSize: 50, - memberImage: 'assets/images/daughter.png', - onTap: () async { - int check = await FamilyInteractionApiService.postFamilyInteraction(familyMembers[3].familyMemberId,myFamilyMemberId,1); - print(familyMembers[3].familyMemberId); - print(myFamilyMemberId); - }, - ); - }, - onAccept: (data) { - interaction(data); - }, - ), + visible: familyMemberNum >= 4, + child: Positioned( + top: 150, + left: -40, + child: DragTarget( + builder: (context, candidateData, rejectedData) { + return FamilyMemberButton( + buttonSize: 0.28, + imageSize: 50, + memberImage: getRoleImage(familyMembers[3].role), + onTap: () async { + int check = await FamilyInteractionApiService + .postFamilyInteraction( + familyMembers[3].familyMemberId, + familyMemberID, + 1); + print(familyMembers[3].familyMemberId); + print(familyMemberID); + }, + ); + }, + onAccept: (data) { + interaction(data); + }, ), ), + ), Positioned( top: 100, @@ -327,10 +395,9 @@ class _HomePageState extends State { child: FamilyMemberButton( buttonSize: 0.4, imageSize: 90, - memberImage: 'assets/images/mom.png', + memberImage: getRoleImage(context.read().role), onTap: () { myStateDialog(context); - }, ), ), diff --git a/lib/pages/login_sign_up_page.dart b/lib/pages/login_sign_up_page.dart index 2d14b34..fb52a37 100644 --- a/lib/pages/login_sign_up_page.dart +++ b/lib/pages/login_sign_up_page.dart @@ -520,13 +520,15 @@ class _LoginSignUpPageState extends State { const FamilyJoinCreatePage())); } else { Navigator.pushReplacement( - context, - MaterialPageRoute( - builder: (context) => - ChangeNotifierProvider( - create: (context) => IdProvider(), - child: const RootPage(), - ))); + context, + MaterialPageRoute( + builder: (context) => ChangeNotifierProvider( + create: (context) => + IdProvider(), // 아니면 value: IdProvider() 로도 가능 + child: const RootPage(), + ), + ), + ); } } catch (e) { // TODO: 에러 내용 알려주기 diff --git a/lib/pages/post_page.dart b/lib/pages/post_page.dart index e82faf7..65ae91d 100644 --- a/lib/pages/post_page.dart +++ b/lib/pages/post_page.dart @@ -39,6 +39,7 @@ class _PostPageState extends State { familyMemberId = context.watch().familyMemberId; print('familyId: $familyId'); print('familyMemberId: $familyMemberId'); + print(context.watch().nickname); postList = PostApiService.getPostList(familyId); return SingleChildScrollView( child: Column( diff --git a/lib/root_page.dart b/lib/root_page.dart index 231ec94..37fb0c6 100644 --- a/lib/root_page.dart +++ b/lib/root_page.dart @@ -56,6 +56,10 @@ class _RootPageState extends State { _familyId = value.familyId; context.read().setFamilyMemberId(_familyMemberId); context.read().setFamilyId(_familyId); + context.read().setRole(_role); + context.read().setName(_name); + context.read().setNicKName(_nickname); + context.read().setIntroMessage(_introMessage); }); }); } diff --git a/pubspec.lock b/pubspec.lock index 93cb832..cfa72de 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -53,10 +53,10 @@ packages: dependency: transitive description: name: collection - sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dev" source: hosted - version: "1.17.2" + version: "1.18.0" crypto: dependency: transitive description: @@ -340,10 +340,10 @@ packages: dependency: transitive description: name: meta - sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.10.0" nested: dependency: transitive description: @@ -481,18 +481,18 @@ packages: dependency: transitive description: name: stack_trace - sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.11.1" stream_channel: dependency: transitive description: name: stream_channel - sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" string_scanner: dependency: transitive description: @@ -513,10 +513,10 @@ packages: dependency: transitive description: name: test_api - sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" + sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" url: "https://pub.dev" source: hosted - version: "0.6.0" + version: "0.6.1" timezone: dependency: transitive description: @@ -545,10 +545,10 @@ packages: dependency: transitive description: name: web - sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 + sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 url: "https://pub.dev" source: hosted - version: "0.1.4-beta" + version: "0.3.0" web_socket_channel: dependency: "direct main" description: @@ -582,5 +582,5 @@ packages: source: hosted version: "6.3.0" sdks: - dart: ">=3.1.0 <4.0.0" + dart: ">=3.2.0-194.0.dev <4.0.0" flutter: ">=3.7.0" From 38a6231a349122dd127aa6608600d38d73e41a1e Mon Sep 17 00:00:00 2001 From: Nam Jin Date: Mon, 11 Dec 2023 03:33:48 +0900 Subject: [PATCH 03/11] =?UTF-8?q?:sparkles:=20Feat=20:=20Provider=EB=A1=9C?= =?UTF-8?q?=20=EC=A0=84=EC=B2=B4=20=EC=95=B1=20=EA=B0=90=EC=8B=B8=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit feat : Provider로 전체 앱 감싸기 --- lib/main.dart | 7 +++++- lib/pages/alarm_page.dart | 39 +++++++++++++++++++------------ lib/pages/home_page.dart | 6 +++-- lib/pages/login_sign_up_page.dart | 6 +---- 4 files changed, 35 insertions(+), 23 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index eded89d..8b0f9dd 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -65,7 +65,12 @@ Future main() async { ); initializeNotification(); - runApp(const FamStory()); + runApp( + ChangeNotifierProvider( + create: (context) => IdProvider(), + child: const FamStory(), + ), + ); } class FamStory extends StatelessWidget { diff --git a/lib/pages/alarm_page.dart b/lib/pages/alarm_page.dart index b89488b..82460fc 100644 --- a/lib/pages/alarm_page.dart +++ b/lib/pages/alarm_page.dart @@ -4,6 +4,9 @@ import 'package:flutter/material.dart'; import 'package:fam_story_frontend/style.dart'; import 'package:fam_story_frontend/models/user_model.dart'; import 'package:fam_story_frontend/models/family_interaction_model.dart'; +import 'package:provider/provider.dart'; + +import '../di/provider/id_provider.dart'; class AlarmPage extends StatefulWidget { const AlarmPage({Key? key}) : super(key: key); @@ -13,15 +16,18 @@ class AlarmPage extends StatefulWidget { } class _AlarmPageState extends State with TickerProviderStateMixin { - String buttonText = 'Clear'; List interactions = []; - - + int familyIDs = 0; @override Widget build(BuildContext context) { + //int familyIDs = Provider.of(context, listen: false).familyId; + IdProvider x = Provider.of(context); + //int familyIDs = context.read().familyMemberId; + familyIDs = x.familyId; + print(familyIDs); return Scaffold( appBar: PreferredSize( preferredSize: const Size.fromHeight(50.0), @@ -55,11 +61,17 @@ class _AlarmPageState extends State with TickerProviderStateMixin { children: [ Text( "Recognize", - style: TextStyle(color: AppColor.textColor, fontSize: 40, fontWeight: FontWeight.bold), + style: TextStyle( + color: AppColor.textColor, + fontSize: 40, + fontWeight: FontWeight.bold), ), Text( "Hear Family's Reactions", - style: TextStyle(color: AppColor.textColor, fontSize: 20, fontWeight: FontWeight.bold), + style: TextStyle( + color: AppColor.textColor, + fontSize: 20, + fontWeight: FontWeight.bold), ) ], ), @@ -72,7 +84,8 @@ class _AlarmPageState extends State with TickerProviderStateMixin { child: Container( constraints: BoxConstraints(maxHeight: 480), margin: const EdgeInsetsDirectional.fromSTEB(20, 20, 20, 20), - padding: const EdgeInsets.only(top:20.0, bottom: 20, left: 15, right: 15), + padding: const EdgeInsets.only( + top: 20.0, bottom: 20, left: 15, right: 15), decoration: BoxDecoration( color: AppColor.objectColor, borderRadius: BorderRadius.circular(15.0), @@ -95,11 +108,13 @@ class _AlarmPageState extends State with TickerProviderStateMixin { physics: NeverScrollableScrollPhysics(), itemCount: interactions.length, itemBuilder: (BuildContext context, int index) { - final item = interactions[interactions.length - 1 - index]; + final item = + interactions[interactions.length - 1 - index]; bool isChecked = item.isChecked ?? false; return Container( height: 60, - color: isChecked ? Colors.white: Colors.grey[200], + color: + isChecked ? Colors.white : Colors.grey[200], child: Row( children: [ SizedBox(width: 10), @@ -135,7 +150,6 @@ class _AlarmPageState extends State with TickerProviderStateMixin { ), ], ), - ); }, ), @@ -147,9 +161,6 @@ class _AlarmPageState extends State with TickerProviderStateMixin { ), ), ), - - - Positioned( left: 0, right: 0, @@ -166,10 +177,8 @@ class _AlarmPageState extends State with TickerProviderStateMixin { } catch (e) { print(e.toString()); } - setState(() { - }); + setState(() {}); }, - style: ElevatedButton.styleFrom( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(35), diff --git a/lib/pages/home_page.dart b/lib/pages/home_page.dart index e474cd7..964d069 100644 --- a/lib/pages/home_page.dart +++ b/lib/pages/home_page.dart @@ -184,6 +184,7 @@ class _HomePageState extends State { @override Widget build(BuildContext context) { + print(familyId); return SafeArea( child: Center( child: Column( @@ -214,7 +215,8 @@ class _HomePageState extends State { Navigator.push( context, MaterialPageRoute( - builder: (context) => AlarmPage()), + builder: (context) => const AlarmPage(), + ), ); }, icon: const Icon(Icons.alarm_on), @@ -225,7 +227,7 @@ class _HomePageState extends State { Navigator.push( context, MaterialPageRoute( - builder: (context) => SettingPage()), + builder: (context) => const SettingPage()), ); }, icon: const Icon(Icons.settings), diff --git a/lib/pages/login_sign_up_page.dart b/lib/pages/login_sign_up_page.dart index fb52a37..05d4480 100644 --- a/lib/pages/login_sign_up_page.dart +++ b/lib/pages/login_sign_up_page.dart @@ -522,11 +522,7 @@ class _LoginSignUpPageState extends State { Navigator.pushReplacement( context, MaterialPageRoute( - builder: (context) => ChangeNotifierProvider( - create: (context) => - IdProvider(), // 아니면 value: IdProvider() 로도 가능 - child: const RootPage(), - ), + builder: (context) => const RootPage(), ), ); } From c35df5dfd9f7a0adf85b3c72d185b50d3d781bd3 Mon Sep 17 00:00:00 2001 From: Nam Jin Date: Mon, 11 Dec 2023 05:17:28 +0900 Subject: [PATCH 04/11] =?UTF-8?q?:sparkles:=20Feat=20:=20FamilyMember=20In?= =?UTF-8?q?teraction=20=EC=86=A1=EC=8B=A0=20(#84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 페밀리 불러오기 및 상호작용 송신 구현 완료 --- lib/models/family_interaction_model.dart | 3 +- lib/pages/alarm_page.dart | 7 +- lib/pages/home_page.dart | 100 ++++++------------ lib/root_page.dart | 93 ++++++++++------ .../family_interaction_api_service.dart | 2 +- 5 files changed, 96 insertions(+), 109 deletions(-) diff --git a/lib/models/family_interaction_model.dart b/lib/models/family_interaction_model.dart index ae63d4c..f67869e 100644 --- a/lib/models/family_interaction_model.dart +++ b/lib/models/family_interaction_model.dart @@ -1,6 +1,5 @@ class FamilyInteractionModel { - final int interactionId, srcMemberId, dstMemberId, interactionType; - final bool isChecked; + final int interactionId, srcMemberId, dstMemberId, interactionType, isChecked; FamilyInteractionModel.fromJson(Map json) : interactionId = json['interactionId'], diff --git a/lib/pages/alarm_page.dart b/lib/pages/alarm_page.dart index 82460fc..72fda5e 100644 --- a/lib/pages/alarm_page.dart +++ b/lib/pages/alarm_page.dart @@ -110,11 +110,12 @@ class _AlarmPageState extends State with TickerProviderStateMixin { itemBuilder: (BuildContext context, int index) { final item = interactions[interactions.length - 1 - index]; - bool isChecked = item.isChecked ?? false; + int isChecked = item.isChecked ?? 0; return Container( height: 60, - color: - isChecked ? Colors.white : Colors.grey[200], + color: isChecked == 1 + ? Colors.white + : Colors.grey[200], child: Row( children: [ SizedBox(width: 10), diff --git a/lib/pages/home_page.dart b/lib/pages/home_page.dart index 964d069..6df892f 100644 --- a/lib/pages/home_page.dart +++ b/lib/pages/home_page.dart @@ -70,23 +70,30 @@ class _HomePageState extends State { }); } - void interaction(Interaction data) { - if (data == Interaction.thumbUp) { - ScaffoldMessenger.of(context).showSnackBar(const SnackBar( - content: Text('thumb up'), - )); - } else if (data == Interaction.thumbDown) { - ScaffoldMessenger.of(context).showSnackBar(const SnackBar( - content: Text('thumb down'), - )); - } else if (data == Interaction.heart) { - ScaffoldMessenger.of(context).showSnackBar(const SnackBar( - content: Text('heart'), - )); - } else if (data == Interaction.poke) { - ScaffoldMessenger.of(context).showSnackBar(const SnackBar( - content: Text('poke'), - )); + Future interaction(Interaction data, int familyMemberIDNum) async { + await FamilyInteractionApiService.postFamilyInteraction( + familyMemberID, familyMemberIDNum, data.title); + switch (data.title) { + case 1: + ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + content: Text('thumb up'), + )); + case 2: + ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + content: Text('thumb down'), + )); + case 3: + ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + content: Text('heart'), + )); + case 4: + ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + content: Text('poke'), + )); + default: + ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + content: Text('NO'), + )); } } @@ -273,17 +280,11 @@ class _HomePageState extends State { buttonSize: 0.28, imageSize: 50, memberImage: getRoleImage(familyMembers[0].role), - onTap: () async { - int check = await FamilyInteractionApiService - .postFamilyInteraction( - familyMembers[0].familyMemberId, - familyMemberID, - 1); - }, + onTap: () async {}, ); }, onAccept: (data) { - interaction(data); + interaction(data, familyMembers[0].familyMemberId); }, ), ), @@ -304,13 +305,7 @@ class _HomePageState extends State { ); }, onAccept: (data) async { - interaction(data); - int check = await FamilyInteractionApiService - .postFamilyInteraction( - familyMembers[1].familyMemberId, - familyMemberID, - 1); - print('ho'); + interaction(data, familyMembers[1].familyMemberId); }, ), ), @@ -327,36 +322,11 @@ class _HomePageState extends State { buttonSize: 0.28, imageSize: 50, memberImage: getRoleImage(familyMembers[2].role), - onTap: () async { - int check = await FamilyInteractionApiService - .postFamilyInteraction( - familyMembers[2].familyMemberId, - familyMemberID, - 1); - - //FamilyMemberApi 테스트 - /* - print(await FamilyMemberApiService.putFamilyMember( - 15, 1, "하잉")); - List x = - await FamilyMemberApiService.getAllFamilyMember( - 13); - for (var member in x) { - print(member.familyMemberId); - print(member.talkCount); - print(member.pokeCount); - print(member.name); - print(member.nickname); - print(member.role); - print(member.introMessage); - } - - */ - }, + onTap: () async {}, ); }, onAccept: (data) { - interaction(data); + interaction(data, familyMembers[2].familyMemberId); }, ), ), @@ -373,19 +343,11 @@ class _HomePageState extends State { buttonSize: 0.28, imageSize: 50, memberImage: getRoleImage(familyMembers[3].role), - onTap: () async { - int check = await FamilyInteractionApiService - .postFamilyInteraction( - familyMembers[3].familyMemberId, - familyMemberID, - 1); - print(familyMembers[3].familyMemberId); - print(familyMemberID); - }, + onTap: () async {}, ); }, onAccept: (data) { - interaction(data); + interaction(data, familyMembers[3].familyMemberId); }, ), ), diff --git a/lib/root_page.dart b/lib/root_page.dart index 37fb0c6..4c0d79a 100644 --- a/lib/root_page.dart +++ b/lib/root_page.dart @@ -7,6 +7,7 @@ import 'package:fam_story_frontend/pages/home_page.dart'; import 'package:fam_story_frontend/pages/post_page.dart'; import 'package:fam_story_frontend/services/family_member_api_service.dart'; import 'package:fam_story_frontend/style.dart'; +import 'package:fam_story_frontend/widgets/loading_indicator.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'style.dart'; @@ -39,8 +40,8 @@ class _RootPageState extends State { @override void initState() { super.initState(); - // Future.microtask(() => _initData()); - _initData(); + //Future.microtask(() => _initData()); + _initData().then((_) {}); } Future _initData() async { @@ -64,40 +65,64 @@ class _RootPageState extends State { }); } + bool flag = false; @override Widget build(BuildContext context) { - return Scaffold( - appBar: PreferredSize( - preferredSize: const Size.fromHeight(40.0), - child: AppBar( - backgroundColor: AppColor.backgroudColor, - ), - ), - backgroundColor: AppColor.backgroudColor, - body: _pages[_selectedIndex], - bottomNavigationBar: BottomNavigationBar( - type: BottomNavigationBarType.fixed, - backgroundColor: AppColor.objectColor, - selectedItemColor: AppColor.swatchColor, - unselectedItemColor: Colors.grey.withOpacity(0.7), - selectedLabelStyle: const TextStyle(color: AppColor.textColor), - currentIndex: _selectedIndex, - items: const [ - BottomNavigationBarItem( - icon: Icon(Icons.home_rounded), label: 'Home'), - BottomNavigationBarItem( - icon: Icon(Icons.question_answer_outlined), label: 'Chat'), - BottomNavigationBarItem( - icon: Icon(Icons.sticky_note_2_outlined), label: 'Post'), - BottomNavigationBarItem( - icon: Icon(Icons.calendar_today_rounded), label: 'Calendar'), - ], - onTap: (index) { - setState(() { - _selectedIndex = index; - }); - }, - ), + return FutureBuilder( + future: Future.delayed( + Duration(seconds: flag ? 0 : 1), () => _pages[_selectedIndex]), + builder: (BuildContext context, AsyncSnapshot snapshot) { + switch (snapshot.connectionState) { + case ConnectionState.none: + case ConnectionState.active: + case ConnectionState.waiting: + // 처음 한 번만 1초 텀 주는 부분 + return Scaffold( + backgroundColor: AppColor.backgroudColor, + body: Center( + child: LoadingIndicator(), + ), + ); + case ConnectionState.done: + if (snapshot.hasError) return Text('Error: ${snapshot.error}'); + return Scaffold( + appBar: PreferredSize( + preferredSize: const Size.fromHeight(40.0), + child: AppBar( + backgroundColor: AppColor.backgroudColor, + ), + ), + backgroundColor: AppColor.backgroudColor, + body: snapshot.data, + bottomNavigationBar: BottomNavigationBar( + type: BottomNavigationBarType.fixed, + backgroundColor: AppColor.objectColor, + selectedItemColor: AppColor.swatchColor, + unselectedItemColor: Colors.grey.withOpacity(0.7), + selectedLabelStyle: const TextStyle(color: AppColor.textColor), + currentIndex: _selectedIndex, + items: const [ + BottomNavigationBarItem( + icon: Icon(Icons.home_rounded), label: 'Home'), + BottomNavigationBarItem( + icon: Icon(Icons.question_answer_outlined), + label: 'Chat'), + BottomNavigationBarItem( + icon: Icon(Icons.sticky_note_2_outlined), label: 'Post'), + BottomNavigationBarItem( + icon: Icon(Icons.calendar_today_rounded), + label: 'Calendar'), + ], + onTap: (index) { + setState(() { + flag = true; + _selectedIndex = index; + }); + }, + ), + ); + } + }, ); } } diff --git a/lib/services/family_interaction_api_service.dart b/lib/services/family_interaction_api_service.dart index b7f3662..d9bef55 100644 --- a/lib/services/family_interaction_api_service.dart +++ b/lib/services/family_interaction_api_service.dart @@ -43,7 +43,7 @@ class FamilyInteractionApiService { ); // 상호작용 전송 완료 - if (response.statusCode == 200) { + if (response.statusCode == 201) { print(jsonDecode(response.body)['message']); int interactionId = jsonDecode(response.body)['data']; return interactionId; From 2b15187ab7ef6aae1be5dd6dc04fba14022dc9a0 Mon Sep 17 00:00:00 2001 From: gw282 Date: Mon, 11 Dec 2023 06:06:37 +0900 Subject: [PATCH 05/11] =?UTF-8?q?:sparkles:=20Feat:=20=EC=95=8C=EB=A6=BC?= =?UTF-8?q?=EC=B0=BD=20API=20=EC=97=B0=EB=8F=99=20=EB=B0=8F=20=EC=95=8C?= =?UTF-8?q?=EB=A6=BC=20=EC=82=AD=EC=A0=9C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit feat: 알림창 API 연동 및 알림 삭제 구현 --- lib/main.dart | 2 +- lib/models/family_interaction_model.dart | 3 +- lib/pages/alarm_page.dart | 190 ++++++++++++++++------- 3 files changed, 134 insertions(+), 61 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 8b0f9dd..f87cc84 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -88,7 +88,7 @@ class FamStory extends StatelessWidget { routes: { // TODO: 로딩에서 가족 여부 체크 - '/': (context) => const LoadingScreen(), + '/': (context) => const LoginSignUpPage(), // '/': (context) => const FamilyJoinPage(), diff --git a/lib/models/family_interaction_model.dart b/lib/models/family_interaction_model.dart index ae63d4c..f67869e 100644 --- a/lib/models/family_interaction_model.dart +++ b/lib/models/family_interaction_model.dart @@ -1,6 +1,5 @@ class FamilyInteractionModel { - final int interactionId, srcMemberId, dstMemberId, interactionType; - final bool isChecked; + final int interactionId, srcMemberId, dstMemberId, interactionType, isChecked; FamilyInteractionModel.fromJson(Map json) : interactionId = json['interactionId'], diff --git a/lib/pages/alarm_page.dart b/lib/pages/alarm_page.dart index 82460fc..4829be6 100644 --- a/lib/pages/alarm_page.dart +++ b/lib/pages/alarm_page.dart @@ -7,6 +7,8 @@ import 'package:fam_story_frontend/models/family_interaction_model.dart'; import 'package:provider/provider.dart'; import '../di/provider/id_provider.dart'; +import '../models/family_member_model.dart'; +import '../services/family_interaction_api_service.dart'; class AlarmPage extends StatefulWidget { const AlarmPage({Key? key}) : super(key: key); @@ -18,16 +20,28 @@ class AlarmPage extends StatefulWidget { class _AlarmPageState extends State with TickerProviderStateMixin { String buttonText = 'Clear'; - List interactions = []; - int familyIDs = 0; + late Future> interactions; + late Future _familyMember; + int familyMemberId = 0; + int _role = 0; + String _nickname = ''; + + @override + void initState() { + super.initState(); + } + + Future _updateInteractions(int id) async { + _familyMember = FamilyMemberApiService.getFamilyMemberID(id); + _familyMember.then((value) { + _role = value.role; + _nickname = value.nickname;} + ); + } @override Widget build(BuildContext context) { - //int familyIDs = Provider.of(context, listen: false).familyId; - IdProvider x = Provider.of(context); - //int familyIDs = context.read().familyMemberId; - familyIDs = x.familyId; - print(familyIDs); + familyMemberId = context.watch().familyMemberId; return Scaffold( appBar: PreferredSize( preferredSize: const Size.fromHeight(50.0), @@ -102,59 +116,70 @@ class _AlarmPageState extends State with TickerProviderStateMixin { crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( - child: Form( - child: ListView.builder( - shrinkWrap: true, - physics: NeverScrollableScrollPhysics(), - itemCount: interactions.length, - itemBuilder: (BuildContext context, int index) { - final item = - interactions[interactions.length - 1 - index]; - bool isChecked = item.isChecked ?? false; + child: FutureBuilder>( + future: FamilyInteractionApiService.getFamilyInteraction(familyMemberId), // Replace with your actual data-fetching method + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + // While data is being fetched, show a loading indicator + return CircularProgressIndicator(); + } else if (snapshot.hasError) { + // If there's an error, display an error message + return Text('Error: ${snapshot.error}'); + } else if (!snapshot.hasData || snapshot.data!.isEmpty) { + // If no data is available, display a message indicating no interactions return Container( - height: 60, - color: - isChecked ? Colors.white : Colors.grey[200], - child: Row( - children: [ - SizedBox(width: 10), - CircleAvatar( - radius: 20, - backgroundColor: Colors.blue, // 도형의 배경색 - child: Icon( - Icons.person, // 아이콘 등을 넣어줄 수 있습니다. - color: Colors.white, // 아이콘의 색상 - ), - ), - SizedBox(width: 10), - CircleAvatar( - radius: 12, - backgroundColor: Colors.blue, // 도형의 배경색 - child: ClipOval( - child: Image.asset( - 'assets/images/heart.png', // 이미지 URL로 변경 - width: 24, - height: 24, - fit: BoxFit.cover, + height: 450, + child: Center(child: Text('No Reactions yet.'))); + } else { + // Data has been successfully fetched, display the interactions + List interactions = snapshot.data!; + return ListView.builder( + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + itemCount: interactions.length, + itemBuilder: (BuildContext context, int index) { + final item = interactions[interactions.length - 1 - index]; + bool isChecked = item.isChecked == 0; + + _updateInteractions(item.srcMemberId); + + return Container( + height: 60, + color: isChecked ? Colors.white : Colors.grey[200], + child: Row( + children: [ + SizedBox(width: 10), + CircleAvatar( + radius: 20, + backgroundColor: Colors.blue, ), - ), - ), - SizedBox(width: 10), // 도형과 텍스트 간격 조절 - Text( - "${item.srcMemberId}님이 당신을 ${item.interactionType}했어요.", - style: TextStyle( - color: Colors.black, - fontWeight: FontWeight.bold, - fontSize: 14, - ), + SizedBox(width: 10), + CircleAvatar( + radius: 12, + backgroundColor: Colors.blue, + child: ClipOval( + child: getImageForInteractionType(item.interactionType), + ), + ), + SizedBox(width: 10), + Text( + "${_nickname} sends you a ${getInteractionTypeText(item.interactionType)}.", + style: TextStyle( + color: Colors.black, + fontWeight: FontWeight.bold, + fontSize: 14, + ), + ), + ], ), - ], - ), + ); + }, ); - }, - ), + } + }, ), - ), + ) + ], ), ), @@ -171,9 +196,8 @@ class _AlarmPageState extends State with TickerProviderStateMixin { ElevatedButton( onPressed: () async { try { - // Access user input values - - // TODO: API 연결, 가족 멤버 생성, 가족 ID 가져오기 + FamilyInteractionApiService.deleteFamilyInteraction(familyMemberId); + Navigator.pop(context); } catch (e) { print(e.toString()); } @@ -202,4 +226,54 @@ class _AlarmPageState extends State with TickerProviderStateMixin { ), ); } + String getInteractionTypeText(int interactionType) { + switch (interactionType) { + case 1: + return "Thumbs-Up"; + case 2: + return "Thumbs-Down"; + case 3: + return "Heart"; + case 4: + return "Poke"; + default: + return "unclassified"; + } + } + + Widget getImageForInteractionType(int interactionType) { + switch (interactionType) { + case 1: + return Image.asset( + 'assets/images/thumbup.png', + width: 24, + height: 24, + fit: BoxFit.cover, + ); + case 2: + return Image.asset( + 'assets/images/thumbdown.png', // 싫어요 이미지에 대한 경로 + width: 24, + height: 24, + fit: BoxFit.cover, + ); + case 3: + return Image.asset( + 'assets/images/heart.png', // 훈훈해요 이미지에 대한 경로 + width: 24, + height: 24, + fit: BoxFit.cover, + ); + case 4: + return Image.asset( + 'assets/images/poke.png', // 슬퍼요 이미지에 대한 경로 + width: 24, + height: 24, + fit: BoxFit.cover, + ); + default: + return Container(); // 기본적으로 빈 컨테이너를 반환하거나 다른 기본 이미지를 설정할 수 있습니다. + } + } + } From 4f64e5e6cc17ac6bd6bbedfc6b8b3a7c9a272544 Mon Sep 17 00:00:00 2001 From: gw282 Date: Mon, 11 Dec 2023 06:24:54 +0900 Subject: [PATCH 06/11] =?UTF-8?q?:sparkles:=20Feat:=20=EC=83=81=ED=98=B8?= =?UTF-8?q?=EC=9E=91=EC=9A=A9=EC=9D=84=20fcm=20=EC=95=8C=EB=A6=BC=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=ED=91=9C=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit feat: 상호작용을 fcm 알림으로 표시 --- lib/root_page.dart | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/lib/root_page.dart b/lib/root_page.dart index 37fb0c6..f926334 100644 --- a/lib/root_page.dart +++ b/lib/root_page.dart @@ -9,6 +9,8 @@ import 'package:fam_story_frontend/services/family_member_api_service.dart'; import 'package:fam_story_frontend/style.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import 'package:firebase_messaging/firebase_messaging.dart'; +import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'style.dart'; class RootPage extends StatefulWidget { @@ -36,11 +38,43 @@ class _RootPageState extends State { const CalendarPage() ]; + var messagetitle = ""; + var messagebody = ""; + void getMyDeviceToken() async { + final token = await FirebaseMessaging.instance.getToken(); + print("내 디바이스 토큰: $token"); + } + @override void initState() { super.initState(); // Future.microtask(() => _initData()); _initData(); + + getMyDeviceToken(); + FirebaseMessaging.onMessage.listen((RemoteMessage message) async { + RemoteNotification? notification = message.notification; + if (notification != null) { + FlutterLocalNotificationsPlugin().show( + notification.hashCode, + notification.title, + notification.body, + const NotificationDetails( + android: AndroidNotificationDetails( + 'high_importance_channel', + 'high_importance_notification', + importance: Importance.max, + ), + ), + ); + setState(() { + messagetitle = message.notification!.title!; + messagebody = message.notification!.body!; + print("Foreground 메시지 제목: $messagetitle"); + print("Foreground 메시지 내용: $messagebody"); + }); + } + }); } Future _initData() async { From 0775ca27c7ec880f4b6af63865b48e9c64c47b3e Mon Sep 17 00:00:00 2001 From: gw282 Date: Mon, 11 Dec 2023 06:33:50 +0900 Subject: [PATCH 07/11] =?UTF-8?q?:recycle:=20Refactor:=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=9E=AC=EC=A0=95=EB=A0=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit refactor: 코드 재정렬 --- lib/pages/alarm_page.dart | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/pages/alarm_page.dart b/lib/pages/alarm_page.dart index 4829be6..7a02a1a 100644 --- a/lib/pages/alarm_page.dart +++ b/lib/pages/alarm_page.dart @@ -163,11 +163,11 @@ class _AlarmPageState extends State with TickerProviderStateMixin { ), SizedBox(width: 10), Text( - "${_nickname} sends you a ${getInteractionTypeText(item.interactionType)}.", + "${_nickname} ${getInteractionTypeText(item.interactionType)}", style: TextStyle( - color: Colors.black, + color: item.isChecked == 0 ? Colors.black : Colors.grey[400], fontWeight: FontWeight.bold, - fontSize: 14, + fontSize: 16, ), ), ], @@ -229,13 +229,13 @@ class _AlarmPageState extends State with TickerProviderStateMixin { String getInteractionTypeText(int interactionType) { switch (interactionType) { case 1: - return "Thumbs-Up"; + return "gives a thumbs-up"; case 2: - return "Thumbs-Down"; + return "gives a thumbs-down"; case 3: - return "Heart"; + return "gives a full of heart"; case 4: - return "Poke"; + return "pokes you"; default: return "unclassified"; } From 633406b828be7d9516f8be3a9bdbea8f018b55ae Mon Sep 17 00:00:00 2001 From: Nam Jin Date: Mon, 11 Dec 2023 06:40:16 +0900 Subject: [PATCH 08/11] =?UTF-8?q?:sparkles:=20Feat=20:=20User=20State=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit feat : User State 수정 기능 구현 --- lib/pages/home_page.dart | 85 +++++++++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 31 deletions(-) diff --git a/lib/pages/home_page.dart b/lib/pages/home_page.dart index 6df892f..ff1a9d7 100644 --- a/lib/pages/home_page.dart +++ b/lib/pages/home_page.dart @@ -7,6 +7,7 @@ import 'package:provider/provider.dart'; import '../di/provider/id_provider.dart'; import '../models/family_member_model.dart'; +import '../root_page.dart'; import '../services/family_member_api_service.dart'; import 'setting_page.dart'; import 'package:fam_story_frontend/models/family_model.dart'; @@ -38,12 +39,13 @@ class HomePage extends StatefulWidget { class _HomePageState extends State { final _formKey = GlobalKey(); - final TextEditingController _textEditingController = TextEditingController(); + late TextEditingController _textEditingController = TextEditingController(); String myState = ''; late Future> _allFamilyMember; int familyId = 0; int familyMemberID = 0; int familyMemberNum = 0; + String? message; List familyMembers = [ // Add more members as needed @@ -53,12 +55,16 @@ class _HomePageState extends State { void initState() { super.initState(); _initData(); + setState(() { + _textEditingController.text = context.read().introMessage; + }); } Future _initData() async { familyId = context.read().familyId; familyMemberID = context.read().familyMemberId; + message = context.read().introMessage; _allFamilyMember = FamilyMemberApiService.getAllFamilyMember(familyId); _allFamilyMember.then((value) { setState(() { @@ -117,6 +123,9 @@ class _HomePageState extends State { } void myStateDialog(BuildContext context) async { + TextEditingController newController = + TextEditingController(text: _textEditingController.text); + await showDialog( context: context, builder: (BuildContext context) { @@ -138,39 +147,46 @@ class _HomePageState extends State { content: Form( key: _formKey, child: TextFormField( - controller: _textEditingController, + controller: newController, maxLength: 11, - decoration: InputDecoration( - labelText: _textEditingController.text, - suffixIcon: IconButton( - onPressed: () => _textEditingController.clear(), - icon: const Icon( - Icons.cancel, - size: 20, - )), - focusedErrorBorder: const UnderlineInputBorder( + decoration: const InputDecoration( + labelText: 'Enter your state!', + focusedErrorBorder: UnderlineInputBorder( borderSide: BorderSide( color: AppColor.objectColor, width: 2, ))), - inputFormatters: [ - FilteringTextInputFormatter( - RegExp('[a-z A-Z |0-9]'), - allow: true, - ) - ], onSaved: (value) { - myState = value!; + setState(() { + newController.text = value!; + }); }, ), ), actions: [ TextButton( - onPressed: () { - final formKeyState = _formKey.currentState!; - if (formKeyState.validate()) { - formKeyState.save(); - Navigator.of(context).pop(); + onPressed: () async { + try { + await FamilyMemberApiService.putFamilyMember( + familyMemberID, + context.read().role, + newController.text, + ).then((value) { + context + .read() + .setIntroMessage(newController.text); + _formKey.currentState!.save(); + //TODO: 다른 방안? + Navigator.pop(context); + Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) => const RootPage(), + ), + ); + }); + } catch (e) { + print('Error during API call: $e'); } }, child: const Text('Ok', @@ -187,6 +203,9 @@ class _HomePageState extends State { ); }, ); + setState(() { + _textEditingController = newController; + }); } @override @@ -431,13 +450,17 @@ class _HomePageState extends State { Positioned( top: 310, left: 190, - child: CustomPaint( - painter: SpeechBubble(color: AppColor.textColor), - child: Container( - margin: const EdgeInsets.all(30), - child: const Text("I'm hungry.."), - ), - ), + child: message != null + ? Center( + child: CustomPaint( + painter: SpeechBubble(color: AppColor.textColor), + child: Container( + margin: const EdgeInsets.all(30), + child: Text(message!), + ), + ), + ) + : Container(), // message가 null일 때는 빈 Container 반환 ), ], ), @@ -551,7 +574,7 @@ class SpeechBubble extends CustomPainter { ..color = color ..style = PaintingStyle.fill); var path = Path(); - path.moveTo(size.width / 2, 0.0); + path.moveTo(size.width / 1.5, .0); path.lineTo(size.width / 2 - _x / 1.5, _x); path.lineTo(size.width / 2 + _x / 1.5, _x); canvas.clipPath(path); From 324c1192bd573ab034ff375d5281306256c158b3 Mon Sep 17 00:00:00 2001 From: gw282 Date: Mon, 11 Dec 2023 16:42:31 +0900 Subject: [PATCH 09/11] =?UTF-8?q?:sparkles:=20Feat:=20family=20model=20?= =?UTF-8?q?=ED=94=84=EB=A1=9C=EB=B0=94=EC=9D=B4=EB=8D=94=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit feat: family model 프로바이더 구현 --- android/app/src/main/AndroidManifest.xml | 2 +- .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 544 -> 7072 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 442 -> 4549 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 721 -> 10156 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 1031 -> 15666 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 1443 -> 21579 bytes lib/di/provider/id_provider.dart | 22 +++++++ lib/pages/alarm_page.dart | 22 +++---- lib/pages/home_page.dart | 2 +- lib/pages/setting_page.dart | 56 +++++++++++++----- lib/root_page.dart | 30 ++++++++++ lib/services/user_api_service.dart | 3 +- 12 files changed, 108 insertions(+), 29 deletions(-) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 5089ebe..ec93a56 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -6,7 +6,7 @@ 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 KMNUMnLSTXlfpN?L literal 544 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8bpbvhu0Wd6uZuB!w&u2PAxD2eNXD>P5D~Wn-+_Wa#27Xc zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U|N3vA*22NaGQG zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#iqdw@AL`7MR}m`rwr|mZgU`8P7SBkL78fFf!WnuYWm$5Z0 zNXhDbCv&49sM544K|?c)WrFfiZvCi9h0O)B3Pgg&ebxsLQ05GG~ AQ2+n{ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png index 17987b79bb8a35cc66c3c1fd44f5a5526c1b78be..2ff1172c78964067ef22cdaf6ce83382e98054f5 100644 GIT binary patch literal 4549 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 diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index d5f1c8d34e7a88e3f88bea192c3a370d44689c3c..deb3d2f5048d13b1184ac9d3444a923c36e07fb9 100644 GIT binary patch literal 15666 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 literal 1031 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xjc(B0U1_% zz5^97Xt*%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3 zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc z$|q_opQ^2TrnVZ0o~wh<3t%W&flvYGe#$xqda2bR_R zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2 z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b zpQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o zo~|9I;xof diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index 4d6372eebdb28e45604e46eeda8dd24651419bc0..905de0ad07f217d9154934ed4fef296982a631e1 100644 GIT binary patch literal 21579 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

EXdT#QeWE$dKZr;hBd7mAd@dv**mW%a)p|iBBK_ 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 diff --git a/lib/di/provider/id_provider.dart b/lib/di/provider/id_provider.dart index a5a62d3..1eedaea 100644 --- a/lib/di/provider/id_provider.dart +++ b/lib/di/provider/id_provider.dart @@ -8,6 +8,11 @@ class IdProvider with ChangeNotifier { String nickname = ''; String introMessage = ''; + int memberNumber = 0; + String familyName = ''; + String createdDate = ''; + String familyKeyCode = ''; + void setFamilyId(int id) { familyId = id; notifyListeners(); @@ -37,4 +42,21 @@ class IdProvider with ChangeNotifier { introMessage = message; notifyListeners(); } + + void setMemberNumber(int memNum) { + memberNumber = memNum; + notifyListeners(); + } + void setFamilyName(String fam) { + familyName = fam; + notifyListeners(); + } + void setCreatedDate(String date) { + createdDate = date; + notifyListeners(); + } + void setKeyCode(String keycode) { + familyKeyCode = keycode; + notifyListeners(); + } } diff --git a/lib/pages/alarm_page.dart b/lib/pages/alarm_page.dart index 7a02a1a..8596300 100644 --- a/lib/pages/alarm_page.dart +++ b/lib/pages/alarm_page.dart @@ -228,14 +228,14 @@ class _AlarmPageState extends State with TickerProviderStateMixin { } String getInteractionTypeText(int interactionType) { switch (interactionType) { - case 1: - return "gives a thumbs-up"; - case 2: - return "gives a thumbs-down"; - case 3: - return "gives a full of heart"; case 4: - return "pokes you"; + return "complimented you"; + case 3: + return "booed you"; + case 2: + return "sent heart to you"; + case 1: + return "poked you"; default: return "unclassified"; } @@ -243,28 +243,28 @@ class _AlarmPageState extends State with TickerProviderStateMixin { Widget getImageForInteractionType(int interactionType) { switch (interactionType) { - case 1: + case 4: return Image.asset( 'assets/images/thumbup.png', width: 24, height: 24, fit: BoxFit.cover, ); - case 2: + case 3: return Image.asset( 'assets/images/thumbdown.png', // 싫어요 이미지에 대한 경로 width: 24, height: 24, fit: BoxFit.cover, ); - case 3: + case 2: return Image.asset( 'assets/images/heart.png', // 훈훈해요 이미지에 대한 경로 width: 24, height: 24, fit: BoxFit.cover, ); - case 4: + case 1: return Image.asset( 'assets/images/poke.png', // 슬퍼요 이미지에 대한 경로 width: 24, diff --git a/lib/pages/home_page.dart b/lib/pages/home_page.dart index ff1a9d7..d92f18e 100644 --- a/lib/pages/home_page.dart +++ b/lib/pages/home_page.dart @@ -323,7 +323,7 @@ class _HomePageState extends State { onTap: () async {}, ); }, - onAccept: (data) async { + onAccept: (data) { interaction(data, familyMembers[1].familyMemberId); }, ), diff --git a/lib/pages/setting_page.dart b/lib/pages/setting_page.dart index b1a471b..c4b0e87 100644 --- a/lib/pages/setting_page.dart +++ b/lib/pages/setting_page.dart @@ -1,9 +1,21 @@ +import 'dart:async'; + +import 'package:fam_story_frontend/models/family_model.dart'; +import 'package:fam_story_frontend/models/family_model.dart'; import 'package:fam_story_frontend/pages/login_sign_up_page.dart'; import 'package:fam_story_frontend/root_page.dart'; import 'package:fam_story_frontend/services/family_member_api_service.dart'; import 'package:flutter/material.dart'; import 'package:fam_story_frontend/style.dart'; import 'package:fam_story_frontend/models/user_model.dart'; +import 'package:provider/provider.dart'; +import 'package:fam_story_frontend/models/family_model.dart'; + +import '../di/provider/id_provider.dart'; +import '../models/family_member_model.dart'; +import '../models/family_model.dart'; +import '../models/family_model.dart'; +import '../models/family_model.dart'; class SettingPage extends StatefulWidget { const SettingPage({Key? key}) : super(key: key); @@ -14,13 +26,13 @@ class SettingPage extends StatefulWidget { class _SettingPageState extends State with TickerProviderStateMixin { final _familyNameController = TextEditingController(); + late Future> _familyInfo; // Future> 타입으로 변경 + int familyId = 0, familyMemberId = 0; + String buttonText = 'Go Out'; String buttonText2 = 'Edit'; - bool _isEditing = false; - - final GlobalKey _formKey = GlobalKey(); String email = ''; String username = ''; String nickname = ''; @@ -29,6 +41,30 @@ class _SettingPageState extends State with TickerProviderStateMixin int gender = -1; bool isEditMode = false; // Track the edit mode + int familyMemberID = 0; + + final _formKey = GlobalKey(); + + @override + void initState() { + super.initState(); + _initData(); + } + + Future _initData() async { + familyId = context.watch().familyId; + familyMemberId = context.watch().familyMemberId; + print('familyId: $familyId'); + print('familyMemberId: $familyMemberId'); + + var familyInfo = await FamilyMemberApiService.postAndGetFamily(familyMemberId); + + setState(() { + _familyInfo = Future.value(familyInfo as FutureOr>?); + }); + } + + String? _selectedGender; final List _genders = ['Male', 'Female']; @override @@ -49,7 +85,7 @@ class _SettingPageState extends State with TickerProviderStateMixin crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - "Setting", + "My Room", style: TextStyle(color: AppColor.textColor, fontSize: 40, fontWeight: FontWeight.bold), ), Text( @@ -347,7 +383,7 @@ class _SettingPageState extends State with TickerProviderStateMixin Align( alignment: Alignment.center, child: Text( - 'Code 주르륵', + 'da', style: TextStyle( fontSize: 20, color: Colors.black, @@ -368,15 +404,7 @@ class _SettingPageState extends State with TickerProviderStateMixin mainAxisAlignment: MainAxisAlignment.center, children: [ ElevatedButton( - onPressed: () async { - - try { - // Access user input values - - // TODO: API 연결, 가족 멤버 생성, 가족 ID 가져오기 - } catch (e) { - print(e.toString()); - } + onPressed: () { setState(() { // Toggle the edit mode when the button is pressed isEditMode = !isEditMode; diff --git a/lib/root_page.dart b/lib/root_page.dart index 77b59bf..29e1021 100644 --- a/lib/root_page.dart +++ b/lib/root_page.dart @@ -32,6 +32,13 @@ class _RootPageState extends State { String _nickname = ''; String _introMessage = ''; + int _memberNumber = 0; + String _familyName = ''; + String _createdDate = ''; + String _familyKeyCode = ''; + + + final List _pages = [ const HomePage(), const ChatPage(), @@ -53,6 +60,7 @@ class _RootPageState extends State { //_initData().then((_) {}); // Future.microtask(() => _initData()); _initData(); + _initData2(); getMyDeviceToken(); FirebaseMessaging.onMessage.listen((RemoteMessage message) async { @@ -80,6 +88,9 @@ class _RootPageState extends State { }); } + + + Future _initData() async { _familyMember = FamilyMemberApiService.getFamilyMember(); _familyMember.then((value) { @@ -101,6 +112,25 @@ class _RootPageState extends State { }); } + + Future _initData2() async { + _family = FamilyMemberApiService.postAndGetFamily(_familyMemberId); + _family.then((value) { + _memberNumber = value.memberNumber; + _familyName = value.familyName; + _createdDate = value.createdDate; + _familyKeyCode = value.familyKeyCode; + _family = FamilyMemberApiService.postAndGetFamily(_familyMemberId); + _family.then((value) { + _familyId = value.familyId; + context.read().setMemberNumber(_memberNumber); + context.read().setFamilyName(_familyName); + context.read().setCreatedDate(_createdDate); + context.read().setKeyCode(_familyKeyCode); + }); + }); + } + bool flag = false; @override Widget build(BuildContext context) { diff --git a/lib/services/user_api_service.dart b/lib/services/user_api_service.dart index 1aefdd9..e1095be 100644 --- a/lib/services/user_api_service.dart +++ b/lib/services/user_api_service.dart @@ -132,8 +132,7 @@ class UserApiService { } /// GET: /user [프로필] 회원 정보 조회 - static Future getUser(String email, String username, - String password, String? nickname, int age, int gender) async { + static Future getUser() async { final url = Uri.parse('$baseUrl/user'); const storage = FlutterSecureStorage(); From 9bb6396a1a74453735f480f533480b50e7530754 Mon Sep 17 00:00:00 2001 From: Nam Jin Date: Mon, 11 Dec 2023 17:47:04 +0900 Subject: [PATCH 10/11] =?UTF-8?q?:sparkles:=20Feat=20:=20IntroMessage=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit feat : IntroMessage 구현 완료 --- devtools_options.yaml | 1 + lib/main.dart | 2 +- lib/pages/home_page.dart | 855 ++++++++++++++++++++++++--------------- lib/pages/role_page.dart | 11 +- lib/root_page.dart | 18 +- 5 files changed, 554 insertions(+), 333 deletions(-) create mode 100644 devtools_options.yaml diff --git a/devtools_options.yaml b/devtools_options.yaml new file mode 100644 index 0000000..7e7e7f6 --- /dev/null +++ b/devtools_options.yaml @@ -0,0 +1 @@ +extensions: diff --git a/lib/main.dart b/lib/main.dart index f87cc84..8b0f9dd 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -88,7 +88,7 @@ class FamStory extends StatelessWidget { routes: { // TODO: 로딩에서 가족 여부 체크 - '/': (context) => const LoginSignUpPage(), + '/': (context) => const LoadingScreen(), // '/': (context) => const FamilyJoinPage(), diff --git a/lib/pages/home_page.dart b/lib/pages/home_page.dart index ff1a9d7..3f15ec9 100644 --- a/lib/pages/home_page.dart +++ b/lib/pages/home_page.dart @@ -23,10 +23,10 @@ enum Interaction { poke; int get title => const { - Interaction.thumbUp: 1, - Interaction.thumbDown: 2, - Interaction.heart: 3, - Interaction.poke: 4, + Interaction.thumbUp: 4, + Interaction.thumbDown: 3, + Interaction.heart: 2, + Interaction.poke: 1, }[this]!; } @@ -46,6 +46,10 @@ class _HomePageState extends State { int familyMemberID = 0; int familyMemberNum = 0; String? message; + bool click1 = false; + bool click2 = false; + bool click3 = false; + bool click4 = false; List familyMembers = [ // Add more members as needed @@ -54,16 +58,16 @@ class _HomePageState extends State { @override void initState() { super.initState(); - _initData(); - setState(() { - _textEditingController.text = context.read().introMessage; + _initData().then((_) { + setState(() { + _textEditingController.text = context.read().introMessage; + }); }); } Future _initData() async { familyId = context.read().familyId; familyMemberID = context.read().familyMemberId; - message = context.read().introMessage; _allFamilyMember = FamilyMemberApiService.getAllFamilyMember(familyId); _allFamilyMember.then((value) { @@ -76,30 +80,92 @@ class _HomePageState extends State { }); } - Future interaction(Interaction data, int familyMemberIDNum) async { - await FamilyInteractionApiService.postFamilyInteraction( - familyMemberID, familyMemberIDNum, data.title); + void interaction(Interaction data, int num) { + FamilyInteractionApiService.postFamilyInteraction( + familyMemberID, familyMembers[num].familyMemberId, data.title); switch (data.title) { - case 1: - ScaffoldMessenger.of(context).showSnackBar(const SnackBar( - content: Text('thumb up'), - )); - case 2: - ScaffoldMessenger.of(context).showSnackBar(const SnackBar( - content: Text('thumb down'), - )); - case 3: - ScaffoldMessenger.of(context).showSnackBar(const SnackBar( - content: Text('heart'), - )); case 4: - ScaffoldMessenger.of(context).showSnackBar(const SnackBar( - content: Text('poke'), - )); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Container( + child: Center( + child: Text( + 'You like \"${familyMembers[num].nickname}\"', + style: TextStyle( + fontFamily: 'AppleSDGothicNeo', + fontWeight: FontWeight.bold, + color: AppColor.textColor, + fontSize: 20), + ), + ), + ), + duration: const Duration(seconds: 1), + ), + ); + break; + case 3: + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Container( + child: Center( + child: Text( + 'You unlike \"${familyMembers[num].nickname}\"', + style: TextStyle( + fontFamily: 'AppleSDGothicNeo', + fontWeight: FontWeight.bold, + color: AppColor.textColor, + fontSize: 20), + ), + ), + ), + duration: const Duration(seconds: 1), + ), + ); + break; + case 2: + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Container( + child: Center( + child: Text( + 'You love \"${familyMembers[num].nickname}\"', + style: TextStyle( + fontFamily: 'AppleSDGothicNeo', + fontWeight: FontWeight.bold, + color: AppColor.textColor, + fontSize: 20), + ), + ), + ), + duration: const Duration(seconds: 1), + ), + ); + break; + case 1: + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Container( + child: Center( + child: Text( + 'You poke \"${familyMembers[num].nickname}\"', + style: TextStyle( + fontFamily: 'AppleSDGothicNeo', + fontWeight: FontWeight.bold, + color: AppColor.textColor, + fontSize: 20), + ), + ), + ), + duration: const Duration(seconds: 1), + ), + ); + break; default: ScaffoldMessenger.of(context).showSnackBar(const SnackBar( content: Text('NO'), + duration: const Duration(seconds: 1), )); + break; } } @@ -130,32 +196,42 @@ class _HomePageState extends State { context: context, builder: (BuildContext context) { return AlertDialog( - shape: - RoundedRectangleBorder(borderRadius: BorderRadius.circular(10.0)), - elevation: 10.0, - icon: const Icon(Icons.account_box, size: 50), - iconColor: AppColor.swatchColor, - title: const Center( - child: Text( - 'My State', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: AppColor.textColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20.0), + ), + elevation: 50.0, + backgroundColor: AppColor.backgroudColor, + title: Center( + child: Text( + 'Enter My State !', + style: TextStyle( + fontSize: 30, + fontWeight: FontWeight.bold, + color: AppColor.textColor, + ), ), - )), + ), content: Form( key: _formKey, child: TextFormField( controller: newController, - maxLength: 11, - decoration: const InputDecoration( - labelText: 'Enter your state!', - focusedErrorBorder: UnderlineInputBorder( - borderSide: BorderSide( - color: AppColor.objectColor, + maxLength: 12, + style: TextStyle( + color: AppColor.swatchColor, + fontWeight: FontWeight.bold, + ), + decoration: InputDecoration( + hintText: 'Enter your state!', + hintStyle: TextStyle( + color: AppColor.swatchColor, + ), + focusedErrorBorder: UnderlineInputBorder( + borderSide: BorderSide( + color: Colors.red, width: 2, - ))), + ), + ), + ), onSaved: (value) { setState(() { newController.text = value!; @@ -176,28 +252,25 @@ class _HomePageState extends State { .read() .setIntroMessage(newController.text); _formKey.currentState!.save(); - //TODO: 다른 방안? Navigator.pop(context); - Navigator.pushReplacement( - context, - MaterialPageRoute( - builder: (context) => const RootPage(), - ), - ); }); } catch (e) { print('Error during API call: $e'); } }, - child: const Text('Ok', - style: TextStyle(color: AppColor.swatchColor, fontSize: 18)), + style: TextButton.styleFrom( + foregroundColor: AppColor.textColor, // 버튼 텍스트 색상 추가 + ), + child: const Text('OK', style: TextStyle(fontSize: 18)), ), TextButton( onPressed: () { Navigator.of(context).pop(); }, - child: const Text('Back', - style: TextStyle(color: AppColor.swatchColor, fontSize: 18)), + style: TextButton.styleFrom( + foregroundColor: AppColor.textColor, // 버튼 텍스트 색상 추가 + ), + child: const Text('Back', style: TextStyle(fontSize: 18)), ), ], ); @@ -210,261 +283,403 @@ class _HomePageState extends State { @override Widget build(BuildContext context) { - print(familyId); - return SafeArea( - child: Center( - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + return Scaffold( + backgroundColor: AppColor.backgroudColor, + resizeToAvoidBottomInset: true, + appBar: null, + body: SafeArea( + child: SingleChildScrollView( + child: Center( + child: Column( children: [ - const Row( + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - SizedBox( - width: 30, - ), - Text( - //TODO: 패밀리 이름으로 변경 - "Living Room", - style: TextStyle( - fontFamily: 'AppleSDGothicNeo', - fontWeight: FontWeight.bold, - color: AppColor.textColor, - fontSize: 35), + const Row( + children: [ + SizedBox( + width: 30, + ), + Text( + //TODO: 패밀리 이름으로 변경 + "Living Room", + style: TextStyle( + fontFamily: 'AppleSDGothicNeo', + fontWeight: FontWeight.bold, + color: AppColor.textColor, + fontSize: 35), + ), + ], ), + Row( + children: [ + IconButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const AlarmPage(), + ), + ); + }, + icon: const Icon(Icons.alarm_on), + color: AppColor.swatchColor, + iconSize: 35), + IconButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const SettingPage()), + ); + }, + icon: const Icon(Icons.settings), + color: AppColor.swatchColor, + iconSize: 35), + const SizedBox( + width: 20, + ), + ], + ) ], ), - Row( + const SizedBox( + height: 140, + ), + Stack( + clipBehavior: Clip.none, + fit: StackFit.passthrough, children: [ - IconButton( - onPressed: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const AlarmPage(), - ), - ); - }, - icon: const Icon(Icons.alarm_on), + Container( + width: 300, + height: 300, + decoration: BoxDecoration( color: AppColor.swatchColor, - iconSize: 35), - IconButton( - onPressed: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const SettingPage()), - ); - }, - icon: const Icon(Icons.settings), - color: AppColor.swatchColor, - iconSize: 35), - const SizedBox( - width: 20, - ), - ], - ) - ], - ), - const SizedBox( - height: 140, - ), - Stack( - clipBehavior: Clip.none, - fit: StackFit.passthrough, - children: [ - Container( - width: 300, - height: 300, - decoration: BoxDecoration( - color: AppColor.swatchColor, - borderRadius: BorderRadius.circular(15), - border: Border.all( - color: Colors.brown[200]!, // Adjust the color as needed - width: 5, // Adjust the width as needed + borderRadius: BorderRadius.circular(15), + border: Border.all( + color: + Colors.brown[200]!, // Adjust the color as needed + width: 5, // Adjust the width as needed + ), + ), ), - ), - ), - //familyId -> - // 0번 리스트 - Visibility( - visible: familyMemberNum >= 1, - child: Positioned( - top: -120, - left: 30, - child: DragTarget( - builder: (context, candidateData, rejectedData) { - return FamilyMemberButton( - buttonSize: 0.28, - imageSize: 50, - memberImage: getRoleImage(familyMembers[0].role), - onTap: () async {}, - ); - }, - onAccept: (data) { - interaction(data, familyMembers[0].familyMemberId); - }, + //familyId -> + // 3번 리스트 + Visibility( + visible: familyMemberNum >= 4, + child: Positioned( + top: -60, + left: 170, + child: Column( + children: [ + DragTarget( + builder: (context, candidateData, rejectedData) { + return FamilyMemberButton( + buttonSize: 110, + imageSize: 50, + memberImage: + getRoleImage(familyMembers[3].role), + onTap: () { + setState(() { + click4 = !click4; + }); + }, + ); + }, + onAccept: (data) { + interaction(data, 3); + }, + ), + if (click4 && + familyMembers.isNotEmpty && + familyMemberNum >= 4 && + familyMembers[3].introMessage != null && + familyMembers[3].introMessage.isNotEmpty) + CustomPaint( + painter: + SpeechBubble(color: AppColor.textColor), + child: Center( + child: Container( + margin: const EdgeInsets.all(30), + child: Text( + familyMembers[3].introMessage, + textAlign: TextAlign.center, + style: TextStyle( + color: AppColor.objectColor, + fontSize: 12, + ), + ), + ), + ), + ) + ], + ), + ), ), - ), - ), - // 1번 리스트 - Visibility( - visible: familyMemberNum >= 2, - child: Positioned( - top: 10, - left: -40, - child: DragTarget( - builder: (context, candidateData, rejectedData) { - return FamilyMemberButton( - buttonSize: 0.28, - imageSize: 50, - memberImage: getRoleImage(familyMembers[1].role), - onTap: () async {}, - ); - }, - onAccept: (data) async { - interaction(data, familyMembers[1].familyMemberId); - }, + // 2번 리스트 + Visibility( + visible: familyMemberNum >= 3, + child: Positioned( + top: 210, + left: -35, + child: Column( + children: [ + DragTarget( + builder: (context, candidateData, rejectedData) { + return FamilyMemberButton( + buttonSize: 110, + imageSize: 50, + memberImage: + getRoleImage(familyMembers[2].role), + onTap: () { + setState(() { + click3 = !click3; + }); + }, + ); + }, + onAccept: (data) { + interaction(data, 2); + }, + ), + if (click3 && + familyMembers.isNotEmpty && + familyMemberNum >= 3 && + familyMembers[2].introMessage != null && + familyMembers[2].introMessage.isNotEmpty) + CustomPaint( + painter: + SpeechBubble(color: AppColor.textColor), + child: Center( + child: Container( + margin: const EdgeInsets.all(30), + child: Text( + familyMembers[2].introMessage, + textAlign: TextAlign.center, + style: TextStyle( + color: AppColor.objectColor, + fontSize: 12, + ), + ), + ), + ), + ) + ], + ), + ), ), - ), - ), - // 2번 리스트 - Visibility( - visible: familyMemberNum >= 3, - child: Positioned( - top: -120, - left: 170, - child: DragTarget( - builder: (context, candidateData, rejectedData) { - return FamilyMemberButton( - buttonSize: 0.28, - imageSize: 50, - memberImage: getRoleImage(familyMembers[2].role), - onTap: () async {}, - ); - }, - onAccept: (data) { - interaction(data, familyMembers[2].familyMemberId); - }, + // 1번 리스트 + Visibility( + visible: familyMemberNum >= 2, + child: Positioned( + top: 60, + left: -35, + child: Column( + children: [ + DragTarget( + builder: (context, candidateData, rejectedData) { + return FamilyMemberButton( + buttonSize: 110, + imageSize: 50, + memberImage: + getRoleImage(familyMembers[1].role), + onTap: () { + setState(() { + click2 = !click2; + }); + }, + ); + }, + onAccept: (data) { + interaction(data, 1); + }, + ), + if (click2 && + familyMembers.isNotEmpty && + familyMemberNum >= 2 && + familyMembers[1].introMessage != null && + familyMembers[1].introMessage.isNotEmpty) + CustomPaint( + painter: + SpeechBubble(color: AppColor.textColor), + child: Center( + child: Container( + margin: const EdgeInsets.all(30), + child: Text( + familyMembers[1].introMessage, + textAlign: TextAlign.center, + style: TextStyle( + color: AppColor.objectColor, + fontSize: 12, + ), + ), + ), + ), + ) + ], + ), + ), ), - ), - ), - // 3번 리스트 - Visibility( - visible: familyMemberNum >= 4, - child: Positioned( - top: 150, - left: -40, - child: DragTarget( - builder: (context, candidateData, rejectedData) { - return FamilyMemberButton( - buttonSize: 0.28, - imageSize: 50, - memberImage: getRoleImage(familyMembers[3].role), - onTap: () async {}, - ); - }, - onAccept: (data) { - interaction(data, familyMembers[3].familyMemberId); - }, + // 0번 리스트 + Visibility( + visible: familyMemberNum >= 1, + child: Positioned( + top: -60, + left: 40, + child: Column( + children: [ + DragTarget( + builder: (context, candidateData, rejectedData) { + return FamilyMemberButton( + buttonSize: 110, + imageSize: 50, + memberImage: + getRoleImage(familyMembers[0].role), + onTap: () { + setState(() { + click1 = !click1; + }); + }, + ); + }, + onAccept: (data) { + interaction(data, 0); + }, + ), + if (click1 && + familyMembers.isNotEmpty && + familyMemberNum >= 1 && + familyMembers[0].introMessage != null && + familyMembers[0].introMessage.isNotEmpty) + CustomPaint( + painter: + SpeechBubble(color: AppColor.textColor), + child: Center( + child: Container( + margin: const EdgeInsets.all(30), + child: Text( + familyMembers[0].introMessage, + textAlign: TextAlign.center, + style: TextStyle( + color: AppColor.objectColor, + fontSize: 12, + ), + ), + ), + ), + ) + ], + ), + ), ), - ), - ), - Positioned( - top: 100, - left: 180, - child: FamilyMemberButton( - buttonSize: 0.4, - imageSize: 90, - memberImage: getRoleImage(context.read().role), - onTap: () { - myStateDialog(context); - }, - ), - ), + ///나 + Positioned( + top: 180, + left: 180, + child: Column( + children: [ + FamilyMemberButton( + buttonSize: 155, + imageSize: 90, + memberImage: + getRoleImage(context.read().role), + onTap: () { + myStateDialog(context); + }, + ), - ///Interaction button - Positioned( - top: 100, - left: 230, - child: Draggable( - feedback: const InteractionButton( - interactionImage: 'assets/images/poke.png', size: 68), - childWhenDragging: Container( - color: AppColor.swatchColor, - ), - data: Interaction.heart, - child: const InteractionButton( - interactionImage: 'assets/images/poke.png', - size: 68)), - ), - Positioned( - top: 125, - left: 175, - child: Draggable( - feedback: const InteractionButton( - interactionImage: 'assets/images/heart.png', - size: 53), - childWhenDragging: Container( - color: AppColor.swatchColor, - ), - data: Interaction.heart, - child: const InteractionButton( - interactionImage: 'assets/images/heart.png', - size: 53)), - ), - Positioned( - top: 170, - left: 125, - child: Draggable( - feedback: const InteractionButton( - interactionImage: 'assets/images/thumbdown.png', - size: 55), - childWhenDragging: Container( - color: AppColor.swatchColor, - ), - data: Interaction.thumbDown, - child: const InteractionButton( - interactionImage: 'assets/images/thumbdown.png', - size: 55)), - ), - Positioned( - top: 235, - left: 115, - child: Draggable( - feedback: const InteractionButton( - interactionImage: 'assets/images/thumbup.png', - size: 55), - childWhenDragging: Container( - color: AppColor.swatchColor, + ///SpeechBubble + Visibility( + visible: + context.read().introMessage != '', + child: CustomPaint( + painter: + SpeechBubble(color: AppColor.textColor), + child: Center( + child: Container( + margin: const EdgeInsets.all(30), + child: Text( + context.read().introMessage, + textAlign: TextAlign.center, + style: TextStyle( + color: AppColor.objectColor, + fontSize: 15, + ), + ), + ), + ))), + ], ), - data: Interaction.thumbUp, - child: const InteractionButton( - interactionImage: 'assets/images/thumbup.png', - size: 55)), - ), + ), - ///SpeechBubble - Positioned( - top: 310, - left: 190, - child: message != null - ? Center( - child: CustomPaint( - painter: SpeechBubble(color: AppColor.textColor), - child: Container( - margin: const EdgeInsets.all(30), - child: Text(message!), - ), + ///Interaction button + Positioned( + top: 100, + left: 230, + child: Draggable( + feedback: const InteractionButton( + interactionImage: 'assets/images/poke.png', + size: 68), + childWhenDragging: Container( + color: AppColor.swatchColor, + ), + data: Interaction.poke, + child: const InteractionButton( + interactionImage: 'assets/images/poke.png', + size: 68)), + ), + Positioned( + top: 125, + left: 175, + child: Draggable( + feedback: const InteractionButton( + interactionImage: 'assets/images/heart.png', + size: 53), + childWhenDragging: Container( + color: AppColor.swatchColor, + ), + data: Interaction.heart, + child: const InteractionButton( + interactionImage: 'assets/images/heart.png', + size: 53)), + ), + Positioned( + top: 170, + left: 125, + child: Draggable( + feedback: const InteractionButton( + interactionImage: 'assets/images/thumbdown.png', + size: 55), + childWhenDragging: Container( + color: AppColor.swatchColor, + ), + data: Interaction.thumbDown, + child: const InteractionButton( + interactionImage: 'assets/images/thumbdown.png', + size: 55)), + ), + Positioned( + top: 235, + left: 115, + child: Draggable( + feedback: const InteractionButton( + interactionImage: 'assets/images/thumbup.png', + size: 55), + childWhenDragging: Container( + color: AppColor.swatchColor, ), - ) - : Container(), // message가 null일 때는 빈 Container 반환 + data: Interaction.thumbUp, + child: const InteractionButton( + interactionImage: 'assets/images/thumbup.png', + size: 55)), + ), + ], ), ], ), - ], + ), ), ), ); @@ -487,8 +702,6 @@ class FamilyMemberButton extends StatelessWidget { @override Widget build(BuildContext context) { - var screenHeight = MediaQuery.of(context).size.height; - var screenWidth = MediaQuery.of(context).size.width; return Material( shape: const CircleBorder(), clipBehavior: Clip.antiAlias, @@ -497,8 +710,8 @@ class FamilyMemberButton extends StatelessWidget { splashColor: AppColor.subColor.withOpacity(0.3), onTap: onTap, child: Ink( - width: screenWidth * buttonSize, - height: screenHeight * buttonSize, + width: buttonSize, + height: buttonSize, decoration: const BoxDecoration( color: AppColor.objectColor, ), @@ -554,41 +767,43 @@ class SpeechBubble extends CustomPainter { required this.color, }); - final _radius = 20.0; + final _radius = 15.0; final _x = 12.0; @override void paint(Canvas canvas, Size size) { canvas.drawRRect( - RRect.fromLTRBAndCorners( - 0.0 + _x, - 0.0 + _x, - size.width - _x, - size.height - _x, - bottomRight: Radius.circular(_radius), - bottomLeft: Radius.circular(_radius), - topRight: Radius.circular(_radius), - topLeft: Radius.circular(_radius), - ), - Paint() - ..color = color - ..style = PaintingStyle.fill); + RRect.fromLTRBAndCorners( + 0.0 + _x, + 0.0 + _x, + size.width - _x, + size.height - _x, + bottomRight: Radius.circular(_radius), + bottomLeft: Radius.circular(_radius), + topRight: Radius.circular(_radius), + topLeft: Radius.circular(_radius), + ), + Paint() + ..color = color + ..style = PaintingStyle.fill, + ); var path = Path(); - path.moveTo(size.width / 1.5, .0); + path.moveTo(size.width / 2, 1); path.lineTo(size.width / 2 - _x / 1.5, _x); path.lineTo(size.width / 2 + _x / 1.5, _x); canvas.clipPath(path); canvas.drawRRect( - RRect.fromLTRBAndCorners( - -_x, - 0.0, - size.width, - size.height, - topRight: Radius.circular(_radius), - ), - Paint() - ..color = color - ..style = PaintingStyle.fill); + RRect.fromLTRBAndCorners( + -_x, + 0.0, + size.width, + size.height, + topRight: Radius.circular(_radius), + ), + Paint() + ..color = color + ..style = PaintingStyle.fill, + ); } @override diff --git a/lib/pages/role_page.dart b/lib/pages/role_page.dart index 45920b2..a6486f0 100644 --- a/lib/pages/role_page.dart +++ b/lib/pages/role_page.dart @@ -224,13 +224,12 @@ class _SelectRolePageState extends State child: TextButton( onPressed: () { Navigator.of(context).pop(); // 현재 라우트 팝 - Navigator.of(context).pushReplacement( + Navigator.pushReplacement( + context, MaterialPageRoute( - builder: (context) => - ChangeNotifierProvider( - create: (context) => - IdProvider(), - child: const RootPage())), + builder: (context) => + const RootPage(), + ), ); }, style: TextButton.styleFrom( diff --git a/lib/root_page.dart b/lib/root_page.dart index 77b59bf..dd5d26b 100644 --- a/lib/root_page.dart +++ b/lib/root_page.dart @@ -113,12 +113,18 @@ class _RootPageState extends State { case ConnectionState.active: case ConnectionState.waiting: // 처음 한 번만 1초 텀 주는 부분 - return Scaffold( - backgroundColor: AppColor.backgroudColor, - body: Center( - child: LoadingIndicator(), - ), - ); + if (flag == 0) { + return Scaffold( + backgroundColor: AppColor.backgroudColor, + body: Center( + child: LoadingIndicator(), + ), + ); + } else { + return Scaffold( + backgroundColor: AppColor.backgroudColor, + ); + } case ConnectionState.done: if (snapshot.hasError) return Text('Error: ${snapshot.error}'); return Scaffold( From 3670aa6335b42346bf257e478b425da76075f4b9 Mon Sep 17 00:00:00 2001 From: gw282 Date: Mon, 11 Dec 2023 17:52:27 +0900 Subject: [PATCH 11/11] =?UTF-8?q?:sparkles:=20Feat:=20=EC=84=A4=EC=A0=95?= =?UTF-8?q?=EC=B0=BD=20=ED=95=AD=EB=AA=A9=20api=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit feat: 설정창 항목 api 적용 --- lib/di/provider/id_provider.dart | 23 +++++++++++ lib/pages/setting_page.dart | 71 +++++++++++++++----------------- lib/root_page.dart | 49 +++++++++++++++------- 3 files changed, 89 insertions(+), 54 deletions(-) diff --git a/lib/di/provider/id_provider.dart b/lib/di/provider/id_provider.dart index 1eedaea..70d97d6 100644 --- a/lib/di/provider/id_provider.dart +++ b/lib/di/provider/id_provider.dart @@ -13,6 +13,11 @@ class IdProvider with ChangeNotifier { String createdDate = ''; String familyKeyCode = ''; + int age = 0; + int gender = 0; + String email = ''; + String username = ''; + void setFamilyId(int id) { familyId = id; notifyListeners(); @@ -59,4 +64,22 @@ class IdProvider with ChangeNotifier { familyKeyCode = keycode; notifyListeners(); } + + void setAge(int ageage) { + age = ageage; + notifyListeners(); + } + void setGender(int gen) { + gender = gen; + notifyListeners(); + } + void setEmail(String emailemail) { + email = emailemail; + notifyListeners(); + } + void setUsername(String usernamename) { + username = usernamename; + notifyListeners(); + } + } diff --git a/lib/pages/setting_page.dart b/lib/pages/setting_page.dart index c4b0e87..a16acc3 100644 --- a/lib/pages/setting_page.dart +++ b/lib/pages/setting_page.dart @@ -5,6 +5,7 @@ import 'package:fam_story_frontend/models/family_model.dart'; import 'package:fam_story_frontend/pages/login_sign_up_page.dart'; import 'package:fam_story_frontend/root_page.dart'; import 'package:fam_story_frontend/services/family_member_api_service.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:fam_story_frontend/style.dart'; import 'package:fam_story_frontend/models/user_model.dart'; @@ -26,14 +27,14 @@ class SettingPage extends StatefulWidget { class _SettingPageState extends State with TickerProviderStateMixin { final _familyNameController = TextEditingController(); - late Future> _familyInfo; // Future> 타입으로 변경 + late Future> _familyInfo; int familyId = 0, familyMemberId = 0; String buttonText = 'Go Out'; String buttonText2 = 'Edit'; - String email = ''; + String username = ''; String nickname = ''; String password = ''; @@ -57,11 +58,6 @@ class _SettingPageState extends State with TickerProviderStateMixin print('familyId: $familyId'); print('familyMemberId: $familyMemberId'); - var familyInfo = await FamilyMemberApiService.postAndGetFamily(familyMemberId); - - setState(() { - _familyInfo = Future.value(familyInfo as FutureOr>?); - }); } @@ -129,7 +125,7 @@ class _SettingPageState extends State with TickerProviderStateMixin children: [ Text("E-mail"), const SizedBox(height: 10), - Text("이 부분에 이메일 고정"), // TODO: 수정해야됨 + Text(context.read().email,), // TODO: 수정해야됨 Divider(color: AppColor.swatchColor,), ], ), @@ -172,7 +168,7 @@ class _SettingPageState extends State with TickerProviderStateMixin crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 16), - Text("username"), // TODO: 수정해야됨 + Text(context.read().username,), const SizedBox(height: 4), Divider(color: AppColor.swatchColor,), ], @@ -219,7 +215,7 @@ class _SettingPageState extends State with TickerProviderStateMixin crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 16), - Text("nickname"), // TODO: 수정해야됨 + Text(context.read().nickname,), const SizedBox(height: 4), Divider(color: AppColor.swatchColor,), ], @@ -275,7 +271,7 @@ class _SettingPageState extends State with TickerProviderStateMixin crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 20), - Text("10"), // TODO: 수정해야됨 + //Text(context.read().age), // TODO Divider(color: AppColor.swatchColor,), ], ) @@ -329,7 +325,13 @@ class _SettingPageState extends State with TickerProviderStateMixin children: [ Text("Gender"), const SizedBox(height: 20), - Text("10"), // TODO: 수정해야됨 + Text( + context.read().gender == 0 ? "남자" : "여자", + // TODO: 수정해야됨 + style: TextStyle( + fontSize: 16, + ), + ), Divider(color: AppColor.swatchColor,) ], ), @@ -344,6 +346,24 @@ class _SettingPageState extends State with TickerProviderStateMixin ), ), ), + Positioned( + left: 300, + right: 0, + top: 110, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + IconButton( + onPressed: () { + setState(() { + // Toggle the edit mode when the button is pressed + isEditMode = !isEditMode; + }); + }, + icon: const Icon(CupertinoIcons.pen)), + ], + ), + ), if(!isEditMode) Positioned( left: 0, @@ -383,7 +403,7 @@ class _SettingPageState extends State with TickerProviderStateMixin Align( alignment: Alignment.center, child: Text( - 'da', + context.read().familyKeyCode, style: TextStyle( fontSize: 20, color: Colors.black, @@ -403,31 +423,6 @@ class _SettingPageState extends State with TickerProviderStateMixin child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - ElevatedButton( - onPressed: () { - setState(() { - // Toggle the edit mode when the button is pressed - isEditMode = !isEditMode; - }); - }, - - style: ElevatedButton.styleFrom( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(35), - ), - backgroundColor: AppColor.textColor, // 항상 활성화된 색상 - minimumSize: const Size(120, 40), - ), - child: Text( - isEditMode ? "Save" : "Edit", - style: const TextStyle( - color: AppColor.objectColor, - fontWeight: FontWeight.bold, - fontSize: 18, - ), - ), - ), - SizedBox(width: 32), ElevatedButton( onPressed: () { setState(() { diff --git a/lib/root_page.dart b/lib/root_page.dart index 29e1021..b33d4a6 100644 --- a/lib/root_page.dart +++ b/lib/root_page.dart @@ -1,11 +1,13 @@ import 'package:fam_story_frontend/di/provider/id_provider.dart'; import 'package:fam_story_frontend/models/family_member_model.dart'; import 'package:fam_story_frontend/models/family_model.dart'; +import 'package:fam_story_frontend/models/user_model.dart'; import 'package:fam_story_frontend/pages/calendar_page.dart'; import 'package:fam_story_frontend/pages/chat_page.dart'; import 'package:fam_story_frontend/pages/home_page.dart'; import 'package:fam_story_frontend/pages/post_page.dart'; import 'package:fam_story_frontend/services/family_member_api_service.dart'; +import 'package:fam_story_frontend/services/user_api_service.dart'; import 'package:fam_story_frontend/style.dart'; import 'package:fam_story_frontend/widgets/loading_indicator.dart'; import 'package:flutter/material.dart'; @@ -25,6 +27,7 @@ class _RootPageState extends State { int _selectedIndex = 0; late Future _familyMember; late Future _family; + late Future _user; int _familyMemberId = 0; int _familyId = 0; int _role = 0; @@ -38,6 +41,11 @@ class _RootPageState extends State { String _familyKeyCode = ''; + int _userId = 0; + int _age = 0; + int _gender = 0; + String _email = ''; + String _nusername = ''; final List _pages = [ const HomePage(), @@ -60,7 +68,6 @@ class _RootPageState extends State { //_initData().then((_) {}); // Future.microtask(() => _initData()); _initData(); - _initData2(); getMyDeviceToken(); FirebaseMessaging.onMessage.listen((RemoteMessage message) async { @@ -93,40 +100,50 @@ class _RootPageState extends State { Future _initData() async { _familyMember = FamilyMemberApiService.getFamilyMember(); + _user = UserApiService.getUser(); + + _user.then((value) { + _age = value.age; + _gender = value.gender; + _email = value.email; + _name = value.username; + + context.read().setAge(_age); + context.read().setGender(_gender); + context.read().setEmail(_email); + context.read().setUsername(_name); + } + ); _familyMember.then((value) { _role = value.role; _name = value.name; _nickname = value.nickname; _introMessage = value.introMessage; _familyMemberId = value.familyMemberId; + + _family = FamilyMemberApiService.postAndGetFamily(_familyMemberId); _family.then((value) { _familyId = value.familyId; + _memberNumber = value.memberNumber; + _familyName = value.familyName; + _createdDate = value.createdDate; + _familyKeyCode = value.familyKeyCode; + context.read().setFamilyMemberId(_familyMemberId); - context.read().setFamilyId(_familyId); + context.read().setRole(_role); context.read().setName(_name); context.read().setNicKName(_nickname); context.read().setIntroMessage(_introMessage); - }); - }); - } - - Future _initData2() async { - _family = FamilyMemberApiService.postAndGetFamily(_familyMemberId); - _family.then((value) { - _memberNumber = value.memberNumber; - _familyName = value.familyName; - _createdDate = value.createdDate; - _familyKeyCode = value.familyKeyCode; - _family = FamilyMemberApiService.postAndGetFamily(_familyMemberId); - _family.then((value) { - _familyId = value.familyId; + context.read().setFamilyId(_familyId); context.read().setMemberNumber(_memberNumber); context.read().setFamilyName(_familyName); context.read().setCreatedDate(_createdDate); context.read().setKeyCode(_familyKeyCode); + + }); }); }