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 @@ main() async { ); initializeNotification(); - runApp(const FamStory()); + runApp( + ChangeNotifierProvider( + create: (context) => IdProvider(), + child: const FamStory(), + ), + ); } class FamStory extends StatelessWidget { @@ -82,11 +88,6 @@ class FamStory extends StatelessWidget { routes: { // TODO: 로딩에서 가족 여부 체크 - // '/': (context) => ChangeNotifierProvider( - // create: (context) => IdProvider(), - // child: const RootPage(), - // ), - '/': (context) => const LoadingScreen(), // '/': (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 b89488b..8596300 100644 --- a/lib/pages/alarm_page.dart +++ b/lib/pages/alarm_page.dart @@ -4,6 +4,11 @@ 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'; +import '../models/family_member_model.dart'; +import '../services/family_interaction_api_service.dart'; class AlarmPage extends StatefulWidget { const AlarmPage({Key? key}) : super(key: key); @@ -13,15 +18,30 @@ class AlarmPage extends StatefulWidget { } class _AlarmPageState extends State with TickerProviderStateMixin { - String buttonText = 'Clear'; - List interactions = []; + 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) { + familyMemberId = context.watch().familyMemberId; return Scaffold( appBar: PreferredSize( preferredSize: const Size.fromHeight(50.0), @@ -55,11 +75,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 +98,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), @@ -89,67 +116,76 @@ 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} ${getInteractionTypeText(item.interactionType)}", + style: TextStyle( + color: item.isChecked == 0 ? Colors.black : Colors.grey[400], + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ], ), - ], - ), - + ); + }, ); - }, - ), + } + }, ), - ), + ) + ], ), ), ), ), ), - - - Positioned( left: 0, right: 0, @@ -160,16 +196,13 @@ 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()); } - setState(() { - }); + setState(() {}); }, - style: ElevatedButton.styleFrom( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(35), @@ -193,4 +226,54 @@ class _AlarmPageState extends State with TickerProviderStateMixin { ), ); } + String getInteractionTypeText(int interactionType) { + switch (interactionType) { + case 4: + return "complimented you"; + case 3: + return "booed you"; + case 2: + return "sent heart to you"; + case 1: + return "poked you"; + default: + return "unclassified"; + } + } + + Widget getImageForInteractionType(int interactionType) { + switch (interactionType) { + case 4: + return Image.asset( + 'assets/images/thumbup.png', + width: 24, + height: 24, + fit: BoxFit.cover, + ); + case 3: + return Image.asset( + 'assets/images/thumbdown.png', // 싫어요 이미지에 대한 경로 + width: 24, + height: 24, + fit: BoxFit.cover, + ); + case 2: + return Image.asset( + 'assets/images/heart.png', // 훈훈해요 이미지에 대한 경로 + width: 24, + height: 24, + fit: BoxFit.cover, + ); + case 1: + return Image.asset( + 'assets/images/poke.png', // 슬퍼요 이미지에 대한 경로 + width: 24, + height: 24, + fit: BoxFit.cover, + ); + default: + return Container(); // 기본적으로 빈 컨테이너를 반환하거나 다른 기본 이미지를 설정할 수 있습니다. + } + } + } diff --git a/lib/pages/home_page.dart b/lib/pages/home_page.dart index 8c609c9..bb73e49 100644 --- a/lib/pages/home_page.dart +++ b/lib/pages/home_page.dart @@ -1,14 +1,34 @@ +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 '../root_page.dart'; import '../services/family_member_api_service.dart'; import 'setting_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; -enum Interaction { thumbUp, thumbDown, heart, poke } + int get title => const { + Interaction.thumbUp: 4, + Interaction.thumbDown: 3, + Interaction.heart: 2, + Interaction.poke: 1, + }[this]!; +} class HomePage extends StatefulWidget { const HomePage({super.key}); @@ -19,413 +39,644 @@ 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; + bool click1 = false; + bool click2 = false; + bool click3 = false; + bool click4 = false; + + List familyMembers = [ + // Add more members as needed + ]; + + @override + void initState() { + super.initState(); + _initData().then((_) {}); + } + + Future _initData() async { + familyId = context.read().familyId; + familyMemberID = context.read().familyMemberId; + message = context.read().introMessage; + _allFamilyMember = FamilyMemberApiService.getAllFamilyMember(familyId); + _allFamilyMember.then((value) { + setState(() { + familyMembers = value; + familyMembers + .removeWhere((element) => element.familyMemberId == familyMemberID); + familyMemberNum = familyMembers.length; + _textEditingController.text = context.read().introMessage; + }); + }); + } + + void interaction(Interaction data, int num) { + FamilyInteractionApiService.postFamilyInteraction( + familyMemberID, familyMembers[num].familyMemberId, data.title); + switch (data.title) { + case 4: + 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; + } + } - 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'), - )); + 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 { + TextEditingController newController = + TextEditingController(text: _textEditingController.text); + await showDialog( 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: _textEditingController, - maxLength: 11, + controller: newController, + maxLength: 12, + style: TextStyle( + color: AppColor.swatchColor, + fontWeight: FontWeight.bold, + ), decoration: InputDecoration( - labelText: _textEditingController.text, - suffixIcon: IconButton( - onPressed: () => _textEditingController.clear(), - icon: const Icon( - Icons.cancel, - size: 20, - )), - focusedErrorBorder: const UnderlineInputBorder( - borderSide: BorderSide( - color: AppColor.objectColor, + hintText: 'Enter your state!', + hintStyle: TextStyle( + color: AppColor.swatchColor, + ), + focusedErrorBorder: UnderlineInputBorder( + borderSide: BorderSide( + color: Colors.red, 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(); + Navigator.pop(context); + }); + } 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)), ), ], ); }, ); + setState(() { + _textEditingController = newController; + }); } @override Widget build(BuildContext context) { - // family 수를 여기에 저장 - int familyMember = 5; - - 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: () {}, - icon: const Icon(Icons.alarm_on), - color: AppColor.swatchColor, - iconSize: 35), - IconButton( - onPressed: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => SettingPage()), - ); - }, - icon: const Icon(Icons.settings), + Container( + width: 300, + height: 300, + decoration: BoxDecoration( color: AppColor.swatchColor, - iconSize: 35), - const SizedBox( - width: 20, + borderRadius: BorderRadius.circular(15), + border: Border.all( + color: + Colors.brown[200]!, // Adjust the color as needed + width: 5, // Adjust the width as needed + ), + ), ), - ], - ) - ], - ), - const SizedBox( - height: 140, - ), - Stack( - clipBehavior: Clip.none, - fit: StackFit.passthrough, - children: [ - 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: () async { - //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); - } - - */ - }, - ); - }, - onAccept: (data) { - interaction(data); - }, - ), - ), - 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); - }, - ), - ), - 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); - }, - ), - ), - Positioned( - top: 150, - left: -40, - child: DragTarget( - builder: (context, candidateData, rejectedData) { - return FamilyMemberButton( - buttonSize: 0.28, - imageSize: 50, - memberImage: 'assets/images/daughter.png', - onTap: () {}, - ); - }, - onAccept: (data) { - interaction(data); - }, - ), - ), - ] 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: () {}, + //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, + ), + ), + ), + ), + ) + ], + ), + ), ), - ), - ] else if (familyMember == 3) ...[ - Positioned( - top: -120, - left: 100, - child: FamilyMemberButton( - buttonSize: 0.36, - imageSize: 90, - memberImage: 'assets/images/son.png', - onTap: () {}, + // 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, + ), + ), + ), + ), + ) + ], + ), + ), ), - ), - Positioned( - top: 10, - left: -40, - child: FamilyMemberButton( - buttonSize: 0.36, - imageSize: 90, - memberImage: 'assets/images/son.png', - onTap: () {}, + // 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, + ), + ), + ), + ), + ) + ], + ), + ), ), - ), - ] else if (familyMember == 2) ...[ - Positioned( - top: -120, - left: -20, - child: FamilyMemberButton( - buttonSize: 0.4, - imageSize: 90, - memberImage: 'assets/images/son.png', - onTap: () {}, + // 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, + ), + ), + ), + ), + ) + ], + ), + ), ), - ), - ] else - ...[], - //Me round - Positioned( - top: 100, - left: 180, - child: FamilyMemberButton( - buttonSize: 0.4, - imageSize: 90, - memberImage: 'assets/images/son.png', - 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, + ///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.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, - ), - data: Interaction.thumbUp, - child: const InteractionButton( - interactionImage: 'assets/images/thumbup.png', - size: 55)), - ), + ), - ///SpeechBubble - 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.."), + ///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, + ), + data: Interaction.thumbUp, + child: const InteractionButton( + interactionImage: 'assets/images/thumbup.png', + size: 55)), + ), + ], ), ], ), - ], + ), ), ), ); @@ -448,8 +699,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, @@ -458,8 +707,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, ), @@ -515,41 +764,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 / 2, 0.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/login_sign_up_page.dart b/lib/pages/login_sign_up_page.dart index 2d14b34..05d4480 100644 --- a/lib/pages/login_sign_up_page.dart +++ b/lib/pages/login_sign_up_page.dart @@ -520,13 +520,11 @@ class _LoginSignUpPageState extends State { const FamilyJoinCreatePage())); } else { Navigator.pushReplacement( - context, - MaterialPageRoute( - builder: (context) => - ChangeNotifierProvider( - create: (context) => IdProvider(), - child: const RootPage(), - ))); + context, + MaterialPageRoute( + builder: (context) => 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/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/pages/setting_page.dart b/lib/pages/setting_page.dart index 62ca21d..a16acc3 100644 --- a/lib/pages/setting_page.dart +++ b/lib/pages/setting_page.dart @@ -1,8 +1,22 @@ +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/cupertino.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); @@ -13,20 +27,39 @@ class SettingPage extends StatefulWidget { class _SettingPageState extends State with TickerProviderStateMixin { final _familyNameController = TextEditingController(); + late Future> _familyInfo; + 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 = ''; String password = ''; int age = -1; int gender = -1; - bool autoLogin = false; + 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'); + + } + String? _selectedGender; final List _genders = ['Male', 'Female']; @@ -48,7 +81,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( @@ -61,7 +94,7 @@ class _SettingPageState extends State with TickerProviderStateMixin Positioned( left: 0, right: 0, - top: 120, + top: 80, child: Center( child: Container( margin: const EdgeInsetsDirectional.fromSTEB(20, 20, 20, 20), @@ -81,7 +114,7 @@ class _SettingPageState extends State with TickerProviderStateMixin crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( - margin: const EdgeInsets.only(top: 20), + margin: const EdgeInsets.only(top: 0), child: Form( child: Column( children: [ @@ -91,27 +124,27 @@ class _SettingPageState extends State with TickerProviderStateMixin crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("E-mail"), - Text("이 부분에 이메일 고정"), + const SizedBox(height: 10), + Text(context.read().email,), // TODO: 수정해야됨 Divider(color: AppColor.swatchColor,), ], ), ), const SizedBox(height: 10), - // Username Container( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text("Username"), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("Username"), + if (isEditMode) TextFormField( + autofocus: true, initialValue: username, decoration: InputDecoration( focusedBorder: const UnderlineInputBorder( - // 선택 시 하단 밑줄 색상 변경 borderSide: BorderSide(color: AppColor.swatchColor), ), enabledBorder: const UnderlineInputBorder( - // 비활성 시 하단 밑줄 색상 borderSide: BorderSide(color: AppColor.swatchColor), ), hintText: 'username', @@ -119,7 +152,6 @@ class _SettingPageState extends State with TickerProviderStateMixin fontSize: 14, color: Colors.grey.withOpacity(0.7), ), - contentPadding: const EdgeInsets.all(10), ), validator: (value) { if (value == null || value.isEmpty) { @@ -128,52 +160,70 @@ class _SettingPageState extends State with TickerProviderStateMixin return null; }, onSaved: (value) { - username = value!; + // Handle saving logic }, ), - ], - ), + if (!isEditMode) + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 16), + Text(context.read().username,), + const SizedBox(height: 4), + Divider(color: AppColor.swatchColor,), + ], + ) + ], ), - const SizedBox(height: 10), - // Nickname + ), + const SizedBox(height: 12), Container( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("Nickname"), - TextFormField( - initialValue: nickname, - decoration: InputDecoration( - focusedBorder: const UnderlineInputBorder( - // 선택 시 하단 밑줄 색상 변경 - borderSide: BorderSide(color: AppColor.swatchColor), - ), - enabledBorder: const UnderlineInputBorder( - // 비활성 시 하단 밑줄 색상 - borderSide: BorderSide(color: AppColor.swatchColor), - ), - hintText: 'nickname', - hintStyle: TextStyle( - fontSize: 14, - color: Colors.grey.withOpacity(0.7), + if (isEditMode) + TextFormField( + autofocus: true, + initialValue: username, + decoration: InputDecoration( + focusedBorder: const UnderlineInputBorder( + borderSide: BorderSide(color: AppColor.swatchColor), + ), + enabledBorder: const UnderlineInputBorder( + borderSide: BorderSide(color: AppColor.swatchColor), + ), + hintText: 'nickname', + hintStyle: TextStyle( + fontSize: 14, + color: Colors.grey.withOpacity(0.7), + ), + ), - contentPadding: const EdgeInsets.all(10), + validator: (value) { + if (value == null || value.isEmpty) { + return 'Please enter your name'; + } + return null; + }, + onSaved: (value) { + // Handle saving logic + }, ), - validator: (value) { - if (value == null || value.isEmpty) { - return 'Please enter your name'; - } - return null; - }, - onSaved: (value) { - username = value!; - }, - ), + if (!isEditMode) + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 16), + Text(context.read().nickname,), + const SizedBox(height: 4), + Divider(color: AppColor.swatchColor,), + ], + ) ], ), ), const SizedBox(height: 10), - // Age, Gender Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -184,6 +234,7 @@ class _SettingPageState extends State with TickerProviderStateMixin crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("Age"), + if (isEditMode) TextFormField( initialValue: age.toString(), keyboardType: TextInputType.number, @@ -201,7 +252,6 @@ class _SettingPageState extends State with TickerProviderStateMixin fontSize: 14, color: Colors.grey.withOpacity(0.7), ), - contentPadding: const EdgeInsets.all(10), ), validator: (value) { if (value == null || value.isEmpty) { @@ -216,12 +266,22 @@ class _SettingPageState extends State with TickerProviderStateMixin age = int.tryParse(value!)!; }, ), + if (!isEditMode) + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 20), + //Text(context.read().age), // TODO + Divider(color: AppColor.swatchColor,), + ], + ) ], ), ), const SizedBox(width: 20), // Gender - SizedBox( + if (isEditMode) + SizedBox( width: 150, child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -257,6 +317,25 @@ class _SettingPageState extends State with TickerProviderStateMixin ], ), ), + if (!isEditMode) + SizedBox( + width: 150, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("Gender"), + const SizedBox(height: 20), + Text( + context.read().gender == 0 ? "남자" : "여자", + // TODO: 수정해야됨 + style: TextStyle( + fontSize: 16, + ), + ), + Divider(color: AppColor.swatchColor,) + ], + ), + ), ], ), ], @@ -268,42 +347,82 @@ class _SettingPageState extends State with TickerProviderStateMixin ), ), Positioned( - left: 0, + left: 300, right: 0, - top: 580, + top: 110, child: Row( - mainAxisAlignment: MainAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - ElevatedButton( - onPressed: () async { - try { - // Access user input values - - // TODO: API 연결, 가족 멤버 생성, 가족 ID 가져오기 - } catch (e) { - print(e.toString()); - } - setState(() { - }); - }, - - style: ElevatedButton.styleFrom( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(35), + IconButton( + onPressed: () { + setState(() { + // Toggle the edit mode when the button is pressed + isEditMode = !isEditMode; + }); + }, + icon: const Icon(CupertinoIcons.pen)), + ], + ), + ), + if(!isEditMode) + Positioned( + left: 0, + right: 0, + top: 460, + child: Center( + child: Container( + width: 350, // Set the width of the Container + height: 120, // Set the height of the Container + margin: const EdgeInsetsDirectional.fromSTEB(20, 20, 20, 20), + padding: const EdgeInsets.all(20.0), + decoration: BoxDecoration( + color: AppColor.objectColor, + borderRadius: BorderRadius.circular(15.0), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + blurRadius: 20, + spreadRadius: 5, ), - backgroundColor: AppColor.textColor, // 항상 활성화된 색상 - minimumSize: const Size(120, 40), - ), - child: Text( - buttonText2, - style: const TextStyle( - color: AppColor.objectColor, - fontWeight: FontWeight.bold, - fontSize: 18, + ], + ), + child: Column( + children: [ + SizedBox(height: 5,), + Align( + child: Text( + 'Send an invitation!', + style: TextStyle( + fontSize: 18, + color: AppColor.textColor, + fontWeight: FontWeight.bold, + ), + ), ), - ), + SizedBox(height: 15,), + Align( + alignment: Alignment.center, + child: Text( + context.read().familyKeyCode, + style: TextStyle( + fontSize: 20, + color: Colors.black, + fontWeight: FontWeight.bold, + ), + ), + ), + ], ), - SizedBox(width: 32), + ), + ), + ), + Positioned( + left: 0, + right: 0, + top: 620, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ ElevatedButton( onPressed: () { setState(() { @@ -327,7 +446,9 @@ class _SettingPageState extends State with TickerProviderStateMixin Center( child: TextButton( onPressed: () { - Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) => const RootPage())); + Navigator.pop(context); + Navigator.pop(context); + Navigator.push(context, MaterialPageRoute(builder: (context) => const LoginSignUpPage())); }, style: TextButton.styleFrom( foregroundColor: AppColor.objectColor, diff --git a/lib/root_page.dart b/lib/root_page.dart index 231ec94..42da9c2 100644 --- a/lib/root_page.dart +++ b/lib/root_page.dart @@ -1,14 +1,19 @@ 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'; 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 { @@ -22,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; @@ -29,6 +35,18 @@ class _RootPageState extends State { String _nickname = ''; String _introMessage = ''; + int _memberNumber = 0; + String _familyName = ''; + String _createdDate = ''; + String _familyKeyCode = ''; + + + int _userId = 0; + int _age = 0; + int _gender = 0; + String _email = ''; + String _nusername = ''; + final List _pages = [ const HomePage(), const ChatPage(), @@ -36,64 +54,164 @@ 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().then((_) {}); // 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 { _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().setRole(_role); + context.read().setName(_name); + context.read().setNicKName(_nickname); + context.read().setIntroMessage(_introMessage); + context.read().setFamilyId(_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) { - 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초 텀 주는 부분 + 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( + 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; 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(); 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"