From 38584387bfbe0aa2a761dbe5d363a09bc6560221 Mon Sep 17 00:00:00 2001 From: dayoung20 Date: Fri, 31 Jan 2025 11:07:07 +0900 Subject: [PATCH 1/7] =?UTF-8?q?feat:=20=EC=8A=A4=ED=81=AC=EB=9E=A9=20UI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/data/models/dictionary_model.dart | 3 ++ economic_fe/lib/main.dart | 2 +- .../lib/view/screens/dictionary_page.dart | 47 ++++++++++--------- economic_fe/pubspec.lock | 30 ++++++------ 4 files changed, 44 insertions(+), 38 deletions(-) diff --git a/economic_fe/lib/data/models/dictionary_model.dart b/economic_fe/lib/data/models/dictionary_model.dart index 12640c7..64213b3 100644 --- a/economic_fe/lib/data/models/dictionary_model.dart +++ b/economic_fe/lib/data/models/dictionary_model.dart @@ -9,11 +9,13 @@ class DictionaryModel with ChangeNotifier { int? termId; String? termName; String? termDescription; + bool? isScraped; DictionaryModel({ this.termId, this.termName, this.termDescription, + this.isScraped, }); factory DictionaryModel.fromJson(Map json) { @@ -21,6 +23,7 @@ class DictionaryModel with ChangeNotifier { termId: json['termId'], termName: json['termName'], termDescription: json['termDescription'], + isScraped: json['isScraped'], ); } } diff --git a/economic_fe/lib/main.dart b/economic_fe/lib/main.dart index 5484eeb..82b35d8 100644 --- a/economic_fe/lib/main.dart +++ b/economic_fe/lib/main.dart @@ -21,7 +21,7 @@ class RippleApp extends StatelessWidget { Widget build(BuildContext context) { return GetMaterialApp( title: 'Ripple', - initialRoute: '/mypage', + initialRoute: '/dictionary', getPages: UserRouter.getPages(), // 라우트 설정 ); } diff --git a/economic_fe/lib/view/screens/dictionary_page.dart b/economic_fe/lib/view/screens/dictionary_page.dart index f84c33f..0783a48 100644 --- a/economic_fe/lib/view/screens/dictionary_page.dart +++ b/economic_fe/lib/view/screens/dictionary_page.dart @@ -491,28 +491,31 @@ class _DictionaryPageState extends State { ], ), ), - // GestureDetector( - // onTap: () { - // setState(() { - // // 'selectedWord'가 null인 경우에는 false로 초기화하고, 값을 반전시킴 - // items[index]['selectedWord'] = - // !(items[index]['selectedWord'] ?? - // false); - // // print("Dd"); - // }); - // }, - // child: Padding( - // padding: const EdgeInsets.only( - // left: 11, top: 8, bottom: 8), - // child: Image.asset( - // items[index]['selectedWord'] ?? false - // ? "assets/bookmark_selected.png" - // : "assets/bookmark.png", - // width: 13, - // height: 18.2, - // ), - // ), - // ) + GestureDetector( + onTap: () { + setState(() { + // 'selectedWord'가 null인 경우에는 false로 초기화하고, 값을 반전시킴 + // items[index]['selectedWord'] = + // !(items[index]['selectedWord'] ?? + // false); + terms.isScraped = + !terms.isScraped! ?? false; + print("Dd"); + print(terms.isScraped); + }); + }, + child: Padding( + padding: const EdgeInsets.only( + left: 11, top: 8, bottom: 8), + child: Image.asset( + terms.isScraped ?? false + ? "assets/bookmark_selected.png" + : "assets/bookmark.png", + width: 13, + height: 18.2, + ), + ), + ) ], ), ), diff --git a/economic_fe/pubspec.lock b/economic_fe/pubspec.lock index a51ef91..3ef30e0 100644 --- a/economic_fe/pubspec.lock +++ b/economic_fe/pubspec.lock @@ -61,10 +61,10 @@ packages: dependency: transitive description: name: collection - sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dev" source: hosted - version: "1.19.0" + version: "1.18.0" convert: dependency: transitive description: @@ -380,18 +380,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" url: "https://pub.dev" source: hosted - version: "10.0.7" + version: "10.0.5" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" url: "https://pub.dev" source: hosted - version: "3.0.8" + version: "3.0.5" leak_tracker_testing: dependency: transitive description: @@ -580,7 +580,7 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.0" + version: "0.0.99" source_span: dependency: transitive description: @@ -593,10 +593,10 @@ packages: dependency: transitive description: name: stack_trace - sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" url: "https://pub.dev" source: hosted - version: "1.12.0" + version: "1.11.1" stream_channel: dependency: transitive description: @@ -609,10 +609,10 @@ packages: dependency: transitive description: name: string_scanner - sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.2.0" term_glyph: dependency: transitive description: @@ -625,10 +625,10 @@ packages: dependency: transitive description: name: test_api - sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" url: "https://pub.dev" source: hosted - version: "0.7.3" + version: "0.7.2" typed_data: dependency: transitive description: @@ -737,10 +737,10 @@ packages: dependency: transitive description: name: vm_service - sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" url: "https://pub.dev" source: hosted - version: "14.3.0" + version: "14.2.5" web: dependency: transitive description: From afc8a2a0259623542dafb5ae788026c5838899e0 Mon Sep 17 00:00:00 2001 From: dayoung20 Date: Fri, 31 Jan 2025 11:26:37 +0900 Subject: [PATCH 2/7] =?UTF-8?q?feat:=20=EC=9A=A9=EC=96=B4=20=EC=8A=A4?= =?UTF-8?q?=ED=81=AC=EB=9E=A9=20api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/data/services/remote_data_source.dart | 59 ++++++++++++++++++- .../lib/view/screens/dictionary_page.dart | 6 +- .../lib/view_model/dictionary_controller.dart | 13 ++++ .../profile_setting_controller.dart | 2 +- 4 files changed, 75 insertions(+), 5 deletions(-) diff --git a/economic_fe/lib/data/services/remote_data_source.dart b/economic_fe/lib/data/services/remote_data_source.dart index 15e0a40..da1a823 100644 --- a/economic_fe/lib/data/services/remote_data_source.dart +++ b/economic_fe/lib/data/services/remote_data_source.dart @@ -13,8 +13,8 @@ class RemoteDataSource { /// API POST /// /// 데이터 생성시 사용 - /// authToken을 포함하도록 수정 - static Future postApi( + /// jsonData 포함X + static Future postApiWithJson( String endPoint, Map jsonData, ) async { @@ -46,6 +46,42 @@ class RemoteDataSource { } } + /// API POST + /// + /// 데이터 생성시 사용 + /// jsonData 포함X + static Future _postApi( + String endPoint, + // Map jsonData, + ) async { + String apiUrl = '$baseUrl/$endPoint'; + // String authToken = dotenv.env['AUTHORIZATION_KEY']!; // 환경 변수에서 가져오기 + Map headers = { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $accessToken', + }; + + try { + final response = await http.post( + Uri.parse(apiUrl), + headers: headers, + // body: jsonEncode(jsonData), + ); + + if (response.statusCode == 200) { + debugPrint('POST 요청 성공'); + return response.statusCode; + } else { + debugPrint('POST 요청 실패: (${response.statusCode}) ${response.body}'); + } + + return response.statusCode; + } catch (e) { + debugPrint('POST 요청 중 예외 발생: $e'); + return null; + } + } + /// API PATCH /// /// 데이터 일부 수정시 사용 @@ -408,4 +444,23 @@ class RemoteDataSource { return null; } } + + /// api/v1/terms/{id}/scrap + /// 용어 스크랩 + static Future postTermsScrap(int id) async { + String endPoint = "api/v1/terms/$id/scrap"; + + try { + final response = await _postApi(endPoint); + + if (response != null) { + debugPrint("스크랩 post 성공"); + return true; + } else { + debugPrint("스크랩 실패"); + } + } catch (e) { + debugPrint("scrap Error : $e"); + } + } } diff --git a/economic_fe/lib/view/screens/dictionary_page.dart b/economic_fe/lib/view/screens/dictionary_page.dart index 0783a48..b77879f 100644 --- a/economic_fe/lib/view/screens/dictionary_page.dart +++ b/economic_fe/lib/view/screens/dictionary_page.dart @@ -498,8 +498,10 @@ class _DictionaryPageState extends State { // items[index]['selectedWord'] = // !(items[index]['selectedWord'] ?? // false); - terms.isScraped = - !terms.isScraped! ?? false; + // terms.isScraped = + // !terms.isScraped! ?? false; + controller.postTermScrap( + terms.termId!); print("Dd"); print(terms.isScraped); }); diff --git a/economic_fe/lib/view_model/dictionary_controller.dart b/economic_fe/lib/view_model/dictionary_controller.dart index ed8ac7c..521ba72 100644 --- a/economic_fe/lib/view_model/dictionary_controller.dart +++ b/economic_fe/lib/view_model/dictionary_controller.dart @@ -76,4 +76,17 @@ class DictionaryController extends GetxController { debugPrint('Error: $e'); } } + + // 특정 용어 스크랩 하기 + Future postTermScrap(int id) async { + try { + print("start"); + + dynamic response; + response = await RemoteDataSource.postTermsScrap(id); + print("scrap response : $response"); + } catch (e) { + debugPrint("Error: $e"); + } + } } diff --git a/economic_fe/lib/view_model/profile_setting/profile_setting_controller.dart b/economic_fe/lib/view_model/profile_setting/profile_setting_controller.dart index 21a47aa..a12e0bd 100644 --- a/economic_fe/lib/view_model/profile_setting/profile_setting_controller.dart +++ b/economic_fe/lib/view_model/profile_setting/profile_setting_controller.dart @@ -111,7 +111,7 @@ class ProfileSettingController extends GetxController { return; } - final response = await RemoteDataSource.postApi( + final response = await RemoteDataSource.postApiWithJson( 'api/v1/user/profile', userProfile.value.toJson(), // Token 전달 ); From 2a5764c15fcebc4950bf8be8ec043820b6301c39 Mon Sep 17 00:00:00 2001 From: dayoung20 Date: Fri, 31 Jan 2025 11:42:30 +0900 Subject: [PATCH 3/7] =?UTF-8?q?feat:=20=EC=9A=A9=EC=96=B4=20=EC=8A=A4?= =?UTF-8?q?=ED=81=AC=EB=9E=A9=20delete=20api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/data/services/remote_data_source.dart | 32 ++++++++++++++++++- .../lib/view/screens/dictionary_page.dart | 11 +++++-- .../lib/view_model/dictionary_controller.dart | 13 ++++++++ 3 files changed, 53 insertions(+), 3 deletions(-) diff --git a/economic_fe/lib/data/services/remote_data_source.dart b/economic_fe/lib/data/services/remote_data_source.dart index da1a823..334d6e7 100644 --- a/economic_fe/lib/data/services/remote_data_source.dart +++ b/economic_fe/lib/data/services/remote_data_source.dart @@ -173,7 +173,14 @@ class RemoteDataSource { debugPrint('DELETE 요청: $endPoint'); try { - final response = await http.delete(Uri.parse(apiUrl)); + final headers = { + 'Authorization': 'Bearer $accessToken', + 'accept': '*/*', + }; + final response = await http.delete( + Uri.parse(apiUrl), + headers: headers, + ); if (response.statusCode == 200) { debugPrint('DELETE 요청 성공'); @@ -458,9 +465,32 @@ class RemoteDataSource { return true; } else { debugPrint("스크랩 실패"); + return false; } } catch (e) { debugPrint("scrap Error : $e"); + return false; + } + } + + /// api/v1/terms/{id}/scrap + /// 용어 스크랩 취소 + static Future deleteScrap(int id) async { + String endPoint = "api/v1/terms/$id/scrap"; + + try { + final response = await _deleteApi(endPoint); + + if (response != null) { + debugPrint("스크랩 delete 성공"); + return true; + } else { + debugPrint("스크랩 delete 실패"); + return false; + } + } catch (e) { + debugPrint("scrap delete Error : $e"); + return false; } } } diff --git a/economic_fe/lib/view/screens/dictionary_page.dart b/economic_fe/lib/view/screens/dictionary_page.dart index b77879f..924d0a2 100644 --- a/economic_fe/lib/view/screens/dictionary_page.dart +++ b/economic_fe/lib/view/screens/dictionary_page.dart @@ -500,8 +500,15 @@ class _DictionaryPageState extends State { // false); // terms.isScraped = // !terms.isScraped! ?? false; - controller.postTermScrap( - terms.termId!); + // controller.postTermScrap( + // terms.termId!); + if (terms.isScraped!) { + controller.deleteTermScrap( + terms.termId!); + } else { + controller.postTermScrap( + terms.termId!); + } print("Dd"); print(terms.isScraped); }); diff --git a/economic_fe/lib/view_model/dictionary_controller.dart b/economic_fe/lib/view_model/dictionary_controller.dart index 521ba72..0352ea5 100644 --- a/economic_fe/lib/view_model/dictionary_controller.dart +++ b/economic_fe/lib/view_model/dictionary_controller.dart @@ -89,4 +89,17 @@ class DictionaryController extends GetxController { debugPrint("Error: $e"); } } + + // 특정 용어 스크랩 취소하기 + Future deleteTermScrap(int id) async { + try { + print("start"); + + dynamic response; + response = await RemoteDataSource.deleteScrap(id); + print("scrap delete response : $response"); + } catch (e) { + debugPrint("Error : $e"); + } + } } From b629dfce3d885420ae72f1acac10764f6feaae93 Mon Sep 17 00:00:00 2001 From: dayoung20 Date: Fri, 31 Jan 2025 12:12:52 +0900 Subject: [PATCH 4/7] =?UTF-8?q?feat:=20=EB=89=B4=EC=8A=A4=20=EC=8A=A4?= =?UTF-8?q?=ED=81=AC=EB=9E=A9=20UI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/data/models/article_model.dart | 3 + economic_fe/lib/main.dart | 2 +- .../screens/article/article_list_page.dart | 341 +++++++----------- .../article/article_list_controller.dart | 34 +- 4 files changed, 151 insertions(+), 229 deletions(-) diff --git a/economic_fe/lib/data/models/article_model.dart b/economic_fe/lib/data/models/article_model.dart index 45b8267..ce1ff3f 100644 --- a/economic_fe/lib/data/models/article_model.dart +++ b/economic_fe/lib/data/models/article_model.dart @@ -14,6 +14,7 @@ class ArticleModel with ChangeNotifier { String? url; String? category; String? createdDate; + bool? isScraped; ArticleModel({ this.id, @@ -24,6 +25,7 @@ class ArticleModel with ChangeNotifier { this.url, this.category, this.createdDate, + this.isScraped, }); factory ArticleModel.fromJson(Map json) { @@ -36,6 +38,7 @@ class ArticleModel with ChangeNotifier { url: json['url'], category: json['category'], createdDate: json['createdDate'], + isScraped: json['isScraped'], ); } } diff --git a/economic_fe/lib/main.dart b/economic_fe/lib/main.dart index 82b35d8..1cd9275 100644 --- a/economic_fe/lib/main.dart +++ b/economic_fe/lib/main.dart @@ -21,7 +21,7 @@ class RippleApp extends StatelessWidget { Widget build(BuildContext context) { return GetMaterialApp( title: 'Ripple', - initialRoute: '/dictionary', + initialRoute: '/article', getPages: UserRouter.getPages(), // 라우트 설정 ); } diff --git a/economic_fe/lib/view/screens/article/article_list_page.dart b/economic_fe/lib/view/screens/article/article_list_page.dart index 29bdc20..42ff751 100644 --- a/economic_fe/lib/view/screens/article/article_list_page.dart +++ b/economic_fe/lib/view/screens/article/article_list_page.dart @@ -19,7 +19,6 @@ class _ArticleListPageState extends State { final ArticleListController controller = Get.put(ArticleListController()); @override void initState() { - // TODO: implement initState super.initState(); controller.getNewsList(1, "RECENT", null); } @@ -199,222 +198,142 @@ class _ArticleListPageState extends State { ), ), // 기사 목록 - Obx(() { - return FutureBuilder>( - future: controller.getNewsList( - 1, - controller.selectedSort.value, - controller.selectedCate.value), - builder: (context, snapshot) { - if (snapshot.connectionState == - ConnectionState.waiting) { - return const Center( - child: CircularProgressIndicator(), - ); - } - // 에러인 경우 - if (snapshot.hasError) { - return Center( - child: Text("에러 발생 ${snapshot.error}"), - ); - } - // 데이터가 없을때 - if (!snapshot.hasData || snapshot.data!.isEmpty) { - return const Center(child: Text('뉴스 데이터가 없습니다.')); - } - final newsList = snapshot.data!; + Obx( + () { + return FutureBuilder>( + future: controller.getNewsList( + 1, + controller.selectedSort.value, + controller.selectedCate.value), + builder: (context, snapshot) { + if (snapshot.connectionState == + ConnectionState.waiting) { + return const Center( + child: CircularProgressIndicator(), + ); + } + // 에러인 경우 + if (snapshot.hasError) { + return Center( + child: Text("에러 발생 ${snapshot.error}"), + ); + } + // 데이터가 없을때 + if (!snapshot.hasData || snapshot.data!.isEmpty) { + return const Center( + child: Text('뉴스 데이터가 없습니다.')); + } + final newsList = snapshot.data!; - return Expanded( - child: ListView.builder( - itemCount: newsList.length, - itemBuilder: (context, index) { - final news = newsList[index]; - return Padding( - padding: const EdgeInsets.all(8.0), - child: Container( - padding: const EdgeInsets.all(16.0), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: - BorderRadius.circular(12.0), - border: const Border( - bottom: BorderSide( - color: Color(0xFFD9D9D9), - width: 1, + return Expanded( + child: ListView.builder( + itemCount: newsList.length, + itemBuilder: (context, index) { + final news = newsList[index]; + return Padding( + padding: const EdgeInsets.all(8.0), + child: Container( + padding: const EdgeInsets.all(16.0), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: + BorderRadius.circular(12.0), + border: const Border( + bottom: BorderSide( + color: Color(0xFFD9D9D9), + width: 1, + ), ), ), - ), - child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Text( - "${news.category}", - style: const TextStyle( - color: Color(0xFF2BD6D6), - fontSize: 12, - fontWeight: FontWeight.w600, - letterSpacing: -0.3, - height: 1.3, + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + "${news.category}", + style: const TextStyle( + color: Color(0xFF2BD6D6), + fontSize: 12, + fontWeight: FontWeight.w600, + letterSpacing: -0.3, + height: 1.3, + ), + ), + // GestureDetector( + // onTap: () { + // controller + // .toDetailPage(news); + // }, + // child: Text( + // news.title ?? "제목 없음", + // style: const TextStyle( + // fontSize: 16, + // fontWeight: + // FontWeight.w500, + // height: 1.3, + // letterSpacing: -0.4, + // ), + // ), + // ), + GestureDetector( + onTap: () { + controller + .toDetailPage(news); + }, + child: Text( + (news.title != null && + news.title!.length > + 30) + ? '${news.title!.substring(0, 20)}...' // 20자까지만 표시하고 "..." 추가 + : news.title ?? "제목 없음", + style: const TextStyle( + fontSize: 16, + fontWeight: + FontWeight.w500, + height: 1.3, + letterSpacing: -0.4, + ), + ), + ), + + const SizedBox(height: 6), + Text( + news.publisher ?? "알 수 없음", + style: const TextStyle( + color: Color(0xFF767676), + fontSize: 12, + fontWeight: FontWeight.w400, + height: 1.5, + letterSpacing: -0.3, + ), + ), + ], ), - ), - GestureDetector( - onTap: () { - controller.toDetailPage(news); - }, - child: Text( - news.title ?? "제목 없음", - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, - height: 1.3, - letterSpacing: -0.4, + GestureDetector( + onTap: () {}, + child: Image.asset( + news.isScraped ?? false + ? 'assets/bookmark_selected.png' + : 'assets/bookmark.png', + width: 13, + height: 18.3, ), - ), - ), - const SizedBox(height: 6), - Text( - news.publisher ?? "알 수 없음", - style: const TextStyle( - color: Color(0xFF767676), - fontSize: 12, - fontWeight: FontWeight.w400, - height: 1.5, - letterSpacing: -0.3, - ), - ), - ], + ) + ], + ), ), - ), - ); - }, - ), - ); - }, - ); - }) - // Expanded( - // child: ListView.separated( - // shrinkWrap: true, - // itemCount: controller.articles.length, // 예시 데이터 갯수 - // itemBuilder: (context, index) { - // final article = controller.articles[index]; - // // 인기순과 최신순을 구분해서 데이터를 다르게 처리 - // if (controller.selectedOrder.value == 0) { - // // 인기순 - // return Padding( - // padding: const EdgeInsets.all(16), - // child: Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // // 카테고리 이름 - // Text( - // article.category, - // style: const TextStyle( - // color: Color(0xFF2AD6D6), - // fontSize: 12, - // fontWeight: FontWeight.w600, - // height: 1.30, - // letterSpacing: -0.30, - // ), - // ), - // const SizedBox( - // height: 6, - // ), - - // Row( - // mainAxisAlignment: - // MainAxisAlignment.spaceBetween, - // crossAxisAlignment: - // CrossAxisAlignment.start, - // children: [ - // // 기사 헤드라인 - // GestureDetector( - // onTap: () { - // controller.toDetailPage(article); - // }, - // child: SizedBox( - // width: MediaQuery.of(context) - // .size - // .width - - // 80, - // child: Text( - // article.headline, - // style: const TextStyle( - // color: Color(0xFF111111), - // fontSize: 16, - // fontWeight: FontWeight.w500, - // height: 1.30, - // letterSpacing: -0.40, - // ), - // ), - // ), - // ), - // GestureDetector( - // onTap: () => controller - // .toggleBookmark(article.id), - // child: Obx(() { - // return Image.asset( - // article.isBookmarked.value - // ? 'assets/bookmark_selected.png' // 북마크 활성 상태 - // : 'assets/bookmark.png', // 북마크 비활성 상태 - // width: 13, - // height: 18.38, - // ); - // }), - // ), - // ], - // ), - // const SizedBox( - // height: 6, - // ), - // Row( - // mainAxisAlignment: - // MainAxisAlignment.spaceBetween, - // children: [ - // // 신문사 - // Text( - // article.publisher, - // style: const TextStyle( - // color: Color(0xFF767676), - // fontSize: 12, - // fontWeight: FontWeight.w400, - // height: 1.50, - // letterSpacing: -0.30, - // ), - // ), - // // 기사 업로드 시간 - // Text( - // article.uploadTime, - // style: const TextStyle( - // color: Color(0xFF767676), - // fontSize: 12, - // fontWeight: FontWeight.w400, - // height: 1.50, - // letterSpacing: -0.30, - // ), - // ), - // ], - // ), - // ], - // ), - // ); - // } else { - // // 최신순 - // return const SizedBox(); - // } - // }, - // separatorBuilder: (context, index) { - // return Padding( - // padding: const EdgeInsets.symmetric(vertical: 16), - // child: Container( - // height: 1, - // color: const Color(0xffd9d9d9), - // ), - // ); // 항목 사이에 구분선 추가 - // }, - // ), - // ), + ); + }, + ), + ); + }, + ); + }, + ), ], ), ); diff --git a/economic_fe/lib/view_model/article/article_list_controller.dart b/economic_fe/lib/view_model/article/article_list_controller.dart index 709a850..f602852 100644 --- a/economic_fe/lib/view_model/article/article_list_controller.dart +++ b/economic_fe/lib/view_model/article/article_list_controller.dart @@ -27,19 +27,19 @@ class ArticleListController extends GetxController { } // 기사 리스트 데이터 - List
articles = List.generate( - 10, - (index) => Article( - id: index, - category: '경기 분석', - headline: '[속보] 기사 제목 $index', - publisher: '경기일보', - uploadTime: '4시간 전', - isBookmarked: false.obs, - url: - 'https://www.hankookilbo.com/News/Read/A2022022411300004923', // 임시 기사 링크 - ), - ); + // List
articles = List.generate( + // 10, + // (index) => Article( + // id: index, + // category: '경기 분석', + // headline: '[속보] 기사 제목 $index', + // publisher: '경기일보', + // uploadTime: '4시간 전', + // isBookmarked: false.obs, + // url: + // 'https://www.hankookilbo.com/News/Read/A2022022411300004923', // 임시 기사 링크 + // ), + // ); // 기사 세부페이지로 이동 void toDetailPage(ArticleModel article) { @@ -47,10 +47,10 @@ class ArticleListController extends GetxController { } // 북마크 상태 토글 메서드 - void toggleBookmark(int articleId) { - final article = articles.firstWhere((article) => article.id == articleId); - article.isBookmarked.value = !article.isBookmarked.value; - } + // void toggleBookmark(int articleId) { + // final article = articles.firstWhere((article) => article.id == articleId); + // article.isBookmarked.value = !article.isBookmarked.value; + // } // 챗봇 화면으로 이동 void toChatbot() { From ed55f800523f631d6a306887844f8530616ea141 Mon Sep 17 00:00:00 2001 From: dayoung20 Date: Fri, 31 Jan 2025 12:32:42 +0900 Subject: [PATCH 5/7] =?UTF-8?q?feat:=20=EB=89=B4=EC=8A=A4=20=EC=8A=A4?= =?UTF-8?q?=ED=81=AC=EB=9E=A9=20api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/data/services/remote_data_source.dart | 42 +++++++++++++++++++ .../screens/article/article_list_page.dart | 5 ++- .../article/article_list_controller.dart | 26 ++++++++++++ 3 files changed, 72 insertions(+), 1 deletion(-) diff --git a/economic_fe/lib/data/services/remote_data_source.dart b/economic_fe/lib/data/services/remote_data_source.dart index 334d6e7..81305a9 100644 --- a/economic_fe/lib/data/services/remote_data_source.dart +++ b/economic_fe/lib/data/services/remote_data_source.dart @@ -236,6 +236,48 @@ class RemoteDataSource { return response; } + /// api/news/{id}/scrap + /// 뉴스 스크랩 + static Future postNewsScrap(int id) async { + String endPoint = "api/news/$id/scrap"; + + try { + final response = await _postApi(endPoint); + + if (response != null) { + debugPrint("스크랩 post 성공"); + return true; + } else { + debugPrint("스크랩 실패"); + return false; + } + } catch (e) { + debugPrint("scrap Error : $e"); + return false; + } + } + + /// 뉴스 스크랩 취소 + /// api/news/{id}/scrap + static Future deleteNewsScrap(int id) async { + String endPoint = "api/news/$id/scrap"; + + try { + final response = await _deleteApi(endPoint); + + if (response != null) { + debugPrint("스크랩 delete 성공"); + return true; + } else { + debugPrint("스크랩 delete 실패"); + return false; + } + } catch (e) { + debugPrint("scrap delete Error : $e"); + return false; + } + } + /// 자음 별 용어 조회 /// api/v1/terms/search/consonant static Future getDictionary(int page, String consonant) async { diff --git a/economic_fe/lib/view/screens/article/article_list_page.dart b/economic_fe/lib/view/screens/article/article_list_page.dart index 42ff751..6def9fb 100644 --- a/economic_fe/lib/view/screens/article/article_list_page.dart +++ b/economic_fe/lib/view/screens/article/article_list_page.dart @@ -314,7 +314,10 @@ class _ArticleListPageState extends State { ], ), GestureDetector( - onTap: () {}, + onTap: () { + controller + .postNewsScrap(news.id!); + }, child: Image.asset( news.isScraped ?? false ? 'assets/bookmark_selected.png' diff --git a/economic_fe/lib/view_model/article/article_list_controller.dart b/economic_fe/lib/view_model/article/article_list_controller.dart index f602852..1f33c7e 100644 --- a/economic_fe/lib/view_model/article/article_list_controller.dart +++ b/economic_fe/lib/view_model/article/article_list_controller.dart @@ -80,4 +80,30 @@ class ArticleListController extends GetxController { return []; } } + + // 뉴스 스크랩 + Future postNewsScrap(int id) async { + try { + print("start"); + dynamic response; + + response = await RemoteDataSource.postNewsScrap(id); + print("뉴스 스크랩 : $response"); + } catch (e) { + debugPrint("Error: $e"); + } + } + + // 특정 용어 스크랩 취소하기 + Future deleteNewsScrap(int id) async { + try { + print("start"); + + dynamic response; + response = await RemoteDataSource.deleteNewsScrap(id); + print("scrap delete response : $response"); + } catch (e) { + debugPrint("Error : $e"); + } + } } From fe38f2d54dd8a71cf6ad2d3e984d990f5ae4e6c2 Mon Sep 17 00:00:00 2001 From: dayoung20 Date: Fri, 31 Jan 2025 12:40:21 +0900 Subject: [PATCH 6/7] =?UTF-8?q?feat:=20=EB=89=B4=EC=8A=A4=20=EC=8A=A4?= =?UTF-8?q?=ED=81=AC=EB=9E=A9=20delete=20api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/view/screens/article/article_list_page.dart | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/economic_fe/lib/view/screens/article/article_list_page.dart b/economic_fe/lib/view/screens/article/article_list_page.dart index 6def9fb..b3490df 100644 --- a/economic_fe/lib/view/screens/article/article_list_page.dart +++ b/economic_fe/lib/view/screens/article/article_list_page.dart @@ -315,8 +315,13 @@ class _ArticleListPageState extends State { ), GestureDetector( onTap: () { - controller - .postNewsScrap(news.id!); + if (news.isScraped!) { + controller.deleteNewsScrap( + news.id!); + } else { + controller + .postNewsScrap(news.id!); + } }, child: Image.asset( news.isScraped ?? false From 93f26cc646983bb2a0f303b33533ed0e7f7b01a1 Mon Sep 17 00:00:00 2001 From: dayoung20 Date: Fri, 31 Jan 2025 12:40:46 +0900 Subject: [PATCH 7/7] =?UTF-8?q?UI:=20=EB=89=B4=EC=8A=A4=20UI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../screens/article/article_list_page.dart | 52 +++++++++++++------ 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/economic_fe/lib/view/screens/article/article_list_page.dart b/economic_fe/lib/view/screens/article/article_list_page.dart index b3490df..1e6cdf7 100644 --- a/economic_fe/lib/view/screens/article/article_list_page.dart +++ b/economic_fe/lib/view/screens/article/article_list_page.dart @@ -313,23 +313,41 @@ class _ArticleListPageState extends State { ), ], ), - GestureDetector( - onTap: () { - if (news.isScraped!) { - controller.deleteNewsScrap( - news.id!); - } else { - controller - .postNewsScrap(news.id!); - } - }, - child: Image.asset( - news.isScraped ?? false - ? 'assets/bookmark_selected.png' - : 'assets/bookmark.png', - width: 13, - height: 18.3, - ), + Column( + children: [ + GestureDetector( + onTap: () { + if (news.isScraped!) { + controller + .deleteNewsScrap( + news.id!); + } else { + controller.postNewsScrap( + news.id!); + } + }, + child: Image.asset( + news.isScraped ?? false + ? 'assets/bookmark_selected.png' + : 'assets/bookmark.png', + width: 13, + height: 18.3, + ), + ), + const SizedBox( + height: 20, + ), + Text( + news.createdDate!, + style: const TextStyle( + color: Color(0xFF767676), + fontSize: 12, + fontWeight: FontWeight.w400, + height: 1.5, + letterSpacing: -0.3, + ), + ), + ], ) ], ),