From e168c180869717bb08dd406784aeee5e9d008947 Mon Sep 17 00:00:00 2001 From: realhsb Date: Thu, 20 Jun 2024 07:31:47 +0900 Subject: [PATCH 01/19] =?UTF-8?q?feat:=20=ED=86=B5=EA=B3=84=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RollTheDice.xcodeproj/project.pbxproj | 4 ++++ .../Domain/ScoopAPI/ScoopAPIStatistics.swift | 15 +++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 iOS/RollTheDice/RollTheDice/Source/Domain/ScoopAPI/ScoopAPIStatistics.swift diff --git a/iOS/RollTheDice/RollTheDice.xcodeproj/project.pbxproj b/iOS/RollTheDice/RollTheDice.xcodeproj/project.pbxproj index 9d4f2cfb..16413fc7 100644 --- a/iOS/RollTheDice/RollTheDice.xcodeproj/project.pbxproj +++ b/iOS/RollTheDice/RollTheDice.xcodeproj/project.pbxproj @@ -69,6 +69,7 @@ 6CC4DDCE2B5574690080E7E8 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6CC4DDCD2B5574690080E7E8 /* Preview Assets.xcassets */; }; 6CC6737A2C217C4B009FB30E /* ScoopAPILogin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CC673792C217C4B009FB30E /* ScoopAPILogin.swift */; }; 6CC6737C2C21BA5B009FB30E /* Auth.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CC6737B2C21BA5B009FB30E /* Auth.swift */; }; + 6CC673802C233A65009FB30E /* ScoopAPIStatistics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CC6737F2C233A65009FB30E /* ScoopAPIStatistics.swift */; }; 6CDB29C92BA97C550081037B /* Pretendard-Black.otf in Resources */ = {isa = PBXBuildFile; fileRef = 6CDB29C02BA97C550081037B /* Pretendard-Black.otf */; }; 6CDB29CA2BA97C550081037B /* Pretendard-ExtraBold.otf in Resources */ = {isa = PBXBuildFile; fileRef = 6CDB29C12BA97C550081037B /* Pretendard-ExtraBold.otf */; }; 6CDB29CB2BA97C550081037B /* Pretendard-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = 6CDB29C22BA97C550081037B /* Pretendard-Regular.otf */; }; @@ -162,6 +163,7 @@ 6CC4DDCD2B5574690080E7E8 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 6CC673792C217C4B009FB30E /* ScoopAPILogin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScoopAPILogin.swift; sourceTree = ""; }; 6CC6737B2C21BA5B009FB30E /* Auth.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Auth.swift; sourceTree = ""; }; + 6CC6737F2C233A65009FB30E /* ScoopAPIStatistics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScoopAPIStatistics.swift; sourceTree = ""; }; 6CDB29BF2BA9735C0081037B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 6CDB29C02BA97C550081037B /* Pretendard-Black.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Pretendard-Black.otf"; sourceTree = ""; }; 6CDB29C12BA97C550081037B /* Pretendard-ExtraBold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Pretendard-ExtraBold.otf"; sourceTree = ""; }; @@ -664,6 +666,7 @@ 6CF130C62BAB7B9800A437B6 /* ScoopAPINews.swift */, 6C5B0C892C1C308A00A0D5F4 /* ScoopAPIBookmarks.swift */, 6CC673792C217C4B009FB30E /* ScoopAPILogin.swift */, + 6CC6737F2C233A65009FB30E /* ScoopAPIStatistics.swift */, ); path = ScoopAPI; sourceTree = ""; @@ -820,6 +823,7 @@ 6CDB29FB2BAA07B10081037B /* GPTChatViewModel.swift in Sources */, 6C32379F2B7C376D00B699AB /* Bookmarks.swift in Sources */, 6C454A7E2B9DAA3F006FD9D0 /* SignUpFinishView.swift in Sources */, + 6CC673802C233A65009FB30E /* ScoopAPIStatistics.swift in Sources */, 6C7704A12B722CEB001B17CB /* ProfileView.swift in Sources */, 6C4F7BAB2BDE50C600ED01DA /* DailyReportModel.swift in Sources */, 6C3237B72B7C434600B699AB /* ChatType.swift in Sources */, diff --git a/iOS/RollTheDice/RollTheDice/Source/Domain/ScoopAPI/ScoopAPIStatistics.swift b/iOS/RollTheDice/RollTheDice/Source/Domain/ScoopAPI/ScoopAPIStatistics.swift new file mode 100644 index 00000000..22424bdf --- /dev/null +++ b/iOS/RollTheDice/RollTheDice/Source/Domain/ScoopAPI/ScoopAPIStatistics.swift @@ -0,0 +1,15 @@ +// +// ScoopAPIStatistics.swift +// RollTheDice +// +// Created by Subeen on 6/20/24. +// + +import Foundation + +public enum ScoopAPIStatistics { +// public static let statistics = String("/statistics") + public static let statisticsPerDates = String("/statistics/per-dates") + public static let statisticsCategories = String("/statistics/categories") + +} From 2b41196a04740fc531d68257d60bce15bc483587 Mon Sep 17 00:00:00 2001 From: realhsb Date: Thu, 20 Jun 2024 07:32:37 +0900 Subject: [PATCH 02/19] =?UTF-8?q?chore:=20Daily=20Report=20(=EC=9D=BC?= =?UTF-8?q?=EB=B3=84=20=EC=A1=B0=ED=9A=8C=EC=88=98=20=EC=A1=B0=ED=9A=8C)?= =?UTF-8?q?=20Model=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../View/Report/Daily/DailyReportModel.swift | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/iOS/RollTheDice/RollTheDice/Source/View/Report/Daily/DailyReportModel.swift b/iOS/RollTheDice/RollTheDice/Source/View/Report/Daily/DailyReportModel.swift index 9a5051cc..10a34175 100644 --- a/iOS/RollTheDice/RollTheDice/Source/View/Report/Daily/DailyReportModel.swift +++ b/iOS/RollTheDice/RollTheDice/Source/View/Report/Daily/DailyReportModel.swift @@ -8,24 +8,25 @@ import Foundation import SwiftUI -struct DailyReportList: Hashable { - var reportList: [DailyReport] -} +//struct DailyReportList: Codable { +// var reportList: [DailyReport] +//} -struct DailyReport: Hashable, Identifiable { - let id = UUID() - let dateStr: String // DateFormatter로 변환 - let views: Int +struct DailyReport: Codable, Identifiable { + + let id = UUID().uuidString + let views: Int? + let dateTime: String? var date: Date { // TODO: Format Style 사용해서 String -> Date 생성하기 // let strategy = Date.ParseStrategy(format: "\(month: .twoDigits)년 \(month: .twoDigits)월 \(day: .defaultDigits)", timeZone: TimeZone(abbreviation: "CDT")!) let dateFormatter = DateFormatter() - dateFormatter.dateFormat = "yyyy년 MM월 dd일" + dateFormatter.dateFormat = "yyyy-MM-dd" - let convertedDate = dateFormatter.date(from: dateStr)! + let convertedDate = dateFormatter.date(from: dateTime ?? "0000-00-00") - return convertedDate + return convertedDate! } } From c2a16b12704b629f1e6e34c8aea5615941177476 Mon Sep 17 00:00:00 2001 From: realhsb Date: Thu, 20 Jun 2024 07:32:57 +0900 Subject: [PATCH 03/19] =?UTF-8?q?chore:=20Daily=20Report=20(=EC=9D=BC?= =?UTF-8?q?=EB=B3=84=20=EC=A1=B0=ED=9A=8C=EC=88=98=20=EC=A1=B0=ED=9A=8C)?= =?UTF-8?q?=20View=20&=20ViewModel=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../View/Report/Daily/DailyBarChartView.swift | 13 ++-- .../Report/Daily/DailyReportViewModel.swift | 62 ++++++++++++++----- 2 files changed, 53 insertions(+), 22 deletions(-) diff --git a/iOS/RollTheDice/RollTheDice/Source/View/Report/Daily/DailyBarChartView.swift b/iOS/RollTheDice/RollTheDice/Source/View/Report/Daily/DailyBarChartView.swift index 8f026af7..2b02f12c 100644 --- a/iOS/RollTheDice/RollTheDice/Source/View/Report/Daily/DailyBarChartView.swift +++ b/iOS/RollTheDice/RollTheDice/Source/View/Report/Daily/DailyBarChartView.swift @@ -11,7 +11,7 @@ import Charts struct DailyBarChartView: View { - @StateObject var dailyViewModel: DailyReportViewModel + var dailyViewModel: DailyReportViewModel @State var selectedDay: Date? @State var selectedView: Int? @@ -21,9 +21,9 @@ struct DailyBarChartView: View { var selectedValue: (date: Date, views: Int)? { if let selectedDay { - for preview in dailyViewModel.dailyReportList.reportList { + for preview in dailyViewModel.dailyReportList ?? [] { if preview.date.formatted(date: .long, time: .omitted) == selectedDay.formatted(date: .long, time: .omitted) { - return (selectedDay, preview.views) + return (selectedDay, preview.views!) } } } @@ -57,10 +57,10 @@ struct DailyBarChartView: View { Chart{ - ForEach(dailyViewModel.dailyReportList.reportList) { day in + ForEach(dailyViewModel.dailyReportList ?? []) { day in BarMark( x: .value("Day", day.date, unit: .weekdayOrdinal), - y: .value("Views", day.views) + y: .value("Views", day.views ?? 0) ) .cornerRadius(8) @@ -100,6 +100,9 @@ struct DailyBarChartView: View { } .chartYAxis(.hidden) .chartXSelection(value: $selectedDay) + .task { + dailyViewModel.getDailyViews() + } } } diff --git a/iOS/RollTheDice/RollTheDice/Source/View/Report/Daily/DailyReportViewModel.swift b/iOS/RollTheDice/RollTheDice/Source/View/Report/Daily/DailyReportViewModel.swift index 344ca3bb..b9aa5374 100644 --- a/iOS/RollTheDice/RollTheDice/Source/View/Report/Daily/DailyReportViewModel.swift +++ b/iOS/RollTheDice/RollTheDice/Source/View/Report/Daily/DailyReportViewModel.swift @@ -6,34 +6,62 @@ // import Foundation +import Combine +import CombineMoya +import Moya +import SwiftUI -class DailyReportViewModel: ObservableObject{ - @Published var dailyReportList: DailyReportList +@Observable class DailyReportViewModel { + var dailyReportList: [DailyReport]? /// 일주일 평균 조회수 var averageView: String { var aver = 0.0 - for daily in dailyReportList.reportList { - aver += Double(daily.views) + for daily in dailyReportList ?? [] { + aver += Double(daily.views ?? 0) } return String(format: "%.1f", aver / 7) } - init( - dailyReportList: DailyReportList = .init( - reportList: - [.init(dateStr: "2024년 1월 1일", views: 32), - .init(dateStr: "2024년 1월 2일", views: 2), - .init(dateStr: "2024년 1월 3일", views: 300), - .init(dateStr: "2024년 1월 4일", views: 999), - .init(dateStr: "2024년 1월 5일", views: 12), - .init(dateStr: "2024년 1월 6일", views: 1), - .init(dateStr: "2024년 1월 7일", views: 99), - ] + var dailyCancellable: AnyCancellable? + + let provider = MoyaProvider(plugins: [MoyaLoggingPlugin()]) + + func dailyToViewModel(_ list: [DailyReport]) { + self.dailyReportList = list + } +} + +extension DailyReportViewModel { + + public func getDailyViews() { + guard let accessToken = TokenManager.shared.accessToken else { + print("Access token 사용 불가능...") + return + } + + if let cancellable = dailyCancellable { + cancellable.cancel() + } + + dailyCancellable = provider.requestWithProgressPublisher( + .recentSevenPerDate(accessToken: accessToken) ) - ) { - self.dailyReportList = dailyReportList + .compactMap { $0.response?.data } + .receive(on: DispatchQueue.main) + .decode(type: [DailyReport].self, decoder: JSONDecoder()) + .sink(receiveCompletion: { result in + switch result { + case .finished: + print("daily report 조회성공") + case .failure(let error): + Log.network("daily report network error", error.localizedDescription) + } + }, receiveValue: { [weak self] response in + self?.dailyToViewModel(response) + print(response) + }) } } From e2b1c8b4e0763bfa3470b93adddfa1b43021eb09 Mon Sep 17 00:00:00 2001 From: realhsb Date: Thu, 20 Jun 2024 07:33:26 +0900 Subject: [PATCH 04/19] feat: Statistics Service --- .../RollTheDice.xcodeproj/project.pbxproj | 4 ++ .../Domain/Service/StatisticsService.swift | 63 +++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 iOS/RollTheDice/RollTheDice/Source/Domain/Service/StatisticsService.swift diff --git a/iOS/RollTheDice/RollTheDice.xcodeproj/project.pbxproj b/iOS/RollTheDice/RollTheDice.xcodeproj/project.pbxproj index 16413fc7..04a94122 100644 --- a/iOS/RollTheDice/RollTheDice.xcodeproj/project.pbxproj +++ b/iOS/RollTheDice/RollTheDice.xcodeproj/project.pbxproj @@ -69,6 +69,7 @@ 6CC4DDCE2B5574690080E7E8 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6CC4DDCD2B5574690080E7E8 /* Preview Assets.xcassets */; }; 6CC6737A2C217C4B009FB30E /* ScoopAPILogin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CC673792C217C4B009FB30E /* ScoopAPILogin.swift */; }; 6CC6737C2C21BA5B009FB30E /* Auth.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CC6737B2C21BA5B009FB30E /* Auth.swift */; }; + 6CC6737E2C233443009FB30E /* StatisticsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CC6737D2C233443009FB30E /* StatisticsService.swift */; }; 6CC673802C233A65009FB30E /* ScoopAPIStatistics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CC6737F2C233A65009FB30E /* ScoopAPIStatistics.swift */; }; 6CDB29C92BA97C550081037B /* Pretendard-Black.otf in Resources */ = {isa = PBXBuildFile; fileRef = 6CDB29C02BA97C550081037B /* Pretendard-Black.otf */; }; 6CDB29CA2BA97C550081037B /* Pretendard-ExtraBold.otf in Resources */ = {isa = PBXBuildFile; fileRef = 6CDB29C12BA97C550081037B /* Pretendard-ExtraBold.otf */; }; @@ -163,6 +164,7 @@ 6CC4DDCD2B5574690080E7E8 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 6CC673792C217C4B009FB30E /* ScoopAPILogin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScoopAPILogin.swift; sourceTree = ""; }; 6CC6737B2C21BA5B009FB30E /* Auth.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Auth.swift; sourceTree = ""; }; + 6CC6737D2C233443009FB30E /* StatisticsService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatisticsService.swift; sourceTree = ""; }; 6CC6737F2C233A65009FB30E /* ScoopAPIStatistics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScoopAPIStatistics.swift; sourceTree = ""; }; 6CDB29BF2BA9735C0081037B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 6CDB29C02BA97C550081037B /* Pretendard-Black.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Pretendard-Black.otf"; sourceTree = ""; }; @@ -637,6 +639,7 @@ 6CF130B12BAB74BA00A437B6 /* NewsService.swift */, 6C5B0C8B2C1C32C000A0D5F4 /* BookmarksService.swift */, 357699432C09C7B900AD2DA4 /* LoginService.swift */, + 6CC6737D2C233443009FB30E /* StatisticsService.swift */, ); path = Service; sourceTree = ""; @@ -836,6 +839,7 @@ 6C41B8DA2BE104A800274FA4 /* RecentNewsCardView.swift in Sources */, 3509091A2C1C1248007D76A1 /* TokenManager.swift in Sources */, 6CF130C72BAB7B9800A437B6 /* ScoopAPINews.swift in Sources */, + 6CC6737E2C233443009FB30E /* StatisticsService.swift in Sources */, 6C7651402BF37F3400196536 /* Log.swift in Sources */, 6CE1031A2BD57A2500498AA4 /* DebateSummaryView.swift in Sources */, 6CE1030C2BD56A4000498AA4 /* TypeReportView.swift in Sources */, diff --git a/iOS/RollTheDice/RollTheDice/Source/Domain/Service/StatisticsService.swift b/iOS/RollTheDice/RollTheDice/Source/Domain/Service/StatisticsService.swift new file mode 100644 index 00000000..9e1ece6d --- /dev/null +++ b/iOS/RollTheDice/RollTheDice/Source/Domain/Service/StatisticsService.swift @@ -0,0 +1,63 @@ +// +// StatisticsService.swift +// RollTheDice +// +// Created by Subeen on 6/20/24. +// + +import Foundation +import Moya + +enum StatisticsService { + case recentSevenPerDate(accessToken: String) /// 최근 일주일 날짜별 뉴스 조회수 조회 + case statisticsCategory(accessToken: String) +} + +extension StatisticsService: BaseTargetType { + var baseURL: URL { + return URL(string: ScoopAPI.baseURL)! + } + + var path: String { + switch self { + case .recentSevenPerDate(let accessToken): + return ScoopAPIStatistics.statisticsPerDates + + case .statisticsCategory(let accessToken): + return ScoopAPIStatistics.statisticsCategories + } + } + + var method: Moya.Method { + switch self { + case .recentSevenPerDate, + .statisticsCategory: + return .get + + } + } + + var task: Moya.Task { + switch self { + case .recentSevenPerDate(_), + .statisticsCategory(_): + + let parameters : [String : Any] = [ : ] + return .requestPlain + } + } + + var headers: [String : String]? { + let accessToken: String + + switch self { + case .recentSevenPerDate(let accessTokenValue), + .statisticsCategory(let accessTokenValue): + accessToken = accessTokenValue + return [ + "Authorization": "Bearer \(accessToken)", + "X-Content-Type_Options" : "nosniff" + ] + } + } +} From ee8349b0bf4b4cf7702c2595a6e5c170a7fb33ad Mon Sep 17 00:00:00 2001 From: realhsb Date: Thu, 20 Jun 2024 08:30:58 +0900 Subject: [PATCH 05/19] =?UTF-8?q?feat:=20Type=20Report=20Model=20(?= =?UTF-8?q?=EC=B9=B4=ED=85=8C=EA=B3=A0=EB=A6=AC=EB=B3=84=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=EC=88=98)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../View/Report/Type/TypeReportModel.swift | 20 +++++-------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/iOS/RollTheDice/RollTheDice/Source/View/Report/Type/TypeReportModel.swift b/iOS/RollTheDice/RollTheDice/Source/View/Report/Type/TypeReportModel.swift index 1c35be6e..2c8c56a1 100644 --- a/iOS/RollTheDice/RollTheDice/Source/View/Report/Type/TypeReportModel.swift +++ b/iOS/RollTheDice/RollTheDice/Source/View/Report/Type/TypeReportModel.swift @@ -7,19 +7,9 @@ import Foundation -struct TypeReportList: Hashable { - var reportList: [TypeReport] -} - -struct TypeReport: Hashable, Identifiable { - var id = UUID() - var newsType: NewsType - var view: Int - - // case politics // 정치 - // case economy // 경제 - // case society // 사회 - // case living // 생활/문화 - // case world // 세계 - // case science // IT/과학 +struct TypeReport: Codable, Identifiable { + + let id = UUID().uuidString + let category: NewsType? + let views: Int? } From ae15c2f2597279cee4c308f1c5c99c672b10fd9d Mon Sep 17 00:00:00 2001 From: realhsb Date: Thu, 20 Jun 2024 08:31:10 +0900 Subject: [PATCH 06/19] =?UTF-8?q?feat:=20Type=20Report=20View=20&=20ViewMo?= =?UTF-8?q?del=20(=EC=B9=B4=ED=85=8C=EA=B3=A0=EB=A6=AC=EB=B3=84=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=EC=88=98)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../View/Report/Type/TypePieChartView.swift | 11 +-- .../Report/Type/TypeReportViewModel.swift | 69 ++++++++++++++----- 2 files changed, 58 insertions(+), 22 deletions(-) diff --git a/iOS/RollTheDice/RollTheDice/Source/View/Report/Type/TypePieChartView.swift b/iOS/RollTheDice/RollTheDice/Source/View/Report/Type/TypePieChartView.swift index bbd26054..f27b7243 100644 --- a/iOS/RollTheDice/RollTheDice/Source/View/Report/Type/TypePieChartView.swift +++ b/iOS/RollTheDice/RollTheDice/Source/View/Report/Type/TypePieChartView.swift @@ -10,23 +10,23 @@ import Charts struct TypePieChartView: View { - @StateObject var reportViewModel: TypeReportViewModel + var reportViewModel: TypeReportViewModel var isPreview: Bool = false var mostViewed: NewsType { - return reportViewModel.sortedList.first!.newsType + return reportViewModel.sortedList.first?.category ?? .economy } var body: some View { Chart(reportViewModel.sortedList) { report in SectorMark( - angle: .value("Views", report.view), + angle: .value("Views", report.views ?? 0), innerRadius: .ratio(0.7), angularInset: 2.0 ) .cornerRadius(8) - .foregroundStyle(report.newsType.color.gradient) + .foregroundStyle(report.category?.color.gradient ?? Color.primary01.gradient) } /// pie chart의 가운데 문구 .chartBackground { chartProxy in @@ -47,6 +47,9 @@ struct TypePieChartView: View { } } .padding(100) + .task { + reportViewModel.getTypeReport() + } } } diff --git a/iOS/RollTheDice/RollTheDice/Source/View/Report/Type/TypeReportViewModel.swift b/iOS/RollTheDice/RollTheDice/Source/View/Report/Type/TypeReportViewModel.swift index d23bce97..fcc6bfde 100644 --- a/iOS/RollTheDice/RollTheDice/Source/View/Report/Type/TypeReportViewModel.swift +++ b/iOS/RollTheDice/RollTheDice/Source/View/Report/Type/TypeReportViewModel.swift @@ -6,28 +6,61 @@ // import Foundation +import Combine +import CombineMoya +import Moya +import SwiftUI -class TypeReportViewModel: ObservableObject { +@Observable class TypeReportViewModel { - @Published var reportList: TypeReportList + var typeReportList: [TypeReport]? + + // 비율이 낮은 순으로 정렬 (파이 차트에서 반시계방향으로 그래프 차지) + var sortedList: [TypeReport] { + if let reportList = typeReportList { + return reportList.sorted { ($0.views ?? 0) < ($1.views ?? 0) } + } else { + return [] + } + } - init( - reportList: TypeReportList = .init( - reportList: [ - .init(newsType: .economy, view: 10), - .init(newsType: .living, view: 20), - .init(newsType: .politics, view: 30), - .init(newsType: .science, view: 5), - .init(newsType: .society, view: 5), - .init(newsType: .world, view: 30) - ] - ) - ) { - self.reportList = reportList + var typeCancellable: AnyCancellable? + + let provider = MoyaProvider(plugins: [MoyaLoggingPlugin()]) + + func typeToViewModel(_ list: [TypeReport]) { + self.typeReportList = list } +} + +extension TypeReportViewModel { - // 비율이 낮은 순으로 정렬 (파이 차트에서 반시계방향으로 그래프 차지) - var sortedList: [TypeReport] { - return reportList.reportList.sorted { $0.view > $1.view } + public func getTypeReport() { + guard let accessToken = TokenManager.shared.accessToken else { + print("Access token 사용 불가능...") + return + } + + if let cancellable = typeCancellable { + cancellable.cancel() + } + + typeCancellable = provider.requestWithProgressPublisher( + .statisticsCategory(accessToken: accessToken) + ) + .compactMap { $0.response?.data } + .receive(on: DispatchQueue.main) + .decode(type: [TypeReport].self, decoder: JSONDecoder()) + .sink(receiveCompletion: { result in + switch result { + case .finished: + print("type report 조회성공") + case .failure(let error): + Log.network("type report network error", error.localizedDescription) + } + }, receiveValue: { [weak self] response in + self?.typeToViewModel(response) + print(response) + }) } } From 7abdbc66ab56c72fd4cc3615f095b60239775773 Mon Sep 17 00:00:00 2001 From: realhsb Date: Thu, 20 Jun 2024 08:31:21 +0900 Subject: [PATCH 07/19] =?UTF-8?q?chore:=20NewsType=20enum=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RollTheDice/Source/Model/Report/NewsType.swift | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/iOS/RollTheDice/RollTheDice/Source/Model/Report/NewsType.swift b/iOS/RollTheDice/RollTheDice/Source/Model/Report/NewsType.swift index 99deabbe..ac4c22df 100644 --- a/iOS/RollTheDice/RollTheDice/Source/Model/Report/NewsType.swift +++ b/iOS/RollTheDice/RollTheDice/Source/Model/Report/NewsType.swift @@ -8,13 +8,13 @@ import Foundation import SwiftUI -enum NewsType { - case politics // 정치 - case economy // 경제 - case society // 사회 - case living // 생활/문화 - case world // 세계 - case science // IT/과학 +enum NewsType: String, Codable { + case politics = "정치" // 정치 + case economy = "경제" // 경제 + case society = "사회" // 사회 + case living = "생활/문화" // 생활/문화 + case world = "세계" // 세계 + case science = "IT/과학" // IT/과학 var desciption: String { switch self { From 73b1ee02477831c1cb6831db72d10ea4184d4bcf Mon Sep 17 00:00:00 2001 From: realhsb Date: Thu, 20 Jun 2024 08:31:37 +0900 Subject: [PATCH 08/19] =?UTF-8?q?chore:=20Statistics=20Service=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RollTheDice/Source/Domain/Service/StatisticsService.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iOS/RollTheDice/RollTheDice/Source/Domain/Service/StatisticsService.swift b/iOS/RollTheDice/RollTheDice/Source/Domain/Service/StatisticsService.swift index 9e1ece6d..9ff4993b 100644 --- a/iOS/RollTheDice/RollTheDice/Source/Domain/Service/StatisticsService.swift +++ b/iOS/RollTheDice/RollTheDice/Source/Domain/Service/StatisticsService.swift @@ -10,7 +10,7 @@ import Moya enum StatisticsService { case recentSevenPerDate(accessToken: String) /// 최근 일주일 날짜별 뉴스 조회수 조회 - case statisticsCategory(accessToken: String) + case statisticsCategory(accessToken: String) /// 카테고리별 조회수 조회 } extension StatisticsService: BaseTargetType { From 93509c52c0fc924be64e5605cefdb90b74443cd4 Mon Sep 17 00:00:00 2001 From: realhsb Date: Thu, 20 Jun 2024 08:35:38 +0900 Subject: [PATCH 09/19] =?UTF-8?q?chore:=20Bookmark=20api=20Token=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../View/Bookmark/BookmarkCard/BookmarksListViewModel.swift | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/iOS/RollTheDice/RollTheDice/Source/View/Bookmark/BookmarkCard/BookmarksListViewModel.swift b/iOS/RollTheDice/RollTheDice/Source/View/Bookmark/BookmarkCard/BookmarksListViewModel.swift index fc069789..f9342a31 100644 --- a/iOS/RollTheDice/RollTheDice/Source/View/Bookmark/BookmarkCard/BookmarksListViewModel.swift +++ b/iOS/RollTheDice/RollTheDice/Source/View/Bookmark/BookmarkCard/BookmarksListViewModel.swift @@ -24,7 +24,10 @@ import SwiftUI extension BookmarksListViewModel { public func getAllBookmarksData(page: Int, size: Int) { - let accessToken = "5Gu45OmOoZnvANl-qfZv-xHv_2eSweVeAAAAAQopyNkAAAGQFbGnJSn2EFsnJsRZ" + guard let accessToken = TokenManager.shared.accessToken else { + print("Access token 사용 불가능...") + return + } if let cancellable = bookmarksCancellable { cancellable.cancel() From 7ecaf7661d5ee2381ebbcaf8f7e0394046fbd840 Mon Sep 17 00:00:00 2001 From: realhsb Date: Thu, 20 Jun 2024 08:53:00 +0900 Subject: [PATCH 10/19] =?UTF-8?q?chore:=20=EC=A3=BC=EC=84=9D=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../News/NewsList/NewsListViewModel.swift | 20 --------- .../Source/View/News/NewsList/NewsView.swift | 43 +------------------ .../View/Report/Type/TypePieChartView.swift | 1 - 3 files changed, 2 insertions(+), 62 deletions(-) diff --git a/iOS/RollTheDice/RollTheDice/Source/View/News/NewsList/NewsListViewModel.swift b/iOS/RollTheDice/RollTheDice/Source/View/News/NewsList/NewsListViewModel.swift index 2b9cbfbb..6948b661 100644 --- a/iOS/RollTheDice/RollTheDice/Source/View/News/NewsList/NewsListViewModel.swift +++ b/iOS/RollTheDice/RollTheDice/Source/View/News/NewsList/NewsListViewModel.swift @@ -60,7 +60,6 @@ extension NewsListViewModel { print("news 조회 성공") break case .failure(let error): -// print(error.localizedDescription) Log.network("network error", error.localizedDescription) } }, receiveValue: { [weak self] response in @@ -70,22 +69,3 @@ extension NewsListViewModel { }) } } - - -//public class NewsListViewModel: ObservableObject { -// // News = [NewsModel] -// @Published var newsList: [News] = [] -//// var currentPage = 0 -// -// init( -// newsList: [News] = [ -// -// .init(title: "네이버, 사우디 'LEAP 2024'서 AI·로봇 등 자사 기술력 뽐낸다", postDate: "2023년3월3일", image: "https://imgnews.pstatic.net/image/008/2024/03/05/0005007355_001_20240305100101016.jpg?type=w647", content: "네이버(NAVER)는 사우디아라비아에서 지난 4일부터 7일까지 열리는 글로벌 IT전시회 LEAP 2024에서 AI(인공지능), 클라우드, 로봇 등 자사 핵심 기술을 선보이고, 글로벌 업체들과 비즈니스 협력을 강화한다고 5일 밝혔다.", isBookmarked: false), -// .init(title: "앤스로픽 최신 AI 모델 '클로드3' 출시", postDate: "2023년3월13일", image: "https://imgnews.pstatic.net/image/014/2024/03/05/0005151141_001_20240305101610000.jpg?type=w647", content: "오픈AI의 대항마 앤스로픽이 생성형 인공지능(AI) 최신 모델 '클로드'(Claude)3를 선보이면서 생성형 AI 주도권을 잡기 위한 경쟁이 다시 뜨거워지고 있다. 앤스로픽은 지난 한 해 동안 구글과 세일즈포스, 아마존 등에서 총 73억 달러(약 9조7309억 원)를 투자받고 '클로드3'를 내놨는데 오픈AI의 챗GPT-4를 능가한다고 도발했다.", isBookmarked: true), -// .init(title: "SK C&C, 외부 전문가 대거 영입… “신성장 동력 강화”", postDate: "2023년2월13일", image: "https://imgnews.pstatic.net/image/366/2024/03/05/0000975131_001_20240305093504301.jpg?type=w647", content: "SK C&C는 국내외 신성장 동력 강화를 위해 인공지능(AI)·클라우드·디지털 팩토리·ESG(환경·사회·지배구조) 등 4대 성장 사업과 디지털 컨설팅 중심으로 외부 전문가를 대거 영입해 전진 배치했다고 5일 밝혔다.", isBookmarked: false), -// .init(title: "NHN, 작년 영업익 555억원...전년비 42% ↑", postDate: "2023년2월13일", image: "https://cdnimage.dailian.co.kr/news/202402/news_1707866329_1327972_m_1.png", content: "2NHN은 연결기준 지난해 영업이익이 555억원으로 전년 대비 42.2% 증가했다고 14일 밝혔다.같은 기간 매출은 7.3% 증가한 2조2696억원으로 연간 최대치를 기록했다. 작년 4분기 매출은 5983억원으로 전년 동기 대비 6.7% 올랐다. 반면 영업손실은 78억원으로 적자전환했다. 커머스 부문의 장기 미회수채권 대손상각비 인식과 기술 부문의 기 인식 매출 차감 등 일회성 요인이 영향을 미쳤다.", isBookmarked: false), -// ] -// ) { -// self.newsList = newsList -// } -//} diff --git a/iOS/RollTheDice/RollTheDice/Source/View/News/NewsList/NewsView.swift b/iOS/RollTheDice/RollTheDice/Source/View/News/NewsList/NewsView.swift index 81e81d9d..7e7731cf 100644 --- a/iOS/RollTheDice/RollTheDice/Source/View/News/NewsList/NewsView.swift +++ b/iOS/RollTheDice/RollTheDice/Source/View/News/NewsList/NewsView.swift @@ -43,46 +43,13 @@ struct NewsView: View { .frame(width: 322, height: 160) .clipShape(RoundedRectangle(cornerRadius: 8)) .shadow(color: .black.opacity(0.25), radius: 2, x: 0, y: 0) -// case .empty: -// Image(.exampleNews) -// .resizable() -// .aspectRatio(contentMode: .fill) -// .frame(width: 322, height: 160) -// .clipShape(RoundedRectangle(cornerRadius: 8)) -// .shadow(color: .black.opacity(0.25), radius: 2, x: 0, y: 0) -// case .failure(_): -// Image(.exampleNews) -// .resizable() -// .aspectRatio(contentMode: .fill) -// .frame(width: 322, height: 160) -// .clipShape(RoundedRectangle(cornerRadius: 8)) -// .shadow(color: .black.opacity(0.25), radius: 2, x: 0, y: 0) + @unknown default: Text(""); } } - - -// if isVisibleView { -// Button { -// let newsId:Int = news.newsId -// print("!!!!!!!!!!! newsID : \(news.newsId)") -// pathModel.paths.append(.detailNewsView(newsId: newsId)) -// } label: { -// Text("더보기") -// .font(.pretendardBold14) -// .foregroundStyle(.gray01) -// .padding(.horizontal, 30) -// .padding(.vertical, 13) -// .background(.primary01) -// .clipShape( -// RoundedRectangle(cornerRadius: 16) -// ) -// .shadow(color: .basicBlack.opacity(0.25), radius: 2, x: 0, y: 0) -// -// } -// } + Button { let newsId:Int = news.newsId print("!!!!!!!!!!! newsID : \(news.newsId)") @@ -134,9 +101,3 @@ struct NewsView: View { NewsView(news: .init(newsId: 1, title: "1분기 선방한 dddddddd韓게임사들…엔씨만 울었다", content: "내용내용ㄴㅇㅇㅇ", thumbnailUrl: "", postDate: "2222-22-22", isBookmarked: true)) .environmentObject(PathModel()) } -//#Preview(traits: .sizeThatFitsLayout) { -// NewsView(news: .init(title: "NHN, 작년 영업익 555억원...전년비 42%", postDate: "2023년2월13일", image: "https://cdnimage.dailian.co.kr/news/202402/news_1707866329_1327972_m_1.png", content: "2NHN은 연결기준 지난해 영업이익이 555억원으로 전년 대비 42.2% 증가했다고 14일 밝혔다.같은 기간 매출은 7.3% 증가한 2조2696억원으로 연간 최대치를 기록했다. 작년 4분기 매출은 5983억원으로 전년 동기 대비 6.7% 올랐다. 반면 영업손실은 78억원으로 적자전환했다. 커머스 부문의 장기 미회수채권 대손상각비 인식과 기술 부문의 기 인식 매출 차감 등 일회성 요인이 영향을 미쳤다.", isBookmarked: false)) -// .previewInterfaceOrientation(.landscapeLeft) -// .previewLayout(.sizeThatFits) -// .colorScheme(.dark) -//} diff --git a/iOS/RollTheDice/RollTheDice/Source/View/Report/Type/TypePieChartView.swift b/iOS/RollTheDice/RollTheDice/Source/View/Report/Type/TypePieChartView.swift index f27b7243..7a2e0399 100644 --- a/iOS/RollTheDice/RollTheDice/Source/View/Report/Type/TypePieChartView.swift +++ b/iOS/RollTheDice/RollTheDice/Source/View/Report/Type/TypePieChartView.swift @@ -28,7 +28,6 @@ struct TypePieChartView: View { .cornerRadius(8) .foregroundStyle(report.category?.color.gradient ?? Color.primary01.gradient) } - /// pie chart의 가운데 문구 .chartBackground { chartProxy in GeometryReader { geometry in let frame = geometry[chartProxy.plotFrame!] From 003da6c76ccbb48d9ca156d34770390e7b8827c9 Mon Sep 17 00:00:00 2001 From: realhsb Date: Thu, 20 Jun 2024 08:53:24 +0900 Subject: [PATCH 11/19] =?UTF-8?q?chore:=20Bookmark=20Service=EC=9D=98=20ta?= =?UTF-8?q?sk=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Source/Domain/Service/BookmarksService.swift | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/iOS/RollTheDice/RollTheDice/Source/Domain/Service/BookmarksService.swift b/iOS/RollTheDice/RollTheDice/Source/Domain/Service/BookmarksService.swift index 926408bc..1d24ede8 100644 --- a/iOS/RollTheDice/RollTheDice/Source/Domain/Service/BookmarksService.swift +++ b/iOS/RollTheDice/RollTheDice/Source/Domain/Service/BookmarksService.swift @@ -12,7 +12,7 @@ enum BookmarksService { case bookmarksIsChecked(newsId: Int, accessToken: String) ///뉴스 북마크 여부 조회 case saveBookmarks(newsId: Int, accessToken: String) ///북마크 저장 case deleteBookmarks(newsId: Int, accessToken: String) ///북마크 삭제 - case allBookmarks(page: Int, size: Int, accessToken: String) ///북마크 전체 조회/ + case allBookmarks(page: Int, size: Int, accessToken: String) ///북마크 전체 조회 } extension BookmarksService: BaseTargetType { @@ -49,12 +49,14 @@ extension BookmarksService: BaseTargetType { var task: Moya.Task { switch self { - case .bookmarksIsChecked(let newsId, _), - .saveBookmarks(let newsId, _), - .deleteBookmarks(let newsId, _): + case .bookmarksIsChecked(_, _), + .deleteBookmarks(_, _): let parameters : [String : Any] = [:] return .requestParameters(parameters: parameters, encoding: URLEncoding.default) + case .saveBookmarks(_, _): + return .requestPlain + case .allBookmarks(let page, let size, _): let parameters : [String : Any] = [ "page" : page, From d009b63a9d3caacebaf4e78c627ec1ef4587db7a Mon Sep 17 00:00:00 2001 From: realhsb Date: Thu, 20 Jun 2024 09:17:40 +0900 Subject: [PATCH 12/19] =?UTF-8?q?feat:=20NewsListView=EC=97=90=20Bookmarks?= =?UTF-8?q?ListViewModel=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Source/View/News/NewsList/NewsListView.swift | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/iOS/RollTheDice/RollTheDice/Source/View/News/NewsList/NewsListView.swift b/iOS/RollTheDice/RollTheDice/Source/View/News/NewsList/NewsListView.swift index d95bb351..45dd6652 100644 --- a/iOS/RollTheDice/RollTheDice/Source/View/News/NewsList/NewsListView.swift +++ b/iOS/RollTheDice/RollTheDice/Source/View/News/NewsList/NewsListView.swift @@ -10,6 +10,7 @@ import SwiftUI struct NewsListView: View { var newsListViewModel: NewsListViewModel + var bookmarksViewModel: BookmarksListViewModel var newsId: Int? @State var selectedIndex: Int = 0 @@ -18,7 +19,7 @@ struct NewsListView: View { ZStack { Color.backgroundDark.ignoresSafeArea(.all) - NewsListContentView(newsList: newsListViewModel.newsList ?? []) + NewsListContentView(newsList: newsListViewModel.newsList ?? [], bookmarksViewModel: bookmarksViewModel) } .task { newsListViewModel.getAllNewsData(page: 0, size: 10) @@ -27,6 +28,7 @@ struct NewsListView: View { private struct NewsListContentView: View { var newsList: [NewsList] + var bookmarksViewModel: BookmarksListViewModel fileprivate var body: some View { @@ -35,7 +37,7 @@ struct NewsListView: View { LazyHStack { ForEach(newsList) { news in - NewsView(news: news) + NewsView(news: news, bookmarksViewModel: bookmarksViewModel) .frame(width: proxy.size.width) .scrollTransition(.interactive, axis: .horizontal) { effect, phase in effect @@ -69,6 +71,6 @@ struct NewsListView: View { } #Preview { - NewsListView(newsListViewModel: NewsListViewModel()) + NewsListView(newsListViewModel: NewsListViewModel(), bookmarksViewModel: BookmarksListViewModel()) .previewInterfaceOrientation(.landscapeLeft) } From 64498015678c39d29555ba7f23268e6214ed9383 Mon Sep 17 00:00:00 2001 From: realhsb Date: Thu, 20 Jun 2024 09:17:50 +0900 Subject: [PATCH 13/19] =?UTF-8?q?chore:=20=EC=A3=BC=EC=84=9D=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Source/View/News/NewsList/NewsView.swift | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/iOS/RollTheDice/RollTheDice/Source/View/News/NewsList/NewsView.swift b/iOS/RollTheDice/RollTheDice/Source/View/News/NewsList/NewsView.swift index 7e7731cf..341cd109 100644 --- a/iOS/RollTheDice/RollTheDice/Source/View/News/NewsList/NewsView.swift +++ b/iOS/RollTheDice/RollTheDice/Source/View/News/NewsList/NewsView.swift @@ -10,12 +10,9 @@ import SwiftUI struct NewsView: View { @EnvironmentObject var pathModel : PathModel - -// var newsListViewModel: NewsListViewModel + var news: NewsList -// var isVisibleView: Bool = true -// var cardWidth: Double = 0.0 -// var cardHeight: Double = 0.0 + var bookmarksViewModel: BookmarksListViewModel var body: some View { VStack(alignment: .center, spacing: 20) { @@ -52,7 +49,6 @@ struct NewsView: View { Button { let newsId:Int = news.newsId - print("!!!!!!!!!!! newsID : \(news.newsId)") pathModel.paths.append(.detailNewsView(newsId: newsId)) } label: { Text("더보기") @@ -74,7 +70,6 @@ struct NewsView: View { .padding(.top, 50) .frame(width: 380) .background( -// LinearGradient(colors: isVisibleView ? [.basicWhite, .primaryLight01] : [.basicWhite], startPoint: .top, endPoint: .bottom) LinearGradient(colors: [.basicWhite, .primaryLight01], startPoint: .top, endPoint: .bottom) ) .clipShape(RoundedRectangle(cornerRadius: 12)) @@ -84,9 +79,13 @@ struct NewsView: View { HStack { Spacer() Button { - + if news.isBookmarked ?? false { + + } else { + + } } label: { - Image(.bookmarkfill) + Image(news.isBookmarked ?? false ? .bookmarkfill : .bookmarkunfill) .shadow(color: .gray06, radius: 2) } .offset(CGSize(width: -20, height: -10)) @@ -98,6 +97,6 @@ struct NewsView: View { } #Preview { - NewsView(news: .init(newsId: 1, title: "1분기 선방한 dddddddd韓게임사들…엔씨만 울었다", content: "내용내용ㄴㅇㅇㅇ", thumbnailUrl: "", postDate: "2222-22-22", isBookmarked: true)) + NewsView(news: .init(newsId: 1, title: "1분기 선방한 dddddddd韓게임사들…엔씨만 울었다", content: "내용내용ㄴㅇㅇㅇ", thumbnailUrl: "", postDate: "2222-22-22", isBookmarked: true), bookmarksViewModel: BookmarksListViewModel()) .environmentObject(PathModel()) } From 85f03cd58c948a9117ccf9d75ab1cb7a570d06b3 Mon Sep 17 00:00:00 2001 From: realhsb Date: Thu, 20 Jun 2024 09:18:14 +0900 Subject: [PATCH 14/19] =?UTF-8?q?feat:=20=EB=B6=81=EB=A7=88=ED=81=AC=20?= =?UTF-8?q?=EC=97=AC=EB=B6=80=20=ED=99=95=EC=9D=B8=20=ED=95=A8=EC=88=98=20?= =?UTF-8?q?=EB=B0=8F=20=EC=A3=BC=EC=84=9D=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BookmarkCard/BookmarksListViewModel.swift | 74 +++++++++++++------ 1 file changed, 52 insertions(+), 22 deletions(-) diff --git a/iOS/RollTheDice/RollTheDice/Source/View/Bookmark/BookmarkCard/BookmarksListViewModel.swift b/iOS/RollTheDice/RollTheDice/Source/View/Bookmark/BookmarkCard/BookmarksListViewModel.swift index f9342a31..0e87e989 100644 --- a/iOS/RollTheDice/RollTheDice/Source/View/Bookmark/BookmarkCard/BookmarksListViewModel.swift +++ b/iOS/RollTheDice/RollTheDice/Source/View/Bookmark/BookmarkCard/BookmarksListViewModel.swift @@ -23,6 +23,8 @@ import SwiftUI } extension BookmarksListViewModel { + + /// 북마크 전체 조회 public func getAllBookmarksData(page: Int, size: Int) { guard let accessToken = TokenManager.shared.accessToken else { print("Access token 사용 불가능...") @@ -56,26 +58,54 @@ extension BookmarksListViewModel { print(response) }) } -} + + /// 뉴스 북마크 여부 조회 + public func isBookmark(newsId: Int) -> Bool { -//public class BookmarksListViewModel: ObservableObject { -// @Published var bookmarkList: [Bookmarks] -// -// init( -// bookmarkList: [Bookmarks] = [ -// .init(title: "2024년 ‘소셜 미디어 다이어트’를 위해 바꿔볼 것", date: "2023년12월3일", image: "exampleNews", content: "2024년으로 접어든지 한 달이 넘었다. 하지만 올 해가 어떻게 흘러갈지 예측하기는 쉽지 않다. 한 가지 확실한 것은 정치적으로 매우 중요한 해라는 점이다. 미국과 러시아, 우크라이나, 방글라데시, 인도, 대만, 한국, 남아프리카공화국, 유럽의회, 영국에서 선거가 치러질 예정이다.", isBookmarked: false), -// .init(title: "앤스로픽 최신 AI 모델 '클로드3' 출시", date: "2023년3월13일", image: "https://imgnews.pstatic.net/image/014/2024/03/05/0005151141_001_20240305101610000.jpg?type=w647", content: "오픈AI의 대항마 앤스로픽이 생성형 인공지능(AI) 최신 모델 '클로드'(Claude)3를 선보이면서 생성형 AI 주도권을 잡기 위한 경쟁이 다시 뜨거워지고 있다. 앤스로픽은 지난 한 해 동안 구글과 세일즈포스, 아마존 등에서 총 73억 달러(약 9조7309억 원)를 투자받고 '클로드3'를 내놨는데 오픈AI의 챗GPT-4를 능가한다고 도발했다.", isBookmarked: true), -// .init(title: "SK C&C, 외부 전문가 대거 영입… “신성장 동력 강화”", date: "2023년2월13일", image: "https://imgnews.pstatic.net/image/366/2024/03/05/0000975131_001_20240305093504301.jpg?type=w647", content: "SK C&C는 국내외 신성장 동력 강화를 위해 인공지능(AI)·클라우드·디지털 팩토리·ESG(환경·사회·지배구조) 등 4대 성장 사업과 디지털 컨설팅 중심으로 외부 전문가를 대거 영입해 전진 배치했다고 5일 밝혔다.", isBookmarked: false), -// .init(title: "NHN, 작년 영업익 555억원...전년비 42% ↑", date: "2023년2월13일", image: "https://cdnimage.dailian.co.kr/news/202402/news_1707866329_1327972_m_1.png", content: "2NHN은 연결기준 지난해 영업이익이 555억원으로 전년 대비 42.2% 증가했다고 14일 밝혔다.같은 기간 매출은 7.3% 증가한 2조2696억원으로 연간 최대치를 기록했다. 작년 4분기 매출은 5983억원으로 전년 동기 대비 6.7% 올랐다. 반면 영업손실은 78억원으로 적자전환했다. 커머스 부문의 장기 미회수채권 대손상각비 인식과 기술 부문의 기 인식 매출 차감 등 일회성 요인이 영향을 미쳤다.", isBookmarked: false), -// -// .init(title: "이종호 과기장관 5년 뒤 구축될 바이오파운드리에 산학연 역량 모아야", date: "2023년3월13일", image: "https://imgnews.pstatic.net/image/003/2024/03/05/NISI20231030_0001398722_web_20231030141808_20240305103108748.jpg?type=w647", content: "정부가 내년부터 합성생물학의 필수 인프라인 '국가 바이오파운드리' 구축에 본격 나서는 가운데 이종호 과학기술정보통신부 장관이 한국생명공학연구원에서 운영 중인 사전연구용 시설을 찾아 구체적인 인프라 구축 계획 등을 점검했다.이 장관은 5일 합성생물학 육성을 위해 바이오파운드리 연구현장을 방문하고, 산·학·연 전문가들을 만났다. 이번 방문은 지난해 미국, 영국과의 정상회담 시 논의됐던 첨단바이오 협력을 위한 후속조치의 일환으로 추진됐다.", isBookmarked: false), -// .init(title: "SW산업 육성에 7308억 예산투자, SaaS 등 육성", date: "2023년3월13일", image: "https://imgnews.pstatic.net/image/008/2024/03/05/0005007507_001_20240305135301539.jpg?type=w647", content: "SW(소프트웨어) 산업의 SaaS(서비스형 소프트웨어) 전환 등 SW산업 육성을 위해 정부 예산 7308억원이 투자된다. 강도현 과학기술정보통신부 제2차관은 5일 오전 서울 을지로 더존비즈온 을지사옥에서 열린 'AI(인공지능) 일상화, SW도 이제 서비스형 SW'라는 주제로 열린 현장 간담회에서 정부도 대한민국 SW산업의 미래가 SaaS에 있다고 생각하고 올해 'SaaS 혁신펀드'를 새롭게 조성하는 등 SaaS 육성 및 기존 SW 기업의 SaaS 전환을 위해 다양한 지원을 추진 중이라며 이같이 밝혔다.", isBookmarked: false), -// .init(title: "파수, 기업용 AI ‘엔터프라이즈 LLM’ 출시", date: "2023년3월13일", image: "https://imgnews.pstatic.net/image/018/2024/03/05/0005685566_001_20240305103201036.jpg?type=w647", content: "2NHN은 연결기준 지난해 영업이익이 555억원으로 전년 대비 42.2% 증가했다고 14일 밝혔다.같은 기간 매출은 7.3% 증가한 2조2696억원으로 연간 최대치를 기록했다. 작년 4분기 매출은 5983억원으로 전년 동기 대비 6.7% 올랐다. 반면 영업손실은 78억원으로 적자전환했다. 커머스 부문의 장기 미회수채권 대손상각비 인식과 기술 부문의 기 인식 매출 차감 등 일회성 요인이 영향을 미쳤다.", isBookmarked: false), -// .init(title: "NHN, 작년 영업익 555억원...전년비 42% ↑", date: "2023년2월13일", image: "https://cdnimage.dailian.co.kr/news/202402/news_1707866329_1327972_m_1.png", content: "2NHN은 연결기준 지난해 영업이익이 555억원으로 전년 대비 42.2% 증가했다고 14일 밝혔다.같은 기간 매출은 7.3% 증가한 2조2696억원으로 연간 최대치를 기록했다. 작년 4분기 매출은 5983억원으로 전년 동기 대비 6.7% 올랐다. 반면 영업손실은 78억원으로 적자전환했다. 커머스 부문의 장기 미회수채권 대손상각비 인식과 기술 부문의 기 인식 매출 차감 등 일회성 요인이 영향을 미쳤다.", isBookmarked: false), -// .init(title: "NHN, 작년 영업익 555억원...전년비 42% ↑", date: "2023년2월13일", image: "https://cdnimage.dailian.co.kr/news/202402/news_1707866329_1327972_m_1.png", content: "2NHN은 연결기준 지난해 영업이익이 555억원으로 전년 대비 42.2% 증가했다고 14일 밝혔다.같은 기간 매출은 7.3% 증가한 2조2696억원으로 연간 최대치를 기록했다. 작년 4분기 매출은 5983억원으로 전년 동기 대비 6.7% 올랐다. 반면 영업손실은 78억원으로 적자전환했다. 커머스 부문의 장기 미회수채권 대손상각비 인식과 기술 부문의 기 인식 매출 차감 등 일회성 요인이 영향을 미쳤다.", isBookmarked: false), -// .init(title: "NHN, 작년 영업익 555억원...전년비 42% ↑", date: "2023년2월13일", image: "https://cdnimage.dailian.co.kr/news/202402/news_1707866329_1327972_m_1.png", content: "2NHN은 연결기준 지난해 영업이익이 555억원으로 전년 대비 42.2% 증가했다고 14일 밝혔다.같은 기간 매출은 7.3% 증가한 2조2696억원으로 연간 최대치를 기록했다. 작년 4분기 매출은 5983억원으로 전년 동기 대비 6.7% 올랐다. 반면 영업손실은 78억원으로 적자전환했다. 커머스 부문의 장기 미회수채권 대손상각비 인식과 기술 부문의 기 인식 매출 차감 등 일회성 요인이 영향을 미쳤다.", isBookmarked: false), -// ] -// ) { -// self.bookmarkList = bookmarkList -// } -//} + var isBookmarked: Bool = false + + guard let accessToken = TokenManager.shared.accessToken else { + print("Access token 사용 불가능...") + return isBookmarked + } + + if let cancellable = bookmarksCancellable { + cancellable.cancel() + } + + bookmarksCancellable = provider.requestWithProgressPublisher( + .saveBookmarks( + newsId: newsId, + accessToken: accessToken + ) + ) + .compactMap { $0.response?.data } + .receive(on: DispatchQueue.main) + .decode(type: Bookmarks.self, decoder: JSONDecoder()) + .sink(receiveCompletion: { result in + switch result { + case .finished: + print("bookmark 여부 확인 성공") + case .failure(let error): + Log.network("network error bookmark 여부 확인 실패", error.localizedDescription) + } + }, receiveValue: { [weak self] response in + print(response) + + if response.isBookmarked ?? false { + isBookmarked = true + } else { + isBookmarked = false + } + }) + + return isBookmarked + } + + /// 북마크 저장 + + + /// 북마크 삭제 + + +} From 3ec8334a7b3d3c62eb7c46674fdba1a3d3973aef Mon Sep 17 00:00:00 2001 From: realhsb Date: Thu, 20 Jun 2024 09:18:27 +0900 Subject: [PATCH 15/19] =?UTF-8?q?chore:=20=EC=A3=BC=EC=84=9D=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Bookmark/BookmarkCard/BookmarkView.swift | 6 ----- .../View/Bookmark/BookmarkListView.swift | 24 ------------------- 2 files changed, 30 deletions(-) diff --git a/iOS/RollTheDice/RollTheDice/Source/View/Bookmark/BookmarkCard/BookmarkView.swift b/iOS/RollTheDice/RollTheDice/Source/View/Bookmark/BookmarkCard/BookmarkView.swift index ea1086b4..24389491 100644 --- a/iOS/RollTheDice/RollTheDice/Source/View/Bookmark/BookmarkCard/BookmarkView.swift +++ b/iOS/RollTheDice/RollTheDice/Source/View/Bookmark/BookmarkCard/BookmarkView.swift @@ -73,9 +73,3 @@ struct BookmarkView: View { } } } - -//#Preview { -// BookmarkView(bookmark: .init(newsId: 0, title: "NHN, 작년 영업익 555억원...전년비 42% ↑", thumbnailURL: <#T##String#>, postDate: <#T##String#>, isBookmarked: <#T##Bool#>)) -// -// BookmarkView(bookmark: .init(title: "NHN, 작년 영업익 555억원...전년비 42% ↑", date: "2023년2월13일", image: "https://cdnimage.dailian.co.kr/news/202402/news_1707866329_1327972_m_1.png", content: "2NHN은 연결기준 지난해 영업이익이 555억원으로 전년 대비 42.2% 증가했다고 14일 밝혔다.같은 기간 매출은 7.3% 증가한 2조2696억원으로 연간 최대치를 기록했다. 작년 4분기 매출은 5983억원으로 전년 동기 대비 6.7% 올랐다. 반면 영업손실은 78억원으로 적자전환했다. 커머스 부문의 장기 미회수채권 대손상각비 인식과 기술 부문의 기 인식 매출 차감 등 일회성 요인이 영향을 미쳤다.", isBookmarked: false)) -//} diff --git a/iOS/RollTheDice/RollTheDice/Source/View/Bookmark/BookmarkListView.swift b/iOS/RollTheDice/RollTheDice/Source/View/Bookmark/BookmarkListView.swift index ae4c8175..d7bb4c80 100644 --- a/iOS/RollTheDice/RollTheDice/Source/View/Bookmark/BookmarkListView.swift +++ b/iOS/RollTheDice/RollTheDice/Source/View/Bookmark/BookmarkListView.swift @@ -67,30 +67,6 @@ struct BookmarkListView: View { } } } - -// private struct BookmarkListContentView: View { -// @StateObject var bookmarkListViewModel: BookmarkListViewModel -// var columns: [GridItem] = [ GridItem(), GridItem()] -// -// fileprivate var body: some View { -// ScrollViewReader { value in -// ScrollView(.horizontal, showsIndicators: false) { -// LazyHGrid(rows: columns, spacing: 10) { -// ForEach(bookmarkListViewModel.bookmarkList, id: \.self) { bookmark in -// BookmarkView(bookmark: bookmark) -//// .onTapGesture { -//// withAnimation { -//// selectedIndex = index -//// value.scrollTo(index) -//// } -//// } -// } -// } -// .padding(.vertical, 90) -// } -// } -// } -// } } #Preview { From 3b019167822b37cd2b629bb82904a268c708f3bb Mon Sep 17 00:00:00 2001 From: realhsb Date: Thu, 20 Jun 2024 09:42:38 +0900 Subject: [PATCH 16/19] =?UTF-8?q?feat:=20=EB=B6=81=EB=A7=88=ED=81=AC=20?= =?UTF-8?q?=EC=A0=80=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BookmarkCard/BookmarksListViewModel.swift | 39 ++++++++++++++++++- .../Source/View/News/NewsList/NewsView.swift | 4 +- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/iOS/RollTheDice/RollTheDice/Source/View/Bookmark/BookmarkCard/BookmarksListViewModel.swift b/iOS/RollTheDice/RollTheDice/Source/View/Bookmark/BookmarkCard/BookmarksListViewModel.swift index 0e87e989..3b91e22e 100644 --- a/iOS/RollTheDice/RollTheDice/Source/View/Bookmark/BookmarkCard/BookmarksListViewModel.swift +++ b/iOS/RollTheDice/RollTheDice/Source/View/Bookmark/BookmarkCard/BookmarksListViewModel.swift @@ -103,7 +103,44 @@ extension BookmarksListViewModel { } /// 북마크 저장 - + public func saveBookmark(newsId: Int) { + print("saveBookmark \(newsId)") + + guard let accessToken = TokenManager.shared.accessToken else { + print("Access token 사용 불가능...") + return + } + + if let cancellable = bookmarksCancellable { + cancellable.cancel() + } + + bookmarksCancellable = provider.requestWithProgressPublisher( + .saveBookmarks( + newsId: newsId, + accessToken: accessToken + ) + ) +// .compactMap { $0.response?.data } + .receive(on: DispatchQueue.main) +// .decode(type: Bookmarks.self, decoder: JSONDecoder()) + .sink(receiveCompletion: { result in + switch result { + case .finished: + print("bookmark 여부 확인 성공") + case .failure(let error): + Log.network("network error bookmark 여부 확인 실패", error.localizedDescription) + } + }, receiveValue: { [weak self] response in + print(response) + if response.response?.statusCode == 201 { + print("북마크 저장 성공") + } else { + print("북마크 저장 실패") + } + }) + + } /// 북마크 삭제 diff --git a/iOS/RollTheDice/RollTheDice/Source/View/News/NewsList/NewsView.swift b/iOS/RollTheDice/RollTheDice/Source/View/News/NewsList/NewsView.swift index 341cd109..0ff8875c 100644 --- a/iOS/RollTheDice/RollTheDice/Source/View/News/NewsList/NewsView.swift +++ b/iOS/RollTheDice/RollTheDice/Source/View/News/NewsList/NewsView.swift @@ -79,10 +79,12 @@ struct NewsView: View { HStack { Spacer() Button { + print("북마크 버튼눌림") + print(news.isBookmarked) if news.isBookmarked ?? false { } else { - + bookmarksViewModel.saveBookmark(newsId: news.newsId) } } label: { Image(news.isBookmarked ?? false ? .bookmarkfill : .bookmarkunfill) From 4667af84235abb9dd2c7cf4276b342ab72af114e Mon Sep 17 00:00:00 2001 From: realhsb Date: Thu, 20 Jun 2024 09:42:54 +0900 Subject: [PATCH 17/19] =?UTF-8?q?chore:=20BookmarksViewModel=20=EC=97=B0?= =?UTF-8?q?=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- iOS/RollTheDice/RollTheDice/RollTheDiceApp.swift | 2 +- .../RollTheDice/Source/View/MainTab/MainTabView.swift | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/iOS/RollTheDice/RollTheDice/RollTheDiceApp.swift b/iOS/RollTheDice/RollTheDice/RollTheDiceApp.swift index 3ea1b27f..5009d613 100644 --- a/iOS/RollTheDice/RollTheDice/RollTheDiceApp.swift +++ b/iOS/RollTheDice/RollTheDice/RollTheDiceApp.swift @@ -40,7 +40,7 @@ struct RollTheDiceApp: App { .environmentObject(signUpViewModel) case .completedSignUp: NavigationStack(path: $pathModel.paths) { - MainTabView(newsListViewModel: newsListViewModel) + MainTabView(newsListViewModel: newsListViewModel, bookmarksListViewModel: bookmarkListViewModel) .navigationDestination(for: PathType.self, destination: { pathType in // 각 뷰마다 .navigationBarBackButtonHidden() 설정하기! diff --git a/iOS/RollTheDice/RollTheDice/Source/View/MainTab/MainTabView.swift b/iOS/RollTheDice/RollTheDice/Source/View/MainTab/MainTabView.swift index 242bc53b..491633c9 100644 --- a/iOS/RollTheDice/RollTheDice/Source/View/MainTab/MainTabView.swift +++ b/iOS/RollTheDice/RollTheDice/Source/View/MainTab/MainTabView.swift @@ -11,6 +11,7 @@ struct MainTabView: View { @EnvironmentObject private var pathModel: PathModel var newsListViewModel: NewsListViewModel + var bookmarksListViewModel: BookmarksListViewModel @EnvironmentObject var authViewModel: AuthenticationViewModel @@ -37,7 +38,7 @@ struct MainTabView: View { } .tag(0) - NewsListView(newsListViewModel: newsListViewModel) + NewsListView(newsListViewModel: newsListViewModel, bookmarksViewModel: bookmarksListViewModel) .tabItem { Image(systemName: "square.3.layers.3d.down.left") } @@ -59,7 +60,7 @@ struct MainTabView: View { } #Preview { - MainTabView(newsListViewModel: NewsListViewModel()) + MainTabView(newsListViewModel: NewsListViewModel(), bookmarksListViewModel: BookmarksListViewModel()) .environmentObject(PathModel()) // .environmentObject(NewsListViewModel()) } From 0c5d6007b623acc7e36af89c6fc918fa163561d9 Mon Sep 17 00:00:00 2001 From: realhsb Date: Thu, 20 Jun 2024 10:12:23 +0900 Subject: [PATCH 18/19] =?UTF-8?q?feat:=20=EB=B6=81=EB=A7=88=ED=81=AC=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BookmarkCard/BookmarksListViewModel.swift | 43 +++++++++++++++++-- .../Source/View/News/NewsList/NewsView.swift | 2 +- 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/iOS/RollTheDice/RollTheDice/Source/View/Bookmark/BookmarkCard/BookmarksListViewModel.swift b/iOS/RollTheDice/RollTheDice/Source/View/Bookmark/BookmarkCard/BookmarksListViewModel.swift index 3b91e22e..f31a3395 100644 --- a/iOS/RollTheDice/RollTheDice/Source/View/Bookmark/BookmarkCard/BookmarksListViewModel.swift +++ b/iOS/RollTheDice/RollTheDice/Source/View/Bookmark/BookmarkCard/BookmarksListViewModel.swift @@ -127,22 +127,57 @@ extension BookmarksListViewModel { .sink(receiveCompletion: { result in switch result { case .finished: - print("bookmark 여부 확인 성공") + print("bookmarks 저장") case .failure(let error): Log.network("network error bookmark 여부 확인 실패", error.localizedDescription) } }, receiveValue: { [weak self] response in print(response) if response.response?.statusCode == 201 { - print("북마크 저장 성공") + print("bookmarks 저장 성공") } else { - print("북마크 저장 실패") + print("bookmarks 저장 실패") } }) } /// 북마크 삭제 - + public func deleteBookmark(newsId: Int) { + print("saveBookmark \(newsId)") + + guard let accessToken = TokenManager.shared.accessToken else { + print("Access token 사용 불가능...") + return + } + + if let cancellable = bookmarksCancellable { + cancellable.cancel() + } + + bookmarksCancellable = provider.requestWithProgressPublisher( + .deleteBookmarks( + newsId: newsId, + accessToken: accessToken + ) + ) + .receive(on: DispatchQueue.main) + .sink(receiveCompletion: { result in + switch result { + case .finished: + print("bookmarks 삭제") + case .failure(let error): + Log.network("network error bookmark 여부 확인 실패", error.localizedDescription) + } + }, receiveValue: { [weak self] response in + print(response) + if response.response?.statusCode == 204 { + print("bookmarks 삭제 성공") + } else { + print("bookmarks 삭제 실패") + } + }) + + } } diff --git a/iOS/RollTheDice/RollTheDice/Source/View/News/NewsList/NewsView.swift b/iOS/RollTheDice/RollTheDice/Source/View/News/NewsList/NewsView.swift index 0ff8875c..d346735d 100644 --- a/iOS/RollTheDice/RollTheDice/Source/View/News/NewsList/NewsView.swift +++ b/iOS/RollTheDice/RollTheDice/Source/View/News/NewsList/NewsView.swift @@ -82,7 +82,7 @@ struct NewsView: View { print("북마크 버튼눌림") print(news.isBookmarked) if news.isBookmarked ?? false { - + bookmarksViewModel.deleteBookmark(newsId: news.newsId) } else { bookmarksViewModel.saveBookmark(newsId: news.newsId) } From 1110c4a75caafac5474563561bfbebbf810622be Mon Sep 17 00:00:00 2001 From: realhsb Date: Thu, 20 Jun 2024 10:12:34 +0900 Subject: [PATCH 19/19] =?UTF-8?q?chore:=20=EC=A3=BC=EC=84=9D=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Source/View/Bookmark/BookmarkCard/BookmarkView.swift | 5 ----- 1 file changed, 5 deletions(-) diff --git a/iOS/RollTheDice/RollTheDice/Source/View/Bookmark/BookmarkCard/BookmarkView.swift b/iOS/RollTheDice/RollTheDice/Source/View/Bookmark/BookmarkCard/BookmarkView.swift index 24389491..f6ddfdd7 100644 --- a/iOS/RollTheDice/RollTheDice/Source/View/Bookmark/BookmarkCard/BookmarkView.swift +++ b/iOS/RollTheDice/RollTheDice/Source/View/Bookmark/BookmarkCard/BookmarkView.swift @@ -7,11 +7,6 @@ import SwiftUI -//let id = UUID().uuidString -//let newsId: Int -//let title, thumbnailURL, postDate: String -//let isBookmarked: Bool - struct BookmarkView: View { @State var bookmark: Bookmarks var body: some View {