From a339aca51fe8b522664169b95ac8d1ad815c2979 Mon Sep 17 00:00:00 2001 From: ZomSik Date: Sat, 11 May 2024 05:29:15 +0900 Subject: [PATCH] =?UTF-8?q?#59=20=EC=84=9C=EB=B2=84=20=EC=97=B0=EA=B2=B0?= =?UTF-8?q?=20=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/.gitignore | 3 +- frontend/android/app/google-service.json | 1 + frontend/devtools_options.yaml | 1 + frontend/lib/http.dart | 79 +++- .../lib/provider/secure_storage_provider.dart | 2 +- .../home/bookreport/bookreport_screen.dart | 1 + .../bookreport_template_screen.dart | 1 + .../bookreport/bookreport_viewing_screen.dart | 15 +- .../bookreport/bookreport_writing_screen.dart | 25 +- .../home/mypage/makelibrary_screen.dart | 52 ++- .../screens/home/mypage/mypage_screen.dart | 349 ++++++++++-------- .../screens/home/mypage/signup_screen.dart | 149 ++------ .../Flutter/GeneratedPluginRegistrant.swift | 2 + frontend/pubspec.lock | 50 ++- frontend/pubspec.yaml | 4 +- 15 files changed, 446 insertions(+), 288 deletions(-) create mode 100644 frontend/android/app/google-service.json create mode 100644 frontend/devtools_options.yaml diff --git a/frontend/.gitignore b/frontend/.gitignore index 6f4ae472c6..d88952ba17 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -245,4 +245,5 @@ fabric.properties !/gradle/wrapper/gradle-wrapper.jar #select file -lib/secret.dart \ No newline at end of file +lib/secret.dart +android\app\google-service.json \ No newline at end of file diff --git a/frontend/android/app/google-service.json b/frontend/android/app/google-service.json new file mode 100644 index 0000000000..d035e9ad45 --- /dev/null +++ b/frontend/android/app/google-service.json @@ -0,0 +1 @@ +{"installed":{"client_id":"801277628829-qba15ch2hanumq1v4hpe94c7rmt6k8ch.apps.googleusercontent.com","project_id":"bookmeeting-422618","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs"}} \ No newline at end of file diff --git a/frontend/devtools_options.yaml b/frontend/devtools_options.yaml new file mode 100644 index 0000000000..7e7e7f67de --- /dev/null +++ b/frontend/devtools_options.yaml @@ -0,0 +1 @@ +extensions: diff --git a/frontend/lib/http.dart b/frontend/lib/http.dart index 2109ccf39e..8329ee972e 100644 --- a/frontend/lib/http.dart +++ b/frontend/lib/http.dart @@ -93,7 +93,7 @@ Future login(String email) async { //유저 정보 가져오기 Future getUserInfo(String id, String token) async { - var address = Uri.parse(BASE_URL + "/member/$id"); + var address = Uri.parse("$BASE_URL/member/$id"); http.Response res = await http.get( address, headers: { @@ -212,3 +212,80 @@ Future> contentLoad(dynamic token, int id) async { } return contentList; } + +// 모임 가입하기 +Future groupJoin(String token, int clubId) async { + var address = Uri.parse(BASE_URL + "/club/join?clubId=$clubId"); + http.Response res = await http.get( + address, + headers: { + "Content-Type": "application/json", + "Authorization": "Bearer $token", + }, + ); + final data = res.body; + + return data; +} + +//모임 나가기 +Future groupOut(String token, int clubId) async { + var address = Uri.parse(BASE_URL + "/club/out?clubId=$clubId"); + http.Response res = await http.get( + address, + headers: { + "Content-Type": "application/json", + "Authorization": "Bearer $token", + }, + ); + final data = res.body; + + return data; +} + +//서재 불러오기 +Future> getLibrary(String token) async { + List libraryList = []; + var address = Uri.parse("$BASE_URL/library"); + http.Response res = await http.get( + address, + headers: { + "Content-Type": "application/json", + "Authorization": 'Bearer $token', + }, + ); + final data = json.decode(utf8.decode(res.bodyBytes)); + for (int i = 0; i < data.length; i++) { + libraryList.add(data[i]); + } + return libraryList; +} + +//서재에 책 추가하기 +Future addBookToLibrary( + String token, + String isbn, + String title, + String author, + String publisher, + String publishDate, + String imageUrl) async { + var address = Uri.parse("$BASE_URL/library/add"); + http.Response res = await http.post( + address, + headers: { + "Content-Type": "application/json", + "Authorization": 'Bearer $token', + }, + body: json.encode({ + "isbn": isbn, + "title": title, + "author": author, + "publisher": publisher, + "publishDate": publishDate, + "imageUrl": imageUrl, + }), + ); + final data = res.body; + return data; +} diff --git a/frontend/lib/provider/secure_storage_provider.dart b/frontend/lib/provider/secure_storage_provider.dart index fa7a6097af..e8c50449ec 100644 --- a/frontend/lib/provider/secure_storage_provider.dart +++ b/frontend/lib/provider/secure_storage_provider.dart @@ -24,7 +24,7 @@ class SecureStorageService extends ChangeNotifier { class SecureStorageProvider extends StatelessWidget { final Widget child; - const SecureStorageProvider({required this.child}); + const SecureStorageProvider({super.key, required this.child}); @override Widget build(BuildContext context) { diff --git a/frontend/lib/screens/home/bookreport/bookreport_screen.dart b/frontend/lib/screens/home/bookreport/bookreport_screen.dart index 205e970284..07a869b59c 100644 --- a/frontend/lib/screens/home/bookreport/bookreport_screen.dart +++ b/frontend/lib/screens/home/bookreport/bookreport_screen.dart @@ -22,6 +22,7 @@ class _BookReportState extends State { color: Colors.white, fontFamily: 'Noto Sans KR', fontWeight: FontWeight.w700, + fontSize: 20, ), backgroundColor: const Color(0xFF0E9913), centerTitle: true, diff --git a/frontend/lib/screens/home/bookreport/bookreport_template_screen.dart b/frontend/lib/screens/home/bookreport/bookreport_template_screen.dart index d034583487..63f693d842 100644 --- a/frontend/lib/screens/home/bookreport/bookreport_template_screen.dart +++ b/frontend/lib/screens/home/bookreport/bookreport_template_screen.dart @@ -15,6 +15,7 @@ class BookReportTemplateScreen extends StatelessWidget { color: Colors.white, fontFamily: 'Noto Sans KR', fontWeight: FontWeight.w700, + fontSize: 20, ), backgroundColor: const Color(0xFF0E9913), centerTitle: true, diff --git a/frontend/lib/screens/home/bookreport/bookreport_viewing_screen.dart b/frontend/lib/screens/home/bookreport/bookreport_viewing_screen.dart index 0b518e1847..e3061ecd3c 100644 --- a/frontend/lib/screens/home/bookreport/bookreport_viewing_screen.dart +++ b/frontend/lib/screens/home/bookreport/bookreport_viewing_screen.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:frontend/http.dart'; -import 'package:frontend/screens/home/search/search_screen.dart'; +import 'package:frontend/provider/secure_storage_provider.dart'; +import 'package:provider/provider.dart'; class BookReportViewingScreen extends StatefulWidget { const BookReportViewingScreen({super.key}); @@ -19,9 +20,11 @@ class _BookReportViewingState extends State { String _body = ''; final String _author = "작가"; final String _publisher = "출판사"; + // ignore: prefer_typing_uninitialized_variables + var token; void initializeContentData(dynamic token) async { - _contentData = await contentLoad(token[0], 1); + _contentData = await contentLoad(token, 2); _template = _contentData[0]['type'] as String; _title = _contentData[0]['title'] as String; _body = _contentData[0]['body'] as String; @@ -30,9 +33,16 @@ class _BookReportViewingState extends State { @override void initState() { super.initState(); + _initUserState(); initializeContentData(token); } + Future _initUserState() async { + final secureStorage = + Provider.of(context, listen: false); + token = await secureStorage.readData("token"); + } + @override void dispose() { super.dispose(); @@ -47,6 +57,7 @@ class _BookReportViewingState extends State { color: Colors.white, fontFamily: 'Noto Sans KR', fontWeight: FontWeight.w700, + fontSize: 20, ), backgroundColor: const Color(0xFF0E9913), centerTitle: true, diff --git a/frontend/lib/screens/home/bookreport/bookreport_writing_screen.dart b/frontend/lib/screens/home/bookreport/bookreport_writing_screen.dart index 072ddb161d..b35a54a1d6 100644 --- a/frontend/lib/screens/home/bookreport/bookreport_writing_screen.dart +++ b/frontend/lib/screens/home/bookreport/bookreport_writing_screen.dart @@ -1,7 +1,9 @@ import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:frontend/http.dart'; import 'package:frontend/provider/bookinfo_provider.dart'; -import 'package:frontend/screens/home/search/search_screen.dart'; +import 'package:frontend/provider/secure_storage_provider.dart'; +import 'package:go_router/go_router.dart'; import 'package:provider/provider.dart'; class BookReportWritingScreen extends StatefulWidget { @@ -36,6 +38,7 @@ class _BookReportWritingState extends State { final TextEditingController _answerController2 = TextEditingController(); final TextEditingController _answerController3 = TextEditingController(); final TextEditingController _answerController4 = TextEditingController(); + var token; // Predefined values for author and publisher final String _author = "작가"; @@ -48,6 +51,7 @@ class _BookReportWritingState extends State { void initState() { super.initState(); + _initUserState(); // Initialize _keyboardVisibilityObserver and _keyboardVisibilityObserverWrapper final keyboardVisibilityObserver = _KeyboardVisibilityObserver((bool visible) { @@ -66,6 +70,12 @@ class _BookReportWritingState extends State { WidgetsBinding.instance.addObserver(_keyboardVisibilityObserverWrapper); } + Future _initUserState() async { + final secureStorage = + Provider.of(context, listen: false); + token = await secureStorage.readData("token"); + } + @override void dispose() { // Remove the keyboard visibility listener @@ -106,6 +116,7 @@ class _BookReportWritingState extends State { color: Colors.white, fontFamily: 'Noto Sans KR', fontWeight: FontWeight.w700, + fontSize: 20, ), backgroundColor: const Color(0xFF0E9913), centerTitle: true, @@ -305,8 +316,16 @@ class _BookReportWritingState extends State { child: ElevatedButton( onPressed: () { // 글 저장 기능 추가 - contentCreate(token[0], 1, 3, '독후감', '제목', '내용', '2021-10-10', - '2021-10-10'); + contentCreate( + token, + 1, + 3, + _template, + _bookTitleController.text, + _writingController.text, + _startDate.toString(), + _endDate.toString()); + context.pop(); }, child: const Text('저장'), ), diff --git a/frontend/lib/screens/home/mypage/makelibrary_screen.dart b/frontend/lib/screens/home/mypage/makelibrary_screen.dart index 90ebdcd956..2c6155a10a 100644 --- a/frontend/lib/screens/home/mypage/makelibrary_screen.dart +++ b/frontend/lib/screens/home/mypage/makelibrary_screen.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:go_router/go_router.dart'; class MakeLibraryScreen extends StatefulWidget { const MakeLibraryScreen({super.key}); @@ -10,13 +11,22 @@ class MakeLibraryScreen extends StatefulWidget { } class _MakeLibraryScreenState extends State { + String _appBarTitle = '서재 이름'; + @override Widget build(BuildContext context) { return ScreenUtilInit( designSize: const Size(390, 675), builder: (context, _) => Scaffold( appBar: AppBar( - title: const Text('서재 이름'), + leading: IconButton( + icon: const Icon(Icons.arrow_back), + color: Colors.white, + onPressed: () { + context.pop(); + }, + ), + title: Text(_appBarTitle), titleTextStyle: const TextStyle( color: Colors.white, fontFamily: 'Noto Sans KR', @@ -25,6 +35,46 @@ class _MakeLibraryScreenState extends State { ), backgroundColor: const Color(0xFF0E9913), centerTitle: true, + actions: [ + IconButton( + icon: const Icon(Icons.more_vert), + color: Colors.white, + onPressed: () { + showDialog( + context: context, + builder: (BuildContext context) { + String newName = ''; + return AlertDialog( + title: const Text("서재 이름 입력"), + content: TextField( + onChanged: (value) { + newName = value; + }, + decoration: const InputDecoration(hintText: "새로운 서재"), + ), + actions: [ + TextButton( + onPressed: () { + setState(() { + _appBarTitle = newName; + }); + Navigator.of(context).pop(); + }, + child: const Text("확인"), + ), + TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: const Text("취소"), + ), + ], + ); + }, + ); + }, + ), + ], ), body: Column( children: [ diff --git a/frontend/lib/screens/home/mypage/mypage_screen.dart b/frontend/lib/screens/home/mypage/mypage_screen.dart index cc0cd6fd07..e4be2b8493 100644 --- a/frontend/lib/screens/home/mypage/mypage_screen.dart +++ b/frontend/lib/screens/home/mypage/mypage_screen.dart @@ -1,6 +1,11 @@ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:frontend/http.dart'; +import 'package:frontend/provider/secure_storage_provider.dart'; import 'package:go_router/go_router.dart'; +import 'package:provider/provider.dart'; +import 'package:google_sign_in/google_sign_in.dart'; class MypageScreen extends StatefulWidget { const MypageScreen({super.key}); @@ -28,6 +33,17 @@ class Book { required this.type, required this.imageUrl, }); + + // factory Book.fromJson(Map json) { + // return Book( + // id: json['id'] as int, + // writer: json['writer'] as String, + // clubId: json['clubId'] as int, + // title: json['title'] as String, + // body: json['body'] as String, + // isSticky: json['isSticky'] as bool, + // ); + // } } class Library { @@ -54,64 +70,7 @@ class _MypageScreenState extends State with SingleTickerProviderStateMixin { late TabController _tabController; - // Example list of books - List books = [ - Book( - title: '원씽(The One Thing)', - author: 'Gary Keller, Jay Papasan', - publisher: 'Business Books', - startDate: '2024.02.13', - endDate: '2024.02.29', - type: '독후감', - imageUrl: 'https://via.placeholder.com/60x86', - ), - Book( - title: '원씽(The One Thing)2', - author: 'Gary Keller, Jay Papasan', - publisher: 'Business Books', - startDate: '2024.01.13', - endDate: '2024.01.29', - type: '독후감', - imageUrl: 'https://via.placeholder.com/60x86', - ), - Book( - title: '원씽(The One Thing)', - author: 'Gary Keller, Jay Papasan', - publisher: 'Business Books', - startDate: '2024.02.13', - endDate: '2024.02.29', - type: '독후감', - imageUrl: 'https://via.placeholder.com/60x86', - ), - Book( - title: '원씽(The One Thing)2', - author: 'Gary Keller, Jay Papasan', - publisher: 'Business Books', - startDate: '2024.01.13', - endDate: '2024.01.29', - type: '독후감', - imageUrl: 'https://via.placeholder.com/60x86', - ), - Book( - title: '원씽(The One Thing)', - author: 'Gary Keller, Jay Papasan', - publisher: 'Business Books', - startDate: '2024.02.13', - endDate: '2024.02.29', - type: '독후감', - imageUrl: 'https://via.placeholder.com/60x86', - ), - Book( - title: '원씽(The One Thing)2', - author: 'Gary Keller, Jay Papasan', - publisher: 'Business Books', - startDate: '2024.01.13', - endDate: '2024.01.29', - type: '독후감', - imageUrl: 'https://via.placeholder.com/60x86', - ), - // Add more books here as needed - ]; + List books = []; List libraries = [ Library( @@ -162,16 +121,46 @@ class _MypageScreenState extends State ), ]; + var id; + var token; + var isLogin; + @override void initState() { super.initState(); + _initUserState(); + // _initBookState(); _tabController = TabController(length: 2, vsync: this); books.sort((a, b) => a.endDate.compareTo(b.endDate)); } + Future _initUserState() async { + final secureStorage = + Provider.of(context, listen: false); + token = await secureStorage.readData("token"); + print(token); + if (token == null) { + isLogin = false; + } else { + isLogin = true; + } + } + +// Future _initBookState() async { +// final secureStorage = +// Provider.of(context, listen: false); +// id = await secureStorage.readData("id"); +// token = await secureStorage.readData("token"); +// Map userInfo = await getUserInfo(id, token); +// if (userInfo.containsKey("contentList")) { +// books = List.from(userInfo["contentList"].map((bookJson) => Book.fromJson(bookJson))); +// } else { +// books = []; // Handle case when "postList" is not present or is empty +// } +// } + @override Widget build(BuildContext context) { - var isLogin = false; return ScreenUtilInit( designSize: const Size(390, 675), builder: (context, _) => Scaffold( @@ -223,36 +212,41 @@ class LoggedWidget extends StatelessWidget { @override Widget build(BuildContext context) { - return Container( - padding: EdgeInsets.all(15.w), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(12), - color: Colors.grey[200], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - CircleAvatar( - radius: 40.w, - backgroundImage: - const NetworkImage('https://via.placeholder.com/70x100'), - ), - SizedBox(width: 16.w), - Text( - 'name', - style: TextStyle(fontSize: 20.sp, fontWeight: FontWeight.bold), - ), - SizedBox(width: 65.w), - ElevatedButton( - onPressed: () {}, - child: const Text('회원 정보 수정'), - ), - ], - ), - ], - ), + return FutureBuilder( + future: Provider.of(context, listen: false) + .readData("name"), + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const CircularProgressIndicator(); + } else if (snapshot.hasError) { + return Text('Error: ${snapshot.error}'); + } else { + final name = snapshot.data ?? ''; + return Container( + padding: EdgeInsets.all(15.w), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + color: Colors.grey[200], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + SizedBox(width: 16.w), + Text( + name, + style: TextStyle( + fontSize: 20.sp, fontWeight: FontWeight.bold), + ), + SizedBox(width: 65.w), + ], + ), + ], + ), + ); + } + }, ); } } @@ -286,7 +280,8 @@ class LoginWidget extends StatelessWidget { SizedBox(width: 76.w), ElevatedButton( onPressed: () { - context.push('/login'); + //context.push('/login'); + signInWithGoogle(context); }, child: const Text('로그인'), ), @@ -299,6 +294,27 @@ class LoginWidget extends StatelessWidget { } } +void signInWithGoogle(BuildContext context) async { + final secureStorage = + Provider.of(context, listen: false); + final GoogleSignInAccount? googleUser = await GoogleSignIn().signIn(); + + if (googleUser != null) { + // print('name = ${googleUser.displayName}'); + // print('email = ${googleUser.email}'); + // print('id = ${googleUser.id}'); + dynamic userInfo = await login(googleUser.email); + await secureStorage.saveData('userID', googleUser.email); + if (userInfo['token'] == null) { + context.push('/signup'); + } + print(userInfo['token']); + print(userInfo['id']); + await secureStorage.saveData("token", userInfo['token']); + await secureStorage.saveData("id", userInfo['id']); + } +} + class BookReportWidget extends StatelessWidget { final List books; @@ -310,95 +326,100 @@ class BookReportWidget extends StatelessWidget { itemCount: books.length, itemBuilder: (context, index) { final book = books[index]; - return SizedBox( - height: 101.h, - child: Stack( - children: [ - Positioned( - left: 90.w, - top: 75.h, - child: SizedBox( - width: 240.w, - height: 16.h, - child: Text( - '${book.startDate} ~ ${book.endDate}', - style: TextStyle( - color: const Color(0xFF6E767F), - fontSize: 9.sp, - fontFamily: 'Noto Sans KR', - fontWeight: FontWeight.w700, + return GestureDetector( + onTap: () async { + context.push('/bookreport_viewing'); + }, + child: SizedBox( + height: 101.h, + child: Stack( + children: [ + Positioned( + left: 90.w, + top: 75.h, + child: SizedBox( + width: 240.w, + height: 16.h, + child: Text( + '${book.startDate} ~ ${book.endDate}', + style: TextStyle( + color: const Color(0xFF6E767F), + fontSize: 9.sp, + fontFamily: 'Noto Sans KR', + fontWeight: FontWeight.w700, + ), ), ), ), - ), - Positioned( - left: 90.w, - top: 60.h, - child: SizedBox( - width: 240.w, - height: 45.h, - child: Text( - book.type, - style: TextStyle( - color: const Color(0xFF6E767F), - fontSize: 9.sp, - fontFamily: 'Noto Sans KR', - fontWeight: FontWeight.w700, + Positioned( + left: 90.w, + top: 60.h, + child: SizedBox( + width: 240.w, + height: 45.h, + child: Text( + book.type, + style: TextStyle( + color: const Color(0xFF6E767F), + fontSize: 9.sp, + fontFamily: 'Noto Sans KR', + fontWeight: FontWeight.w700, + ), ), ), ), - ), - Positioned( - left: 90.w, - top: 43.h, - child: SizedBox( - width: 240.w, - height: 16.h, - child: Text( - '${book.author} | ${book.publisher}', - style: TextStyle( - color: Colors.black, - fontSize: 10.sp, - fontFamily: 'Noto Sans KR', - fontWeight: FontWeight.w700, + Positioned( + left: 90.w, + top: 43.h, + child: SizedBox( + width: 240.w, + height: 16.h, + child: Text( + '${book.author} | ${book.publisher}', + style: TextStyle( + color: Colors.black, + fontSize: 10.sp, + fontFamily: 'Noto Sans KR', + fontWeight: FontWeight.w700, + ), ), ), ), - ), - Positioned( - left: 90.w, - top: 15.h, - child: SizedBox( - width: 240.w, - child: Text( - book.title, - style: TextStyle( - color: Colors.black, - fontSize: 20.sp, - fontFamily: 'Noto Sans KR', - fontWeight: FontWeight.w700, + Positioned( + left: 90.w, + top: 15.h, + child: SizedBox( + width: 240.w, + child: Text( + book.title, + style: TextStyle( + color: Colors.black, + fontSize: 20.sp, + fontFamily: 'Noto Sans KR', + fontWeight: FontWeight.w700, + ), ), ), ), - ), - Positioned( - left: 15.w, - top: 15.h, - child: Container( - width: 60.w, - height: 85.68.h, - decoration: ShapeDecoration( - image: DecorationImage( - image: NetworkImage(book.imageUrl), - fit: BoxFit.fill, - ), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(3), + Positioned( + left: 15.w, + top: 15.h, + child: Container( + width: 60.w, + height: 85.68.h, + decoration: ShapeDecoration( + image: DecorationImage( + image: NetworkImage(book.imageUrl), + fit: BoxFit.fill, + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(3), + ), ), ), ), - ), - ], + ], + ), ), ); }, diff --git a/frontend/lib/screens/home/mypage/signup_screen.dart b/frontend/lib/screens/home/mypage/signup_screen.dart index 26bb1a8bb7..0fd34c5b5b 100644 --- a/frontend/lib/screens/home/mypage/signup_screen.dart +++ b/frontend/lib/screens/home/mypage/signup_screen.dart @@ -1,5 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:frontend/provider/secure_storage_provider.dart'; +import 'package:frontend/http.dart'; +import 'package:go_router/go_router.dart'; +import 'package:provider/provider.dart'; class SignupScreen extends StatefulWidget { const SignupScreen({super.key}); @@ -10,9 +14,8 @@ class SignupScreen extends StatefulWidget { class _SignupState extends State { final TextEditingController _nameController = TextEditingController(); - final TextEditingController _emailController = TextEditingController(); - final TextEditingController _passwordController = TextEditingController(); final TextEditingController _ageController = TextEditingController(); + final TextEditingController _genderController = TextEditingController(); String? _validateName(String? value) { if (value == null || value.isEmpty) { @@ -21,20 +24,6 @@ class _SignupState extends State { return null; } - String? _validateEmail(String? value) { - if (value == null || value.isEmpty || !value.contains('@')) { - return '유효한 이메일을 입력하세요'; - } - return null; - } - - String? _validatePassword(String? value) { - if (value == null || value.isEmpty) { - return '비밀번호를 입력하세요'; - } - return null; - } - String? _validateAge(String? value) { if (value == null || value.isEmpty) { return '나이를 입력하세요'; @@ -46,6 +35,13 @@ class _SignupState extends State { return null; } + String? _validateGender(String? value) { + if (value == null || value.isEmpty) { + return '성별을 입력하세요'; + } + return null; + } + @override Widget build(BuildContext context) { return ScreenUtilInit( @@ -135,7 +131,7 @@ class _SignupState extends State { ], ), ), - SizedBox(height: 20.h), + SizedBox(height: 30.h), SizedBox( width: 330.w, height: 39.h, @@ -163,52 +159,13 @@ class _SignupState extends State { width: 330.w, child: TextFormField( style: const TextStyle(fontSize: 14), - controller: _emailController, - decoration: const InputDecoration( - hintText: '이메일', - border: InputBorder.none, - ), - validator: _validateEmail, - ), - ), - ), - ), - ], - ), - ), - SizedBox(height: 20.h), - SizedBox( - width: 330.w, - height: 39.h, - child: Stack( - children: [ - Positioned( - left: 0.w, - top: 0.h, - child: Container( - width: 330.w, - height: 39.h, - decoration: ShapeDecoration( - shape: RoundedRectangleBorder( - side: const BorderSide( - width: 1, color: Color(0xFFA8AFB6)), - borderRadius: BorderRadius.circular(25), - ), - ), - ), - ), - Positioned( - left: 20.w, - child: Expanded( - child: SizedBox( - width: 330.w, - child: TextField( - style: const TextStyle(fontSize: 14), - controller: _passwordController, + controller: _ageController, + keyboardType: TextInputType.number, decoration: const InputDecoration( - hintText: '비밀번호', + hintText: '나이', border: InputBorder.none, ), + validator: _validateAge, ), ), ), @@ -216,7 +173,7 @@ class _SignupState extends State { ], ), ), - SizedBox(height: 20.h), + SizedBox(height: 30.h), SizedBox( width: 330.w, height: 39.h, @@ -244,10 +201,9 @@ class _SignupState extends State { width: 330.w, child: TextFormField( style: const TextStyle(fontSize: 14), - controller: _ageController, - keyboardType: TextInputType.number, + controller: _genderController, decoration: const InputDecoration( - hintText: '나이', + hintText: '성별', border: InputBorder.none, ), validator: _validateAge, @@ -260,13 +216,26 @@ class _SignupState extends State { ), SizedBox(height: 50.h), GestureDetector( - onTap: () { - if (_validateEmail(_emailController.text) == null && - _validateAge(_ageController.text) == null && + onTap: () async { + if (_validateAge(_ageController.text) == null && _validateName(_nameController.text) == null && - _validatePassword(_passwordController.text) == - null) { + _validateGender(_genderController.text) == null) { print("성공"); + final secureStorage = + Provider.of(context, + listen: false); + await singup( + (await secureStorage.readData("userID")) ?? '', + _nameController.text, + int.parse(_ageController.text), + _genderController.text); + await secureStorage.saveData( + 'name', _nameController.text); + await secureStorage.saveData( + 'age', _ageController.text); + await secureStorage.saveData( + 'gender', _genderController.text); + context.pop(); } else { print("실패"); } @@ -292,48 +261,6 @@ class _SignupState extends State { ), ), ), - SizedBox(height: 30.h), - GestureDetector( - onTap: () { - // Handle Google signup action - }, - child: Container( - width: 330.w, - height: 45.h, - decoration: ShapeDecoration( - shape: RoundedRectangleBorder( - side: const BorderSide(width: 1.5), - borderRadius: BorderRadius.circular(25), - ), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SizedBox( - width: 28.w, - height: 28.h, - child: AspectRatio( - aspectRatio: 28.0 / 28.0, - child: Image.network( - 'https://via.placeholder.com/28x28', - fit: BoxFit.fitWidth, - ), - ), - ), - SizedBox(width: 10.w), - Text( - '구글로 회원가입하기', - style: TextStyle( - color: Colors.black, - fontSize: 18.sp, - fontFamily: 'Noto Sans KR', - fontWeight: FontWeight.w400, - ), - ), - ], - ), - ), - ), ], ), ), diff --git a/frontend/macos/Flutter/GeneratedPluginRegistrant.swift b/frontend/macos/Flutter/GeneratedPluginRegistrant.swift index 15a1671b02..3b3b576b5f 100644 --- a/frontend/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/frontend/macos/Flutter/GeneratedPluginRegistrant.swift @@ -6,9 +6,11 @@ import FlutterMacOS import Foundation import flutter_secure_storage_macos +import google_sign_in_ios import path_provider_foundation func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin")) + FLTGoogleSignInPlugin.register(with: registry.registrar(forPlugin: "FLTGoogleSignInPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) } diff --git a/frontend/pubspec.lock b/frontend/pubspec.lock index 8329c13697..58d3628926 100644 --- a/frontend/pubspec.lock +++ b/frontend/pubspec.lock @@ -152,6 +152,54 @@ packages: url: "https://pub.dev" source: hosted version: "13.2.3" + google_identity_services_web: + dependency: transitive + description: + name: google_identity_services_web + sha256: "9482364c9f8b7bd36902572ebc3a7c2b5c8ee57a9c93e6eb5099c1a9ec5265d8" + url: "https://pub.dev" + source: hosted + version: "0.3.1+1" + google_sign_in: + dependency: "direct main" + description: + name: google_sign_in + sha256: "0b8787cb9c1a68ad398e8010e8c8766bfa33556d2ab97c439fb4137756d7308f" + url: "https://pub.dev" + source: hosted + version: "6.2.1" + google_sign_in_android: + dependency: transitive + description: + name: google_sign_in_android + sha256: "7647893c65e6720973f0e579051c8f84b877b486614d9f70a404259c41a4632e" + url: "https://pub.dev" + source: hosted + version: "6.1.23" + google_sign_in_ios: + dependency: transitive + description: + name: google_sign_in_ios + sha256: a058c9880be456f21e2e8571c1126eaacd570bdc5b6c6d9d15aea4bdf22ca9fe + url: "https://pub.dev" + source: hosted + version: "5.7.6" + google_sign_in_platform_interface: + dependency: transitive + description: + name: google_sign_in_platform_interface + sha256: "1f6e5787d7a120cc0359ddf315c92309069171306242e181c09472d1b00a2971" + url: "https://pub.dev" + source: hosted + version: "2.4.5" + google_sign_in_web: + dependency: transitive + description: + name: google_sign_in_web + sha256: fc0f14ed45ea616a6cfb4d1c7534c2221b7092cc4f29a709f0c3053cc3e821bd + url: "https://pub.dev" + source: hosted + version: "0.12.4" http: dependency: "direct main" description: @@ -455,4 +503,4 @@ packages: version: "5.3.6" sdks: dart: ">=3.3.0 <4.0.0" - flutter: ">=3.16.0" + flutter: ">=3.19.0" diff --git a/frontend/pubspec.yaml b/frontend/pubspec.yaml index 5986322257..4a43846498 100644 --- a/frontend/pubspec.yaml +++ b/frontend/pubspec.yaml @@ -30,16 +30,14 @@ environment: dependencies: flutter: sdk: flutter - go_router: ^13.2.3 flutter_screenutil: ^5.9.0 - http: ^1.2.1 provider: ^6.1.2 xml: ^6.5.0 xml2json: ^5.3.1 - flutter_secure_storage: ^9.0.0 + google_sign_in: ^6.2.1 # The following adds the Cupertino Icons font to your application.