diff --git a/iOS-NOTTODO/Widget-NOTTODO/Network/Service/WidgetService.swift b/iOS-NOTTODO/Widget-NOTTODO/Network/Service/WidgetService.swift new file mode 100644 index 0000000..2b9afe2 --- /dev/null +++ b/iOS-NOTTODO/Widget-NOTTODO/Network/Service/WidgetService.swift @@ -0,0 +1,64 @@ +// +// WidgetService.swift +// iOS-NOTTODO +// +// Created by 강윤서 on 5/10/24. +// + +import Foundation + +typealias QuoteData = GeneralResponse + +struct WidgetService { + + static let shared = WidgetService() + private init() {} + + private let session = URLSession.shared + + func fetchWiseSaying() async throws -> QuoteResponseDTO { + do { + return try await getWiseSaying(from: generateURL()) + } catch { + switch error { + case NetworkError.networkError: + print("네트워크 에러가 발생") + case NetworkError.invalidResponse: + print("유효하지 않은 응답") + case NetworkError.dataParsingError: + print("데이터 파싱 실패") + default: + print("알 수 없는 에러 발생") + } + throw error + } + } + + private func getWiseSaying(from url: URL) async throws -> QuoteResponseDTO { + let (data, response) = try await session.data(from: url) + + guard let httpResponse = response as? HTTPURLResponse else { + throw NetworkError.networkError + } + + guard (200..<300).contains(httpResponse.statusCode) else { + throw NetworkError.invalidResponse + } + + do { + let result = try JSONDecoder().decode(QuoteData.self, from: data) + guard let responseData = result.data else { + throw NetworkError.dataParsingError + } + return responseData + } catch { + throw NetworkError.dataParsingError + } + } + + private func generateURL() -> URL { + let baseURL = Bundle.main.baseURL + let url = baseURL + URLConstant.quote + return URL(string: url)! + } +} diff --git a/iOS-NOTTODO/Widget-NOTTODO/Provider/MissionProvider.swift b/iOS-NOTTODO/Widget-NOTTODO/Provider/MissionProvider.swift new file mode 100644 index 0000000..6dccff5 --- /dev/null +++ b/iOS-NOTTODO/Widget-NOTTODO/Provider/MissionProvider.swift @@ -0,0 +1,46 @@ +// +// MissionProvider.swift +// iOS-NOTTODO +// +// Created by 강윤서 on 5/11/24. +// + +import SwiftUI +import WidgetKit + +struct Provider: AppIntentTimelineProvider { + @AppStorage("dailyMission", store: UserDefaults.shared) var sharedData: Data = Data() + + func placeholder(in context: Context) -> SimpleEntry { + SimpleEntry(todayMission: [], quote: "") + } + + func snapshot(for configuration: ConfigurationAppIntent, in context: Context) async -> SimpleEntry { + do { + let entry = try await getTimelineEntry() + return entry + } catch { + return SimpleEntry(todayMission: [], quote: "") + } + } + + func timeline(for configuration: ConfigurationAppIntent, in context: Context) async -> Timeline { + do { + let entry = try await getTimelineEntry() + return Timeline(entries: [entry], policy: .never) + } catch { + return Timeline(entries: [], policy: .never) + } + + } + + private func getTimelineEntry() async throws -> SimpleEntry { + guard let decodedData = try? JSONDecoder().decode([DailyMissionResponseDTO].self, from: sharedData) else { + return SimpleEntry(todayMission: [], quote: "") + } + + let quoteResponse = try await WidgetService.shared.fetchWiseSaying() + let quote = quoteResponse.description + " - " + quoteResponse.author + return SimpleEntry(todayMission: decodedData, quote: quote) + } +} diff --git a/iOS-NOTTODO/Widget-NOTTODO/Provider/TimeEntity.swift b/iOS-NOTTODO/Widget-NOTTODO/Provider/TimeEntity.swift new file mode 100644 index 0000000..2679e15 --- /dev/null +++ b/iOS-NOTTODO/Widget-NOTTODO/Provider/TimeEntity.swift @@ -0,0 +1,14 @@ +// +// TimeEntity.swift +// iOS-NOTTODO +// +// Created by 강윤서 on 5/11/24. +// + +import WidgetKit + +struct SimpleEntry: TimelineEntry { + var date: Date = .now + var todayMission: [DailyMissionResponseDTO] + let quote: String +} diff --git a/iOS-NOTTODO/Widget-NOTTODO/View/MediumFamily.swift b/iOS-NOTTODO/Widget-NOTTODO/View/MediumFamily.swift index c13cccb..3d6dea6 100644 --- a/iOS-NOTTODO/Widget-NOTTODO/View/MediumFamily.swift +++ b/iOS-NOTTODO/Widget-NOTTODO/View/MediumFamily.swift @@ -13,7 +13,7 @@ struct MediumFamily: View { @AppStorage("dayOfWeek", store: UserDefaults.shared) var dayOfWeek: String = "" var body: some View { - let progressPercent = Double(entry.lastThreeTask.filter { $0.completionStatus == .CHECKED }.count) / Double(entry.lastThreeTask.count) + let progressPercent = Double(entry.todayMission.filter { $0.completionStatus == .CHECKED }.count) / Double(entry.todayMission.count) HStack { VStack { ZStack { @@ -28,19 +28,20 @@ struct MediumFamily: View { .padding(.leading, 17) VStack { - Text("성공한상위십퍼센트는하하글자수가과연어디까지일까요하하하먼저하지말아야할어쩌구저쩌구") + Text(entry.quote) .foregroundStyle(.gray3) .font(.custom("Pretendard", size: 10)) .fontWeight(.regular) .lineLimit(2) .padding(.horizontal, 12) .padding(.top, 18) + .frame(maxWidth: .infinity, maxHeight: 51, alignment: .leading) HorizontalDivider(color: .gray5) .padding(.top, 6) VStack(spacing: 9) { - if entry.lastThreeTask.isEmpty { + if entry.todayMission.isEmpty { Button(action: { print("앱으로 이동") }, label: { @@ -50,7 +51,7 @@ struct MediumFamily: View { .buttonStyle(.plain) .position(x: 10, y: 9) } else { - ForEach(entry.lastThreeTask) { task in + ForEach(entry.todayMission) { task in HStack { Button(intent: ToggleButtonIntent(id: task.id)) { Image(task.completionStatus == .CHECKED ? .btnMediumFill : .btnMedium) @@ -82,5 +83,5 @@ struct MediumFamily: View { #Preview(as: .systemMedium) { Widget_NOTTODO() } timeline: { - SimpleEntry(lastThreeTask: []) + SimpleEntry(todayMission: [], quote: "") } diff --git a/iOS-NOTTODO/Widget-NOTTODO/View/SmallFamily.swift b/iOS-NOTTODO/Widget-NOTTODO/View/SmallFamily.swift index 15d70df..8bb6127 100644 --- a/iOS-NOTTODO/Widget-NOTTODO/View/SmallFamily.swift +++ b/iOS-NOTTODO/Widget-NOTTODO/View/SmallFamily.swift @@ -13,7 +13,7 @@ struct SmallFamily: View { @AppStorage("dayOfWeek", store: UserDefaults.shared) var dayOfWeek: String = "" var body: some View { - let progressPercent = Double(entry.lastThreeTask.filter { $0.completionStatus == .CHECKED }.count) / Double(entry.lastThreeTask.count) + let progressPercent = Double(entry.todayMission.filter { $0.completionStatus == .CHECKED }.count) / Double(entry.todayMission.count) VStack { HStack { @@ -28,11 +28,12 @@ struct SmallFamily: View { CircularProgressBarView(percent: progressPercent, size: 27, lineWidth: 3) } - Text("성공하지않는거엊이ㅏ러미아러어쩌구요명어니아러나어ㅏ아아아") + Text(entry.quote) .foregroundStyle(.white) .font(.custom("Pretendard", size: 7)) .fontWeight(.regular) .lineLimit(2) + .frame(maxWidth: .infinity, alignment: .leading) Spacer() } @@ -40,7 +41,7 @@ struct SmallFamily: View { .background(.ntdBlack) VStack(spacing: 12) { - if entry.lastThreeTask.isEmpty { + if entry.todayMission.isEmpty { Button(action: { print("앱으로 이동") }, label: { @@ -50,7 +51,7 @@ struct SmallFamily: View { .buttonStyle(.plain) .position(x: 17, y: 12) } else { - ForEach(entry.lastThreeTask) { task in + ForEach(entry.todayMission) { task in HStack { Button(intent: ToggleButtonIntent(id: task.id)) { Image(task.completionStatus == .CHECKED ? .btnSmallBoxFill : .btnSmallBox) diff --git a/iOS-NOTTODO/Widget-NOTTODO/Widget_NOTTODO.swift b/iOS-NOTTODO/Widget-NOTTODO/Widget_NOTTODO.swift index 04b77d2..c712149 100644 --- a/iOS-NOTTODO/Widget-NOTTODO/Widget_NOTTODO.swift +++ b/iOS-NOTTODO/Widget-NOTTODO/Widget_NOTTODO.swift @@ -8,58 +8,24 @@ import WidgetKit import SwiftUI -struct Provider: AppIntentTimelineProvider { - @AppStorage("dailyMission", store: UserDefaults.shared) var sharedData: Data = Data() - func placeholder(in context: Context) -> SimpleEntry { - SimpleEntry(lastThreeTask: []) - } - - func snapshot(for configuration: ConfigurationAppIntent, in context: Context) async -> SimpleEntry { - if let decodedData = try? JSONDecoder().decode([DailyMissionResponseDTO].self, from: sharedData) { - return SimpleEntry(lastThreeTask: decodedData) - } - return SimpleEntry(lastThreeTask: []) - } - - func timeline(for configuration: ConfigurationAppIntent, in context: Context) async -> Timeline { - if let decodedData = try? JSONDecoder().decode([DailyMissionResponseDTO].self, from: sharedData) { - let entries: [SimpleEntry] = [SimpleEntry(lastThreeTask: decodedData)] - - return Timeline(entries: entries, policy: .never) - } - - return Timeline(entries: [], policy: .never) - } -} - -struct SimpleEntry: TimelineEntry { - let date: Date = .now - var lastThreeTask: [DailyMissionResponseDTO] -} - struct Widget_NOTTODOEntryView: View { @Environment(\.widgetFamily) var family: WidgetFamily var entry: Provider.Entry @ViewBuilder var body: some View { - @AppStorage("dailyMission", store: UserDefaults.shared) var sharedData: Data = Data() - - if let decodedData = try? JSONDecoder().decode([DailyMissionResponseDTO].self, from: sharedData) { - - switch self.family { - case .systemSmall: - SmallFamily(entry: SimpleEntry(lastThreeTask: decodedData)) - default: - MediumFamily(entry: SimpleEntry(lastThreeTask: decodedData)) - } + switch self.family { + case .systemSmall: + SmallFamily(entry: entry) + default: + MediumFamily(entry: entry) } } } struct Widget_NOTTODO: Widget { let kind: String = "Widget_NOTTODO" - + var body: some WidgetConfiguration { AppIntentConfiguration(kind: kind, intent: ConfigurationAppIntent.self, provider: Provider()) { entry in Widget_NOTTODOEntryView(entry: entry) @@ -75,5 +41,5 @@ struct Widget_NOTTODO: Widget { #Preview(as: .systemMedium) { Widget_NOTTODO() } timeline: { - SimpleEntry(lastThreeTask: []) + SimpleEntry(todayMission: [], quote: "") }