From 1a1f317c20fcd8baf4b1010885aab9f66c4a67e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=A7=80=ED=98=84?= <102128060+wlgusqkr@users.noreply.github.com> Date: Wed, 8 Oct 2025 14:38:54 +0900 Subject: [PATCH 01/13] =?UTF-8?q?feat:=EA=B5=AC=EB=8F=85=EC=A4=91=EC=9D=B8?= =?UTF-8?q?=20=ED=8E=98=EC=9D=B4=EC=A7=80,=20=EB=A9=94=EC=9D=B8=ED=99=94?= =?UTF-8?q?=EB=A9=B4,=20=EC=B5=9C=EA=B7=BC=20=EC=95=8C=EB=A6=BC=20?= =?UTF-8?q?=EB=94=94=EC=9E=90=EC=9D=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- today-s-sound.xcodeproj/project.pbxproj | 56 +++++- today-s-sound/App/TodaySSoundApp.swift | 2 +- today-s-sound/Core/Network/APIService.swift | 72 ++++++++ today-s-sound/Core/Network/NetworkError.swift | 10 ++ today-s-sound/Core/SpeechService.swift | 26 +++ today-s-sound/Data/Models/Alert.swift | 10 ++ today-s-sound/Data/Models/Subscription.swift | 8 + today-s-sound/Features/Home/HomeView.swift | 25 --- today-s-sound/Layout.png | Bin 0 -> 131979 bytes .../AddSubscription/AddSubscriptionView.swift | 164 ++++++++++++++++++ .../AddSubscriptionViewModel.swift | 10 ++ .../Features/Main}/HomeModel.swift | 0 .../Presentation/Features/Main/HomeView.swift | 109 ++++++++++++ .../Features/Main}/HomeViewModel.swift | 0 .../Presentation/Features/Main/MainView.swift | 34 ++++ .../Features/Main/MainViewModel.swift | 34 ++++ .../NotificationListView.swift | 111 ++++++++++++ .../NotificationListViewModel.swift | 19 ++ .../SubscriptionListView.swift | 136 +++++++++++++++ .../SubscriptionListViewModel.swift | 18 ++ 20 files changed, 816 insertions(+), 28 deletions(-) create mode 100644 today-s-sound/Core/Network/APIService.swift create mode 100644 today-s-sound/Core/Network/NetworkError.swift create mode 100644 today-s-sound/Core/SpeechService.swift create mode 100644 today-s-sound/Data/Models/Alert.swift create mode 100644 today-s-sound/Data/Models/Subscription.swift delete mode 100644 today-s-sound/Features/Home/HomeView.swift create mode 100644 today-s-sound/Layout.png create mode 100644 today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionView.swift create mode 100644 today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionViewModel.swift rename today-s-sound/{Features/Home => Presentation/Features/Main}/HomeModel.swift (100%) create mode 100644 today-s-sound/Presentation/Features/Main/HomeView.swift rename today-s-sound/{Features/Home => Presentation/Features/Main}/HomeViewModel.swift (100%) create mode 100644 today-s-sound/Presentation/Features/Main/MainView.swift create mode 100644 today-s-sound/Presentation/Features/Main/MainViewModel.swift create mode 100644 today-s-sound/Presentation/Features/NotificationList/NotificationListView.swift create mode 100644 today-s-sound/Presentation/Features/NotificationList/NotificationListViewModel.swift create mode 100644 today-s-sound/Presentation/Features/SubscriptionList/SubscriptionListView.swift create mode 100644 today-s-sound/Presentation/Features/SubscriptionList/SubscriptionListViewModel.swift diff --git a/today-s-sound.xcodeproj/project.pbxproj b/today-s-sound.xcodeproj/project.pbxproj index 8c883e2..6664c45 100644 --- a/today-s-sound.xcodeproj/project.pbxproj +++ b/today-s-sound.xcodeproj/project.pbxproj @@ -6,6 +6,13 @@ objectVersion = 77; objects = { +/* Begin PBXBuildFile section */ + 9ADF457E2E950B6100E8B5A2 /* CombineMoya in Frameworks */ = {isa = PBXBuildFile; productRef = 9ADF457D2E950B6100E8B5A2 /* CombineMoya */; }; + 9ADF45802E950B6100E8B5A2 /* Moya in Frameworks */ = {isa = PBXBuildFile; productRef = 9ADF457F2E950B6100E8B5A2 /* Moya */; }; + 9ADF45822E950B6100E8B5A2 /* ReactiveMoya in Frameworks */ = {isa = PBXBuildFile; productRef = 9ADF45812E950B6100E8B5A2 /* ReactiveMoya */; }; + 9ADF45842E950B6100E8B5A2 /* RxMoya in Frameworks */ = {isa = PBXBuildFile; productRef = 9ADF45832E950B6100E8B5A2 /* RxMoya */; }; +/* End PBXBuildFile section */ + /* Begin PBXFileReference section */ 259FC9672E890D7F001152B9 /* today-s-sound.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "today-s-sound.app"; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -36,6 +43,10 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 9ADF45802E950B6100E8B5A2 /* Moya in Frameworks */, + 9ADF457E2E950B6100E8B5A2 /* CombineMoya in Frameworks */, + 9ADF45842E950B6100E8B5A2 /* RxMoya in Frameworks */, + 9ADF45822E950B6100E8B5A2 /* ReactiveMoya in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -78,6 +89,10 @@ ); name = "today-s-sound"; packageProductDependencies = ( + 9ADF457D2E950B6100E8B5A2 /* CombineMoya */, + 9ADF457F2E950B6100E8B5A2 /* Moya */, + 9ADF45812E950B6100E8B5A2 /* ReactiveMoya */, + 9ADF45832E950B6100E8B5A2 /* RxMoya */, ); productName = "today-s-sound"; productReference = 259FC9672E890D7F001152B9 /* today-s-sound.app */; @@ -107,6 +122,9 @@ ); mainGroup = 259FC95E2E890D7E001152B9; minimizedProjectReferenceProxies = 1; + packageReferences = ( + 9ADF457C2E950ADB00E8B5A2 /* XCRemoteSwiftPackageReference "Moya" */, + ); preferredProjectObjectVersion = 77; productRefGroup = 259FC9682E890D7F001152B9 /* Products */; projectDirPath = ""; @@ -265,7 +283,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; ENABLE_PREVIEWS = YES; - GENERATE_INFOPLIST_FILE = NO; + GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = "today-s-sound/Info.plist"; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; @@ -293,7 +311,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; ENABLE_PREVIEWS = YES; - GENERATE_INFOPLIST_FILE = NO; + GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = "today-s-sound/Info.plist"; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; @@ -335,6 +353,40 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + 9ADF457C2E950ADB00E8B5A2 /* XCRemoteSwiftPackageReference "Moya" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/Moya/Moya"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 15.0.3; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 9ADF457D2E950B6100E8B5A2 /* CombineMoya */ = { + isa = XCSwiftPackageProductDependency; + package = 9ADF457C2E950ADB00E8B5A2 /* XCRemoteSwiftPackageReference "Moya" */; + productName = CombineMoya; + }; + 9ADF457F2E950B6100E8B5A2 /* Moya */ = { + isa = XCSwiftPackageProductDependency; + package = 9ADF457C2E950ADB00E8B5A2 /* XCRemoteSwiftPackageReference "Moya" */; + productName = Moya; + }; + 9ADF45812E950B6100E8B5A2 /* ReactiveMoya */ = { + isa = XCSwiftPackageProductDependency; + package = 9ADF457C2E950ADB00E8B5A2 /* XCRemoteSwiftPackageReference "Moya" */; + productName = ReactiveMoya; + }; + 9ADF45832E950B6100E8B5A2 /* RxMoya */ = { + isa = XCSwiftPackageProductDependency; + package = 9ADF457C2E950ADB00E8B5A2 /* XCRemoteSwiftPackageReference "Moya" */; + productName = RxMoya; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = 259FC95F2E890D7E001152B9 /* Project object */; } diff --git a/today-s-sound/App/TodaySSoundApp.swift b/today-s-sound/App/TodaySSoundApp.swift index e3f6917..127aaf5 100644 --- a/today-s-sound/App/TodaySSoundApp.swift +++ b/today-s-sound/App/TodaySSoundApp.swift @@ -11,7 +11,7 @@ import SwiftUI struct TodaySSoundApp: App { var body: some Scene { WindowGroup { - HomeView() + MainView() } } } diff --git a/today-s-sound/Core/Network/APIService.swift b/today-s-sound/Core/Network/APIService.swift new file mode 100644 index 0000000..6530873 --- /dev/null +++ b/today-s-sound/Core/Network/APIService.swift @@ -0,0 +1,72 @@ + +import Foundation +import Combine +import Moya +import CombineMoya + +// Example TargetType - replace with actual API endpoints +enum TodaySoundAPI { + case fetchContent(id: String) +} + +extension TodaySoundAPI: TargetType { + var baseURL: URL { URL(string: "https://your-api-url.com")! } + + var path: String { + switch self { + case .fetchContent(let id): + return "/content/\(id)" + } + } + + var method: Moya.Method { + switch self { + case .fetchContent: + return .get + } + } + + var task: Task { + switch self { + case .fetchContent: + return .requestPlain + } + } + + var headers: [String: String]? { + return ["Content-type": "application/json"] + } +} + +protocol APIServiceType { + func request(_ target: TodaySoundAPI) -> AnyPublisher +} + +class APIService: APIServiceType { + private let provider: MoyaProvider + + init(provider: MoyaProvider = MoyaProvider()) { + self.provider = provider + } + + func request(_ target: TodaySoundAPI) -> AnyPublisher { + return provider.requestPublisher(target) + .tryMap { response -> Data in + guard (200...299).contains(response.statusCode) else { + throw NetworkError.serverError(statusCode: response.statusCode) + } + return response.data + } + .decode(type: T.self, decoder: JSONDecoder()) + .mapError { error -> NetworkError in + if let networkError = error as? NetworkError { + return networkError + } else if error is DecodingError { + return .decodingFailed(error) + } else { + return .requestFailed(error) + } + } + .eraseToAnyPublisher() + } +} diff --git a/today-s-sound/Core/Network/NetworkError.swift b/today-s-sound/Core/Network/NetworkError.swift new file mode 100644 index 0000000..0f41732 --- /dev/null +++ b/today-s-sound/Core/Network/NetworkError.swift @@ -0,0 +1,10 @@ + +import Foundation + +enum NetworkError: Error { + case invalidURL + case requestFailed(Error) + case decodingFailed(Error) + case serverError(statusCode: Int) + case unknown +} diff --git a/today-s-sound/Core/SpeechService.swift b/today-s-sound/Core/SpeechService.swift new file mode 100644 index 0000000..8b99d68 --- /dev/null +++ b/today-s-sound/Core/SpeechService.swift @@ -0,0 +1,26 @@ + +import Foundation +import AVFoundation + +class SpeechService { + static let shared = SpeechService() + private let synthesizer = AVSpeechSynthesizer() + + private init() {} + + func speak(text: String, language: String = "ko-KR") { + let utterance = AVSpeechUtterance(string: text) + utterance.voice = AVSpeechSynthesisVoice(language: language) + + // Stop any speaking in progress before starting a new one + if synthesizer.isSpeaking { + synthesizer.stopSpeaking(at: .immediate) + } + + synthesizer.speak(utterance) + } + + func stop() { + synthesizer.stopSpeaking(at: .immediate) + } +} diff --git a/today-s-sound/Data/Models/Alert.swift b/today-s-sound/Data/Models/Alert.swift new file mode 100644 index 0000000..e055738 --- /dev/null +++ b/today-s-sound/Data/Models/Alert.swift @@ -0,0 +1,10 @@ + +import Foundation + +struct Alert: Codable, Identifiable { + let id: UUID + let title: String + let content: String + let date: Date + let isUrgent: Bool +} diff --git a/today-s-sound/Data/Models/Subscription.swift b/today-s-sound/Data/Models/Subscription.swift new file mode 100644 index 0000000..2d6307e --- /dev/null +++ b/today-s-sound/Data/Models/Subscription.swift @@ -0,0 +1,8 @@ + +import Foundation + +struct Subscription: Codable, Identifiable { + let id: UUID + let name: String + let url: String +} diff --git a/today-s-sound/Features/Home/HomeView.swift b/today-s-sound/Features/Home/HomeView.swift deleted file mode 100644 index 25a2b98..0000000 --- a/today-s-sound/Features/Home/HomeView.swift +++ /dev/null @@ -1,25 +0,0 @@ -// -// HomeView.swift -// today-s-sound -// -// Created by 하승연 on 9/28/25. -// - -import SwiftUI - -struct HomeView: View { - var body: some View { - VStack { - Group { - Text("오늘의 소리") - .font(.KoddiBold56) - .shadow(color: .black.opacity(0.25), radius: 2, x: 0, y: 4) - } - .foregroundStyle(Color.black) - } - } -} - -#Preview { - HomeView() -} diff --git a/today-s-sound/Layout.png b/today-s-sound/Layout.png new file mode 100644 index 0000000000000000000000000000000000000000..054c3d38fda06e472fb46c46687a1c03e8e43bdb GIT binary patch literal 131979 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⋙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 literal 0 HcmV?d00001 diff --git a/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionView.swift b/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionView.swift new file mode 100644 index 0000000..dc8fd3f --- /dev/null +++ b/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionView.swift @@ -0,0 +1,164 @@ + +import SwiftUI + +struct AddSubscriptionView: View { + @StateObject private var viewModel = AddSubscriptionViewModel() + @Environment(\.colorScheme) var colorScheme + + var body: some View { + NavigationView { + ZStack { + (colorScheme == .dark ? Color.black : Color(white: 0.95)) + .ignoresSafeArea() + + VStack(spacing: 0) { + // 상단 바 + HStack { + Button(action: {}) { + Image(systemName: "bell") + .font(.title2) + .foregroundColor(.green) + } + Spacer() + Button(action: {}) { + Image(systemName: "line.3.horizontal") + .font(.title2) + .foregroundColor(colorScheme == .dark ? .white : .black) + } + } + .padding(.horizontal, 24) + .padding(.vertical, 16) + + // 타이틀 + Text("새 웹페이지 추가") + .font(.system(size: 28, weight: .bold)) + .foregroundColor(colorScheme == .dark ? .white : .black) + .frame(maxWidth: .infinity, alignment: .leading) + .padding(.horizontal, 24) + .padding(.bottom, 16) + + ScrollView { + VStack(spacing: 24) { + // URL 입력 섹션 + VStack(alignment: .leading, spacing: 12) { + Text("웹사이트 URL") + .font(.system(size: 16, weight: .semibold)) + .foregroundColor(colorScheme == .dark ? .white : .black) + + TextField("https://www.example.com", text: $viewModel.urlText) + .padding() + .background( + RoundedRectangle(cornerRadius: 12) + .fill(colorScheme == .dark ? Color(white: 0.15) : Color.white) + ) + .foregroundColor(colorScheme == .dark ? .white : .black) + + Text("모니터링 할 웹페이지 URL을 입력하세요.") + .font(.system(size: 13)) + .foregroundColor(colorScheme == .dark ? .white.opacity(0.6) : .black.opacity(0.6)) + } + + // 웹페이지 별명 섹션 + VStack(alignment: .leading, spacing: 12) { + Text("웹페이지 별명") + .font(.system(size: 16, weight: .semibold)) + .foregroundColor(colorScheme == .dark ? .white : .black) + + TextField("동국대학교 공지사항", text: $viewModel.nameText) + .padding() + .background( + RoundedRectangle(cornerRadius: 12) + .fill(colorScheme == .dark ? Color(white: 0.15) : Color.white) + ) + .foregroundColor(colorScheme == .dark ? .white : .black) + + Text("웹 페이지를 식별할 명칭을 입력하세요.") + .font(.system(size: 13)) + .foregroundColor(colorScheme == .dark ? .white.opacity(0.6) : .black.opacity(0.6)) + } + + // 키워드 벡터 섹션 + VStack(alignment: .leading, spacing: 12) { + Text("키워드 벡터") + .font(.system(size: 16, weight: .semibold)) + .foregroundColor(colorScheme == .dark ? .white : .black) + + TextField("장학금, 교직, 학생회", text: $viewModel.keywordsText) + .padding() + .background( + RoundedRectangle(cornerRadius: 12) + .fill(colorScheme == .dark ? Color(white: 0.15) : Color.white) + ) + .foregroundColor(colorScheme == .dark ? .white : .black) + + HStack(spacing: 8) { + KeywordBadge(text: "장학금", colorScheme: colorScheme) + KeywordBadge(text: "교직부공지사항", colorScheme: colorScheme) + } + + Text("관심 키워드가 포함된 내용을 걸러낼 필요가 있으면 입력하세요.") + .font(.system(size: 13)) + .foregroundColor(colorScheme == .dark ? .white.opacity(0.6) : .black.opacity(0.6)) + } + + // 긴급 알림으로 설정 토글 + HStack { + Text("긴급 알림으로 설정") + .font(.system(size: 16, weight: .semibold)) + .foregroundColor(colorScheme == .dark ? .white : .black) + Spacer() + Toggle("", isOn: $viewModel.isUrgent) + .labelsHidden() + } + .padding() + .background( + RoundedRectangle(cornerRadius: 12) + .fill(colorScheme == .dark ? Color(white: 0.15) : Color.white) + ) + + // 하단 버튼 + Button(action: {}) { + Text("등록 승인 요청") + .font(.system(size: 16, weight: .semibold)) + .foregroundColor(.white) + .frame(maxWidth: .infinity) + .padding(.vertical, 16) + .background( + RoundedRectangle(cornerRadius: 12) + .fill(Color.green.opacity(0.9)) + ) + } + } + .padding(.horizontal, 16) + .padding(.top, 8) + .padding(.bottom, 16) + } + } + } + .navigationBarHidden(true) + } + } +} + +struct KeywordBadge: View { + let text: String + let colorScheme: ColorScheme + + var body: some View { + Text(text) + .font(.system(size: 12, weight: .medium)) + .foregroundColor(colorScheme == .dark ? .white : .black) + .padding(.horizontal, 12) + .padding(.vertical, 6) + .background( + RoundedRectangle(cornerRadius: 8) + .fill(Color.green.opacity(0.2)) + ) + } +} + +struct AddSubscriptionView_Previews: PreviewProvider { + static var previews: some View { + AddSubscriptionView() + } +} diff --git a/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionViewModel.swift b/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionViewModel.swift new file mode 100644 index 0000000..62e1124 --- /dev/null +++ b/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionViewModel.swift @@ -0,0 +1,10 @@ + +import Foundation +import Combine + +class AddSubscriptionViewModel: ObservableObject { + @Published var urlText: String = "" + @Published var nameText: String = "" + @Published var keywordsText: String = "" + @Published var isUrgent: Bool = false +} diff --git a/today-s-sound/Features/Home/HomeModel.swift b/today-s-sound/Presentation/Features/Main/HomeModel.swift similarity index 100% rename from today-s-sound/Features/Home/HomeModel.swift rename to today-s-sound/Presentation/Features/Main/HomeModel.swift diff --git a/today-s-sound/Presentation/Features/Main/HomeView.swift b/today-s-sound/Presentation/Features/Main/HomeView.swift new file mode 100644 index 0000000..998ef6e --- /dev/null +++ b/today-s-sound/Presentation/Features/Main/HomeView.swift @@ -0,0 +1,109 @@ +// +// HomeView.swift +// today-s-sound +// +// Created by 하승연 on 9/28/25. +// + +import SwiftUI + +struct HomeView: View { + @StateObject private var viewModel = MainViewModel() + @Environment(\.colorScheme) var colorScheme + + var body: some View { + ZStack { + // 다크모드에 따라 배경색 변경 + (colorScheme == .dark ? Color.black : Color.white) + .ignoresSafeArea() + + VStack(spacing: 0) { +// HStack { +// Button(action: {}) { +// Image(systemName: "bell") +// .font(.system(size: 48, weight: .medium)) +// .foregroundColor(colorScheme == .dark ? .white : Color.green.opacity(0.9)) +// } +// Spacer() +// Button(action: {}) { +// Image(systemName: "line.3.horizontal") +// .font(.system(size: 48, weight: .medium)) +// .foregroundColor(colorScheme == .dark ? .white : Color.green.opacity(0.9)) +// } +// } +// .padding(.horizontal, 24) +// .padding(.top, 16) +// +// Spacer() + Spacer() + + // 오늘의 소리 타이틀 + Text("오늘의 소리") + .font(.KoddiBold56) + .foregroundStyle(colorScheme == .dark ? Color.white : Color.black) + .shadow(color: .black.opacity(0.25), radius: 2, x: 0, y: 4) + .padding(.bottom, 60) + + Button(action: { + if let first = viewModel.recentAlerts.first { + viewModel.playAlert(first) + } + }) { + Image(systemName: "play.fill") + .resizable() + .scaledToFit() + .frame(width: 120, height: 120) + .foregroundColor(Color.green.opacity(0.9)) + .padding(40) + } + .padding(.bottom, 60) + + // 속도 조절 + HStack(spacing: 48) { + Button(action: { viewModel.decreaseRate() }) { + Image(systemName: "minus") + .font(.system(size: 35, weight: .medium)) + .foregroundColor(colorScheme == .dark ? .white : Color.green.opacity(0.9)) + } + + Text(String(format: "%.1f x", viewModel.playbackRate)) + .font(.system(size: 48, weight: .bold)) + .foregroundColor(colorScheme == .dark ? .white : .black) + .monospacedDigit() + .frame(minWidth: 100) + + Button(action: { viewModel.increaseRate() }) { + Image(systemName: "plus") + .font(.system(size: 35, weight: .medium)) + .foregroundColor(colorScheme == .dark ? .white : Color.green.opacity(0.9)) + } + } + + Spacer() + + VStack(spacing: 16) { + Text("현재 카테고리") + .font(.system(size: 28)) + .foregroundColor(colorScheme == .dark ? .white.opacity(0.6) : .black.opacity(0.6)) + + Text(viewModel.currentCategoryName) + .font(.system(size: 32, weight: .semibold)) + .foregroundColor(colorScheme == .dark ? .black : .white) + .padding(.horizontal, 24) + .padding(.vertical, 12) + .frame(width: 340, height: 85) + .background( + RoundedRectangle(cornerRadius: 16) + .fill(Color.green.opacity(0.9)) + ) + .foregroundColor(.white) + } + .padding(.bottom, 32) + } + } + } +} + +#Preview { + HomeView() +} diff --git a/today-s-sound/Features/Home/HomeViewModel.swift b/today-s-sound/Presentation/Features/Main/HomeViewModel.swift similarity index 100% rename from today-s-sound/Features/Home/HomeViewModel.swift rename to today-s-sound/Presentation/Features/Main/HomeViewModel.swift diff --git a/today-s-sound/Presentation/Features/Main/MainView.swift b/today-s-sound/Presentation/Features/Main/MainView.swift new file mode 100644 index 0000000..ada8a85 --- /dev/null +++ b/today-s-sound/Presentation/Features/Main/MainView.swift @@ -0,0 +1,34 @@ + +import SwiftUI + +struct MainView: View { + @StateObject private var viewModel = MainViewModel() + + var body: some View { + TabView { + HomeView() + .tabItem { + Image(systemName: "house.fill") + Text("메인") + } + + NotificationListView() + .tabItem { + Image(systemName: "bell.fill") + Text("알림") + } + + SubscriptionListView() + .tabItem { + Image(systemName: "bookmark.fill") + Text("구독") + } + } + } +} + +struct MainView_Previews: PreviewProvider { + static var previews: some View { + MainView() + } +} diff --git a/today-s-sound/Presentation/Features/Main/MainViewModel.swift b/today-s-sound/Presentation/Features/Main/MainViewModel.swift new file mode 100644 index 0000000..9959781 --- /dev/null +++ b/today-s-sound/Presentation/Features/Main/MainViewModel.swift @@ -0,0 +1,34 @@ + +import Foundation +import Combine + +class MainViewModel: ObservableObject { + @Published var playbackRate: Double = 1.0 + @Published var currentCategoryName: String = "동국대학교 공지사항" + @Published var recentAlerts: [Alert] = [] + + private var cancellables = Set() + + init() { + loadMockAlerts() + } + + func increaseRate() { + playbackRate = min(2.0, (playbackRate * 10 + 1).rounded() / 10) + } + + func decreaseRate() { + playbackRate = max(0.5, (playbackRate * 10 - 1).rounded() / 10) + } + + func playAlert(_ alert: Alert) { + SpeechService.shared.speak(text: alert.title) + } + + private func loadMockAlerts() { + recentAlerts = [ + Alert(id: UUID(), title: "일이삼사오육칠팔", content: "공지 내용 예시", date: Date().addingTimeInterval(-7200), isUrgent: true), + Alert(id: UUID(), title: "잡코리아 채용 공고", content: "채용 소식", date: Date().addingTimeInterval(-10800), isUrgent: false) + ] + } +} diff --git a/today-s-sound/Presentation/Features/NotificationList/NotificationListView.swift b/today-s-sound/Presentation/Features/NotificationList/NotificationListView.swift new file mode 100644 index 0000000..2d45333 --- /dev/null +++ b/today-s-sound/Presentation/Features/NotificationList/NotificationListView.swift @@ -0,0 +1,111 @@ + +import SwiftUI + +struct NotificationListView: View { + @StateObject private var viewModel = NotificationListViewModel() + @Environment(\.colorScheme) var colorScheme + + var body: some View { + NavigationView { + ZStack { + (colorScheme == .dark ? Color.black : Color(white: 0.95)) + .ignoresSafeArea() + + VStack(spacing: 0) { + Spacer() + // 타이틀 + Text("최근 알림") + .font(.system(size: 28, weight: .bold)) + .foregroundColor(colorScheme == .dark ? .white : .black) + .frame(maxWidth: .infinity, alignment: .leading) + .padding(.horizontal, 24) + .padding(.bottom, 16) + + ScrollView { + VStack(spacing: 16) { + ForEach(viewModel.alerts) { alert in + AlertCardView(alert: alert, colorScheme: colorScheme) + } + } + .padding(.horizontal, 16) + .padding(.top, 8) + } + } + } + .navigationBarHidden(true) + } + } +} + +struct AlertCardView: View { + let alert: Alert + let colorScheme: ColorScheme + let customPink = Color(red: 1.0, green: 0.298, blue: 0.729, opacity: 1.0) + let customGreen = Color(red: 0 / 255, green: 223 / 255, blue: 119 / 255) + + private var cardColor: Color { + alert.isUrgent ? customPink : customGreen + } + + private var buttonBackgroundColor: Color { + colorScheme == .dark ? .black : .white + } + + var body: some View { + + VStack(spacing: 20) { + // 상단: 타이틀과 아이콘 + HStack(alignment: .top, spacing: 12) { + Image(systemName: alert.isUrgent ? "bell.fill" : "doc.fill") + .font(.system(size: 24)) + .foregroundColor(.white) + + VStack(alignment: .leading, spacing: 8) { + Text(alert.title) + .font(.system(size: 20, weight: .bold)) + .foregroundColor(.white) + .multilineTextAlignment(.leading) + + Text("2시간 전") + .font(.system(size: 16)) + .foregroundColor(.white.opacity(0.9)) + } + + Spacer() + } + + // 하단: 음성으로 듣기 버튼 + Button(action: { + SpeechService.shared.speak(text: alert.title) + }) { + HStack(spacing: 8) { + Image(systemName: "speaker.wave.2.fill") + .font(.system(size: 18)) + .foregroundStyle(colorScheme == .dark ? .white : .black) + Text("음성으로 듣기") + .font(.system(size: 18, weight: .semibold)) + .foregroundColor(colorScheme == .dark ? .white : .black) + } + .foregroundColor(colorScheme == .dark ? .black : .white) + .frame(maxWidth: .infinity) + .padding(.vertical, 14) + .background( + RoundedRectangle(cornerRadius: 12) + .fill(buttonBackgroundColor) + ) + } + } + .padding(24) + .background( + RoundedRectangle(cornerRadius: 16) + .fill(cardColor) + .shadow(color: .black.opacity(0.15), radius: 8, x: 0, y: 4) + ) + } +} + +struct NotificationListView_Previews: PreviewProvider { + static var previews: some View { + NotificationListView() + } +} diff --git a/today-s-sound/Presentation/Features/NotificationList/NotificationListViewModel.swift b/today-s-sound/Presentation/Features/NotificationList/NotificationListViewModel.swift new file mode 100644 index 0000000..197947c --- /dev/null +++ b/today-s-sound/Presentation/Features/NotificationList/NotificationListViewModel.swift @@ -0,0 +1,19 @@ + +import Foundation +import Combine + +class NotificationListViewModel: ObservableObject { + @Published var alerts: [Alert] = [] + + init() { + loadMock() + } + + private func loadMock() { + alerts = [ + Alert(id: UUID(), title: "일이삼사오육칠팔", content: "본문 예시", date: Date().addingTimeInterval(-7200), isUrgent: true), + Alert(id: UUID(), title: "잡코리아 채용 공고", content: "본문 예시 2", date: Date().addingTimeInterval(-10800), isUrgent: false), + Alert(id: UUID(), title: "동국대 도서관 휴관 안내", content: "본문 예시 3", date: Date().addingTimeInterval(-14400), isUrgent: true) + ] + } +} diff --git a/today-s-sound/Presentation/Features/SubscriptionList/SubscriptionListView.swift b/today-s-sound/Presentation/Features/SubscriptionList/SubscriptionListView.swift new file mode 100644 index 0000000..fa2901a --- /dev/null +++ b/today-s-sound/Presentation/Features/SubscriptionList/SubscriptionListView.swift @@ -0,0 +1,136 @@ + +import SwiftUI + + +struct SubscriptionListView: View { + @StateObject private var viewModel = SubscriptionListViewModel() + @Environment(\.colorScheme) var colorScheme + let customGreen = Color(red: 0 / 255, green: 223 / 255, blue: 119 / 255) + var body: some View { + NavigationView { + ZStack { + (colorScheme == .dark ? Color.black : .white) + .ignoresSafeArea() + + VStack(alignment: .leading, spacing: 12) { + + Spacer() + // 타이틀 + Text("구독 설정") + .font(.system(size: 31, weight: .bold)) + .foregroundColor(colorScheme == .dark ? .white : .black) + .frame(maxWidth: .infinity, alignment: .leading) + .padding(.horizontal, 24) + .padding(.bottom, 16) + + Text("구독 중인 페이지") + .font(.system(size:28, weight: .bold)) + .foregroundStyle(customGreen) + .padding(.horizontal, 24) + + // 구독 목록 + ScrollView { + VStack(spacing: 12) { + ForEach(viewModel.subscriptions) { subscription in + SubscriptionCardView(subscription: subscription, colorScheme: colorScheme) + } + } + .padding(.horizontal, 16) + .padding(.top, 8) + } + + // 하단 버튼 + VStack(spacing: 12) { + Button(action: {}) { + HStack { + Image(systemName: "plus.circle.fill") + .font(.system(size: 18)) + Text("새로운 웹페이지 추가") + .font(.system(size: 24, weight: .semibold)) + } + .foregroundColor(.white) + .frame(maxWidth: .infinity) + .padding(.vertical, 16) + .background( + RoundedRectangle(cornerRadius: 12) + .fill(Color.green.opacity(0.9)) + ) + } + + } + .padding(.horizontal, 16) + .padding(.bottom, 16) + } + } + .navigationBarHidden(true) + } + } +} + +struct SubscriptionCardView: View { + let subscription: Subscription + let colorScheme: ColorScheme + + let cardGreyColor = Color(red: 245 / 255, green: 245 / 255, blue: 245 / 255) + + + var body: some View { + HStack(spacing: 12) { + VStack(alignment: .leading, spacing: 8) { + Text(subscription.name) + .font(.system(size: 20, weight: .semibold)) + .foregroundColor(colorScheme == .dark ? .white : .black) + + Text(subscription.url) + .font(.system(size: 13)) + .foregroundColor(colorScheme == .dark ? .white.opacity(0.8) : .black.opacity(0.6)) + .lineLimit(1) + + HStack(spacing: 8) { + StatusBadge(text: "등록중", colorScheme: colorScheme) + StatusBadge(text: "일이삼사", colorScheme: colorScheme) + } + } + + Spacer() + + Button(action: {}) { + Image(systemName: "bell") + .font(.system(size: 40)) + .foregroundColor(.green) + } + } + .padding(16) + .background( + RoundedRectangle(cornerRadius: 12) + .fill(colorScheme == .dark ? Color(white: 0.15) : cardGreyColor) + .shadow(color: .black.opacity(0.05), radius: 4, x: 0, y: 2) + ) + } +} + +struct StatusBadge: View { + let text: String + let colorScheme: ColorScheme + + let fontgreenColor = Color(red: 0 / 255, green: 223 / 255, blue: 119 / 255) + let badgeBackgroundColor = Color(red: 52 / 255, green: 199 / 255, blue: 89 / 255, opacity: 0.16) + + var body: some View { + Text(text) + .font(.system(size: 14, weight: .medium)) + .foregroundColor(colorScheme == .dark ? .white :fontgreenColor) + .padding(.horizontal, 8) + .padding(.vertical, 4) + .background( + RoundedRectangle(cornerRadius: 20) + .fill(badgeBackgroundColor) + ) + } +} + +struct SubscriptionListView_Previews: PreviewProvider { + static var previews: some View { + SubscriptionListView() + } +} diff --git a/today-s-sound/Presentation/Features/SubscriptionList/SubscriptionListViewModel.swift b/today-s-sound/Presentation/Features/SubscriptionList/SubscriptionListViewModel.swift new file mode 100644 index 0000000..daa2b11 --- /dev/null +++ b/today-s-sound/Presentation/Features/SubscriptionList/SubscriptionListViewModel.swift @@ -0,0 +1,18 @@ + +import Foundation +import Combine + +class SubscriptionListViewModel: ObservableObject { + @Published var subscriptions: [Subscription] = [] + + init() { + loadMock() + } + + private func loadMock() { + subscriptions = [ + Subscription(id: UUID(), name: "동국대학교 공지사항", url: "https://www.dongguk.edu"), + Subscription(id: UUID(), name: "네이버 연합뉴스 속보", url: "https://news.naver.com") + ] + } +} From 9d04f972a5af1b1f5c8a236b44636074a5cb20ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=A7=80=ED=98=84?= <102128060+wlgusqkr@users.noreply.github.com> Date: Wed, 8 Oct 2025 15:35:00 +0900 Subject: [PATCH 02/13] =?UTF-8?q?feat:=20=EC=83=88=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20=EC=B6=94=EA=B0=80=20=EB=A0=88=EC=9D=B4=EC=95=84?= =?UTF-8?q?=EC=9B=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AddSubscription/AddSubscriptionView.swift | 52 +++++++++++-------- .../SubscriptionListView.swift | 8 ++- 2 files changed, 38 insertions(+), 22 deletions(-) diff --git a/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionView.swift b/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionView.swift index dc8fd3f..bdefba3 100644 --- a/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionView.swift +++ b/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionView.swift @@ -4,27 +4,26 @@ import SwiftUI struct AddSubscriptionView: View { @StateObject private var viewModel = AddSubscriptionViewModel() @Environment(\.colorScheme) var colorScheme + @Environment(\.dismiss) var dismiss + let customGreen = Color(red: 0 / 255, green: 223 / 255, blue: 119 / 255) + var body: some View { - NavigationView { - ZStack { - (colorScheme == .dark ? Color.black : Color(white: 0.95)) + ZStack { + (colorScheme == .dark ? Color.black : .white) .ignoresSafeArea() VStack(spacing: 0) { // 상단 바 HStack { - Button(action: {}) { - Image(systemName: "bell") - .font(.title2) - .foregroundColor(.green) - } - Spacer() - Button(action: {}) { - Image(systemName: "line.3.horizontal") + Button(action: { + dismiss() + }) { + Image(systemName: "xmark") .font(.title2) .foregroundColor(colorScheme == .dark ? .white : .black) } + Spacer() } .padding(.horizontal, 24) .padding(.vertical, 16) @@ -32,11 +31,12 @@ struct AddSubscriptionView: View { // 타이틀 Text("새 웹페이지 추가") .font(.system(size: 28, weight: .bold)) - .foregroundColor(colorScheme == .dark ? .white : .black) + .foregroundColor(colorScheme == .dark ? .white : customGreen) .frame(maxWidth: .infinity, alignment: .leading) .padding(.horizontal, 24) .padding(.bottom, 16) + ScrollView { VStack(spacing: 24) { // URL 입력 섹션 @@ -44,14 +44,20 @@ struct AddSubscriptionView: View { Text("웹사이트 URL") .font(.system(size: 16, weight: .semibold)) .foregroundColor(colorScheme == .dark ? .white : .black) + .background( + RoundedRectangle(cornerRadius: 12) + .fill(colorScheme == .dark ? Color(white: 0.15) : Color(white : 0.95)) + ) TextField("https://www.example.com", text: $viewModel.urlText) .padding() .background( RoundedRectangle(cornerRadius: 12) - .fill(colorScheme == .dark ? Color(white: 0.15) : Color.white) + .fill(colorScheme == .dark ? Color(white: 0.15) : Color(white: 0.95)) + .stroke(colorScheme == .dark ? Color.white.opacity(0.2) : Color.gray.opacity(0.3), lineWidth: 1) ) .foregroundColor(colorScheme == .dark ? .white : .black) + .accentColor(colorScheme == .dark ? .white : .black) Text("모니터링 할 웹페이지 URL을 입력하세요.") .font(.system(size: 13)) @@ -68,18 +74,20 @@ struct AddSubscriptionView: View { .padding() .background( RoundedRectangle(cornerRadius: 12) - .fill(colorScheme == .dark ? Color(white: 0.15) : Color.white) + .fill(colorScheme == .dark ? Color(white: 0.15) : Color(white: 0.95)) + .stroke(colorScheme == .dark ? Color.white.opacity(0.2) : Color.gray.opacity(0.3), lineWidth: 1) ) .foregroundColor(colorScheme == .dark ? .white : .black) + .accentColor(colorScheme == .dark ? .white : .black) Text("웹 페이지를 식별할 명칭을 입력하세요.") .font(.system(size: 13)) .foregroundColor(colorScheme == .dark ? .white.opacity(0.6) : .black.opacity(0.6)) } - // 키워드 벡터 섹션 + // 키워드 필터 섹션 VStack(alignment: .leading, spacing: 12) { - Text("키워드 벡터") + Text("키워드 필터") .font(.system(size: 16, weight: .semibold)) .foregroundColor(colorScheme == .dark ? .white : .black) @@ -87,10 +95,11 @@ struct AddSubscriptionView: View { .padding() .background( RoundedRectangle(cornerRadius: 12) - .fill(colorScheme == .dark ? Color(white: 0.15) : Color.white) + .fill(colorScheme == .dark ? Color(white: 0.15) : Color(white: 0.95)) + .stroke(colorScheme == .dark ? Color.white.opacity(0.2) : Color.gray.opacity(0.3), lineWidth: 1) ) .foregroundColor(colorScheme == .dark ? .white : .black) - + .accentColor(colorScheme == .dark ? .white : .black) HStack(spacing: 8) { KeywordBadge(text: "장학금", colorScheme: colorScheme) KeywordBadge(text: "교직부공지사항", colorScheme: colorScheme) @@ -117,7 +126,10 @@ struct AddSubscriptionView: View { ) // 하단 버튼 - Button(action: {}) { + Button(action: { + // TODO: 등록 로직 추가 + dismiss() + }) { Text("등록 승인 요청") .font(.system(size: 16, weight: .semibold)) .foregroundColor(.white) @@ -135,8 +147,6 @@ struct AddSubscriptionView: View { } } } - .navigationBarHidden(true) - } } } diff --git a/today-s-sound/Presentation/Features/SubscriptionList/SubscriptionListView.swift b/today-s-sound/Presentation/Features/SubscriptionList/SubscriptionListView.swift index fa2901a..9a1d7c4 100644 --- a/today-s-sound/Presentation/Features/SubscriptionList/SubscriptionListView.swift +++ b/today-s-sound/Presentation/Features/SubscriptionList/SubscriptionListView.swift @@ -5,6 +5,7 @@ import SwiftUI struct SubscriptionListView: View { @StateObject private var viewModel = SubscriptionListViewModel() @Environment(\.colorScheme) var colorScheme + @State private var showAddSubscription = false let customGreen = Color(red: 0 / 255, green: 223 / 255, blue: 119 / 255) var body: some View { NavigationView { @@ -41,7 +42,9 @@ struct SubscriptionListView: View { // 하단 버튼 VStack(spacing: 12) { - Button(action: {}) { + Button(action: { + showAddSubscription = true + }) { HStack { Image(systemName: "plus.circle.fill") .font(.system(size: 18)) @@ -64,6 +67,9 @@ struct SubscriptionListView: View { } .navigationBarHidden(true) } + .sheet(isPresented: $showAddSubscription) { + AddSubscriptionView() + } } } From e08048692389175535f065e53cc1b547ddd06e7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=A7=80=ED=98=84?= <102128060+wlgusqkr@users.noreply.github.com> Date: Wed, 8 Oct 2025 16:09:21 +0900 Subject: [PATCH 03/13] =?UTF-8?q?feat:=20=EC=83=89=EC=83=81=20=ED=86=B5?= =?UTF-8?q?=ED=95=A9=20=EA=B4=80=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- today-s-sound/Info.plist | 6 +- .../AddSubscription/AddSubscriptionView.swift | 54 ++++++-------- .../Presentation/Features/Main/HomeView.swift | 24 +++--- .../NotificationListView.swift | 18 ++--- .../SubscriptionListView.swift | 24 +++--- today-s-sound/Resources/Colors.swift | 74 +++++++++++++++++++ 6 files changed, 130 insertions(+), 70 deletions(-) create mode 100644 today-s-sound/Resources/Colors.swift diff --git a/today-s-sound/Info.plist b/today-s-sound/Info.plist index 8748d7a..2155055 100644 --- a/today-s-sound/Info.plist +++ b/today-s-sound/Info.plist @@ -4,9 +4,9 @@ UIAppFonts - KoddiUDOnGothic-ExtraBold - KoddiUDOnGothic-Regular - KoddiUDOnGothic-Bold + KoddiUDOnGothic-ExtraBold.otf + KoddiUDOnGothic-Regular.otf + KoddiUDOnGothic-Bold.otf diff --git a/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionView.swift b/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionView.swift index bdefba3..72b1e6b 100644 --- a/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionView.swift +++ b/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionView.swift @@ -6,11 +6,10 @@ struct AddSubscriptionView: View { @Environment(\.colorScheme) var colorScheme @Environment(\.dismiss) var dismiss - let customGreen = Color(red: 0 / 255, green: 223 / 255, blue: 119 / 255) var body: some View { ZStack { - (colorScheme == .dark ? Color.black : .white) + Color.background(colorScheme) .ignoresSafeArea() VStack(spacing: 0) { @@ -21,7 +20,7 @@ struct AddSubscriptionView: View { }) { Image(systemName: "xmark") .font(.title2) - .foregroundColor(colorScheme == .dark ? .white : .black) + .foregroundColor(Color.text(colorScheme)) } Spacer() } @@ -31,7 +30,7 @@ struct AddSubscriptionView: View { // 타이틀 Text("새 웹페이지 추가") .font(.system(size: 28, weight: .bold)) - .foregroundColor(colorScheme == .dark ? .white : customGreen) + .foregroundColor(colorScheme == .dark ? .white : .primaryGreen) .frame(maxWidth: .infinity, alignment: .leading) .padding(.horizontal, 24) .padding(.bottom, 16) @@ -43,63 +42,60 @@ struct AddSubscriptionView: View { VStack(alignment: .leading, spacing: 12) { Text("웹사이트 URL") .font(.system(size: 16, weight: .semibold)) - .foregroundColor(colorScheme == .dark ? .white : .black) + .foregroundColor(Color.text(colorScheme)) .background( RoundedRectangle(cornerRadius: 12) - .fill(colorScheme == .dark ? Color(white: 0.15) : Color(white : 0.95)) + .fill(Color.secondaryBackground(colorScheme)) ) TextField("https://www.example.com", text: $viewModel.urlText) .padding() .background( RoundedRectangle(cornerRadius: 12) - .fill(colorScheme == .dark ? Color(white: 0.15) : Color(white: 0.95)) - .stroke(colorScheme == .dark ? Color.white.opacity(0.2) : Color.gray.opacity(0.3), lineWidth: 1) + .fill(Color.secondaryBackground(colorScheme)) + .stroke(Color.border(colorScheme), lineWidth: 1) ) - .foregroundColor(colorScheme == .dark ? .white : .black) - .accentColor(colorScheme == .dark ? .white : .black) + .foregroundColor(Color.text(colorScheme)) Text("모니터링 할 웹페이지 URL을 입력하세요.") .font(.system(size: 13)) - .foregroundColor(colorScheme == .dark ? .white.opacity(0.6) : .black.opacity(0.6)) + .foregroundColor(Color.secondaryText(colorScheme)) } // 웹페이지 별명 섹션 VStack(alignment: .leading, spacing: 12) { Text("웹페이지 별명") .font(.system(size: 16, weight: .semibold)) - .foregroundColor(colorScheme == .dark ? .white : .black) + .foregroundColor(Color.text(colorScheme)) TextField("동국대학교 공지사항", text: $viewModel.nameText) .padding() .background( RoundedRectangle(cornerRadius: 12) - .fill(colorScheme == .dark ? Color(white: 0.15) : Color(white: 0.95)) - .stroke(colorScheme == .dark ? Color.white.opacity(0.2) : Color.gray.opacity(0.3), lineWidth: 1) + .fill(Color.secondaryBackground(colorScheme)) + .stroke(Color.border(colorScheme), lineWidth: 1) ) - .foregroundColor(colorScheme == .dark ? .white : .black) - .accentColor(colorScheme == .dark ? .white : .black) + .foregroundColor(Color.text(colorScheme)) Text("웹 페이지를 식별할 명칭을 입력하세요.") .font(.system(size: 13)) - .foregroundColor(colorScheme == .dark ? .white.opacity(0.6) : .black.opacity(0.6)) + .foregroundColor(Color.secondaryText(colorScheme)) } // 키워드 필터 섹션 VStack(alignment: .leading, spacing: 12) { Text("키워드 필터") .font(.system(size: 16, weight: .semibold)) - .foregroundColor(colorScheme == .dark ? .white : .black) + .foregroundColor(Color.text(colorScheme)) TextField("장학금, 교직, 학생회", text: $viewModel.keywordsText) .padding() .background( RoundedRectangle(cornerRadius: 12) - .fill(colorScheme == .dark ? Color(white: 0.15) : Color(white: 0.95)) - .stroke(colorScheme == .dark ? Color.white.opacity(0.2) : Color.gray.opacity(0.3), lineWidth: 1) + .fill(Color.secondaryBackground(colorScheme)) + .stroke(Color.border(colorScheme), lineWidth: 1) ) - .foregroundColor(colorScheme == .dark ? .white : .black) - .accentColor(colorScheme == .dark ? .white : .black) + .foregroundColor(Color.text(colorScheme)) HStack(spacing: 8) { KeywordBadge(text: "장학금", colorScheme: colorScheme) KeywordBadge(text: "교직부공지사항", colorScheme: colorScheme) @@ -107,23 +103,19 @@ struct AddSubscriptionView: View { Text("관심 키워드가 포함된 내용을 걸러낼 필요가 있으면 입력하세요.") .font(.system(size: 13)) - .foregroundColor(colorScheme == .dark ? .white.opacity(0.6) : .black.opacity(0.6)) + .foregroundColor(Color.secondaryText(colorScheme)) } // 긴급 알림으로 설정 토글 HStack { Text("긴급 알림으로 설정") .font(.system(size: 16, weight: .semibold)) - .foregroundColor(colorScheme == .dark ? .white : .black) + .foregroundColor(Color.text(colorScheme)) Spacer() Toggle("", isOn: $viewModel.isUrgent) .labelsHidden() } .padding() - .background( - RoundedRectangle(cornerRadius: 12) - .fill(colorScheme == .dark ? Color(white: 0.15) : Color.white) - ) // 하단 버튼 Button(action: { @@ -137,7 +129,7 @@ struct AddSubscriptionView: View { .padding(.vertical, 16) .background( RoundedRectangle(cornerRadius: 12) - .fill(Color.green.opacity(0.9)) + .fill(Color.primaryGreen90) ) } } @@ -157,12 +149,12 @@ struct KeywordBadge: View { var body: some View { Text(text) .font(.system(size: 12, weight: .medium)) - .foregroundColor(colorScheme == .dark ? .white : .black) + .foregroundColor(Color.text(colorScheme)) .padding(.horizontal, 12) .padding(.vertical, 6) .background( RoundedRectangle(cornerRadius: 8) - .fill(Color.green.opacity(0.2)) + .fill(Color.primaryGreen20) ) } } diff --git a/today-s-sound/Presentation/Features/Main/HomeView.swift b/today-s-sound/Presentation/Features/Main/HomeView.swift index 998ef6e..06c411b 100644 --- a/today-s-sound/Presentation/Features/Main/HomeView.swift +++ b/today-s-sound/Presentation/Features/Main/HomeView.swift @@ -14,7 +14,7 @@ struct HomeView: View { var body: some View { ZStack { // 다크모드에 따라 배경색 변경 - (colorScheme == .dark ? Color.black : Color.white) + Color.background(colorScheme) .ignoresSafeArea() VStack(spacing: 0) { @@ -22,13 +22,13 @@ struct HomeView: View { // Button(action: {}) { // Image(systemName: "bell") // .font(.system(size: 48, weight: .medium)) -// .foregroundColor(colorScheme == .dark ? .white : Color.green.opacity(0.9)) +// .foregroundColor(colorScheme == .dark ? .white : Color.primaryGreen90) // } // Spacer() // Button(action: {}) { // Image(systemName: "line.3.horizontal") // .font(.system(size: 48, weight: .medium)) -// .foregroundColor(colorScheme == .dark ? .white : Color.green.opacity(0.9)) +// .foregroundColor(colorScheme == .dark ? .white : Color.primaryGreen90) // } // } // .padding(.horizontal, 24) @@ -40,8 +40,8 @@ struct HomeView: View { // 오늘의 소리 타이틀 Text("오늘의 소리") .font(.KoddiBold56) - .foregroundStyle(colorScheme == .dark ? Color.white : Color.black) - .shadow(color: .black.opacity(0.25), radius: 2, x: 0, y: 4) + .foregroundStyle(Color.text(colorScheme)) + .shadow(color: .black25, radius: 2, x: 0, y: 4) .padding(.bottom, 60) Button(action: { @@ -53,7 +53,7 @@ struct HomeView: View { .resizable() .scaledToFit() .frame(width: 120, height: 120) - .foregroundColor(Color.green.opacity(0.9)) + .foregroundColor(Color.primaryGreen90) .padding(40) } .padding(.bottom, 60) @@ -63,19 +63,19 @@ struct HomeView: View { Button(action: { viewModel.decreaseRate() }) { Image(systemName: "minus") .font(.system(size: 35, weight: .medium)) - .foregroundColor(colorScheme == .dark ? .white : Color.green.opacity(0.9)) + .foregroundColor(colorScheme == .dark ? .white : Color.primaryGreen90) } Text(String(format: "%.1f x", viewModel.playbackRate)) .font(.system(size: 48, weight: .bold)) - .foregroundColor(colorScheme == .dark ? .white : .black) + .foregroundColor(Color.text(colorScheme)) .monospacedDigit() .frame(minWidth: 100) Button(action: { viewModel.increaseRate() }) { Image(systemName: "plus") .font(.system(size: 35, weight: .medium)) - .foregroundColor(colorScheme == .dark ? .white : Color.green.opacity(0.9)) + .foregroundColor(colorScheme == .dark ? .white : Color.primaryGreen90) } } @@ -84,17 +84,17 @@ struct HomeView: View { VStack(spacing: 16) { Text("현재 카테고리") .font(.system(size: 28)) - .foregroundColor(colorScheme == .dark ? .white.opacity(0.6) : .black.opacity(0.6)) + .foregroundColor(Color.secondaryText(colorScheme)) Text(viewModel.currentCategoryName) .font(.system(size: 32, weight: .semibold)) - .foregroundColor(colorScheme == .dark ? .black : .white) + .foregroundColor(.white) .padding(.horizontal, 24) .padding(.vertical, 12) .frame(width: 340, height: 85) .background( RoundedRectangle(cornerRadius: 16) - .fill(Color.green.opacity(0.9)) + .fill(Color.primaryGreen90) ) .foregroundColor(.white) } diff --git a/today-s-sound/Presentation/Features/NotificationList/NotificationListView.swift b/today-s-sound/Presentation/Features/NotificationList/NotificationListView.swift index 2d45333..7d61d70 100644 --- a/today-s-sound/Presentation/Features/NotificationList/NotificationListView.swift +++ b/today-s-sound/Presentation/Features/NotificationList/NotificationListView.swift @@ -8,7 +8,7 @@ struct NotificationListView: View { var body: some View { NavigationView { ZStack { - (colorScheme == .dark ? Color.black : Color(white: 0.95)) + Color.background(colorScheme) .ignoresSafeArea() VStack(spacing: 0) { @@ -16,7 +16,7 @@ struct NotificationListView: View { // 타이틀 Text("최근 알림") .font(.system(size: 28, weight: .bold)) - .foregroundColor(colorScheme == .dark ? .white : .black) + .foregroundColor(Color.text(colorScheme)) .frame(maxWidth: .infinity, alignment: .leading) .padding(.horizontal, 24) .padding(.bottom, 16) @@ -40,15 +40,13 @@ struct NotificationListView: View { struct AlertCardView: View { let alert: Alert let colorScheme: ColorScheme - let customPink = Color(red: 1.0, green: 0.298, blue: 0.729, opacity: 1.0) - let customGreen = Color(red: 0 / 255, green: 223 / 255, blue: 119 / 255) private var cardColor: Color { - alert.isUrgent ? customPink : customGreen + alert.isUrgent ? .urgentPink : .primaryGreen } private var buttonBackgroundColor: Color { - colorScheme == .dark ? .black : .white + Color.buttonBackground(colorScheme) } var body: some View { @@ -81,12 +79,12 @@ struct AlertCardView: View { HStack(spacing: 8) { Image(systemName: "speaker.wave.2.fill") .font(.system(size: 18)) - .foregroundStyle(colorScheme == .dark ? .white : .black) + .foregroundStyle(Color.text(colorScheme)) Text("음성으로 듣기") .font(.system(size: 18, weight: .semibold)) - .foregroundColor(colorScheme == .dark ? .white : .black) + .foregroundColor(Color.text(colorScheme)) } - .foregroundColor(colorScheme == .dark ? .black : .white) + .foregroundColor(Color.buttonBackground(colorScheme)) .frame(maxWidth: .infinity) .padding(.vertical, 14) .background( @@ -99,7 +97,7 @@ struct AlertCardView: View { .background( RoundedRectangle(cornerRadius: 16) .fill(cardColor) - .shadow(color: .black.opacity(0.15), radius: 8, x: 0, y: 4) + .shadow(color: .black15, radius: 8, x: 0, y: 4) ) } } diff --git a/today-s-sound/Presentation/Features/SubscriptionList/SubscriptionListView.swift b/today-s-sound/Presentation/Features/SubscriptionList/SubscriptionListView.swift index 9a1d7c4..024c059 100644 --- a/today-s-sound/Presentation/Features/SubscriptionList/SubscriptionListView.swift +++ b/today-s-sound/Presentation/Features/SubscriptionList/SubscriptionListView.swift @@ -6,11 +6,10 @@ struct SubscriptionListView: View { @StateObject private var viewModel = SubscriptionListViewModel() @Environment(\.colorScheme) var colorScheme @State private var showAddSubscription = false - let customGreen = Color(red: 0 / 255, green: 223 / 255, blue: 119 / 255) var body: some View { NavigationView { ZStack { - (colorScheme == .dark ? Color.black : .white) + Color.background(colorScheme) .ignoresSafeArea() VStack(alignment: .leading, spacing: 12) { @@ -19,14 +18,14 @@ struct SubscriptionListView: View { // 타이틀 Text("구독 설정") .font(.system(size: 31, weight: .bold)) - .foregroundColor(colorScheme == .dark ? .white : .black) + .foregroundColor(Color.text(colorScheme)) .frame(maxWidth: .infinity, alignment: .leading) .padding(.horizontal, 24) .padding(.bottom, 16) Text("구독 중인 페이지") .font(.system(size:28, weight: .bold)) - .foregroundStyle(customGreen) + .foregroundStyle(Color.primaryGreen) .padding(.horizontal, 24) // 구독 목록 @@ -56,7 +55,7 @@ struct SubscriptionListView: View { .padding(.vertical, 16) .background( RoundedRectangle(cornerRadius: 12) - .fill(Color.green.opacity(0.9)) + .fill(Color.primaryGreen90) ) } @@ -77,7 +76,6 @@ struct SubscriptionCardView: View { let subscription: Subscription let colorScheme: ColorScheme - let cardGreyColor = Color(red: 245 / 255, green: 245 / 255, blue: 245 / 255) var body: some View { @@ -85,11 +83,11 @@ struct SubscriptionCardView: View { VStack(alignment: .leading, spacing: 8) { Text(subscription.name) .font(.system(size: 20, weight: .semibold)) - .foregroundColor(colorScheme == .dark ? .white : .black) + .foregroundColor(Color.text(colorScheme)) Text(subscription.url) .font(.system(size: 13)) - .foregroundColor(colorScheme == .dark ? .white.opacity(0.8) : .black.opacity(0.6)) + .foregroundColor(Color.secondaryText(colorScheme)) .lineLimit(1) HStack(spacing: 8) { @@ -109,8 +107,8 @@ struct SubscriptionCardView: View { .padding(16) .background( RoundedRectangle(cornerRadius: 12) - .fill(colorScheme == .dark ? Color(white: 0.15) : cardGreyColor) - .shadow(color: .black.opacity(0.05), radius: 4, x: 0, y: 2) + .fill(Color.secondaryBackground(colorScheme)) + .shadow(color: .black5, radius: 4, x: 0, y: 2) ) } } @@ -119,18 +117,16 @@ struct StatusBadge: View { let text: String let colorScheme: ColorScheme - let fontgreenColor = Color(red: 0 / 255, green: 223 / 255, blue: 119 / 255) - let badgeBackgroundColor = Color(red: 52 / 255, green: 199 / 255, blue: 89 / 255, opacity: 0.16) var body: some View { Text(text) .font(.system(size: 14, weight: .medium)) - .foregroundColor(colorScheme == .dark ? .white :fontgreenColor) + .foregroundColor(colorScheme == .dark ? .white : .primaryGreen) .padding(.horizontal, 8) .padding(.vertical, 4) .background( RoundedRectangle(cornerRadius: 20) - .fill(badgeBackgroundColor) + .fill(Color.badgeGreen) ) } } diff --git a/today-s-sound/Resources/Colors.swift b/today-s-sound/Resources/Colors.swift new file mode 100644 index 0000000..92b7aa5 --- /dev/null +++ b/today-s-sound/Resources/Colors.swift @@ -0,0 +1,74 @@ +// +// Colors.swift +// today-s-sound +// +// Created by Assistant on 12/19/24. +// + +import SwiftUI + +// MARK: - Brand Colors +extension Color { + /// 메인 브랜드 그린 색상 (Primary Green) + static let primaryGreen = Color(red: 0 / 255, green: 223 / 255, blue: 119 / 255) + + /// 긴급 알림 핑크 색상 (Urgent Pink) + static let urgentPink = Color(red: 1.0, green: 0.298, blue: 0.729, opacity: 1.0) + + /// 배지 배경 그린 색상 (Badge Background Green) + static let badgeGreen = Color(red: 52 / 255, green: 199 / 255, blue: 89 / 255, opacity: 0.16) + + /// 카드 그레이 색상 (Card Grey) + static let cardGrey = Color(red: 245 / 255, green: 245 / 255, blue: 245 / 255) +} + +// MARK: - Semantic Colors +extension Color { + /// 배경색 (다크모드 대응) + static func background(_ colorScheme: ColorScheme) -> Color { + colorScheme == .dark ? .black : .white + } + + /// 보조 배경색 (다크모드 대응) + static func secondaryBackground(_ colorScheme: ColorScheme) -> Color { + colorScheme == .dark ? Color(white: 0.15) : Color(white: 0.95) + } + + /// 텍스트 색상 (다크모드 대응) + static func text(_ colorScheme: ColorScheme) -> Color { + colorScheme == .dark ? .white : .black + } + + /// 보조 텍스트 색상 (다크모드 대응) + static func secondaryText(_ colorScheme: ColorScheme) -> Color { + colorScheme == .dark ? .white.opacity(0.6) : .black.opacity(0.6) + } + + /// 테두리 색상 (다크모드 대응) + static func border(_ colorScheme: ColorScheme) -> Color { + colorScheme == .dark ? .white.opacity(0.2) : .gray.opacity(0.3) + } + + /// 버튼 배경색 (다크모드 대응) + static func buttonBackground(_ colorScheme: ColorScheme) -> Color { + colorScheme == .dark ? .black : .white + } +} + +// MARK: - Opacity Variants +extension Color { + /// Primary Green with 90% opacity + static let primaryGreen90 = Color.primaryGreen.opacity(0.9) + + /// Primary Green with 20% opacity + static let primaryGreen20 = Color.primaryGreen.opacity(0.2) + + /// Black with 15% opacity + static let black15 = Color.black.opacity(0.15) + + /// Black with 25% opacity + static let black25 = Color.black.opacity(0.25) + + /// Black with 5% opacity + static let black5 = Color.black.opacity(0.05) +} From 2b4affc51b79b465fbdb9c63d067f511755a01e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=A7=80=ED=98=84?= <102128060+wlgusqkr@users.noreply.github.com> Date: Wed, 8 Oct 2025 16:18:55 +0900 Subject: [PATCH 04/13] =?UTF-8?q?[Refactor]=20#4=20Badge=ED=8C=8C=EC=9D=BC?= =?UTF-8?q?=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AddSubscription/AddSubscriptionView.swift | 16 --- .../AddSubscription/KeywordBadge.swift | 35 ++++++ .../NotificationList/AlertCardView.swift | 102 ++++++++++++++++++ .../NotificationListView.swift | 64 ----------- .../SubscriptionList/StatusBadge.swift | 35 ++++++ .../SubscriptionListView.swift | 17 --- 6 files changed, 172 insertions(+), 97 deletions(-) create mode 100644 today-s-sound/Presentation/Features/AddSubscription/KeywordBadge.swift create mode 100644 today-s-sound/Presentation/Features/NotificationList/AlertCardView.swift create mode 100644 today-s-sound/Presentation/Features/SubscriptionList/StatusBadge.swift diff --git a/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionView.swift b/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionView.swift index 72b1e6b..d6e1527 100644 --- a/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionView.swift +++ b/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionView.swift @@ -142,22 +142,6 @@ struct AddSubscriptionView: View { } } -struct KeywordBadge: View { - let text: String - let colorScheme: ColorScheme - - var body: some View { - Text(text) - .font(.system(size: 12, weight: .medium)) - .foregroundColor(Color.text(colorScheme)) - .padding(.horizontal, 12) - .padding(.vertical, 6) - .background( - RoundedRectangle(cornerRadius: 8) - .fill(Color.primaryGreen20) - ) - } -} struct AddSubscriptionView_Previews: PreviewProvider { static var previews: some View { diff --git a/today-s-sound/Presentation/Features/AddSubscription/KeywordBadge.swift b/today-s-sound/Presentation/Features/AddSubscription/KeywordBadge.swift new file mode 100644 index 0000000..593b599 --- /dev/null +++ b/today-s-sound/Presentation/Features/AddSubscription/KeywordBadge.swift @@ -0,0 +1,35 @@ +// +// KeywordBadge.swift +// today-s-sound +// +// Created by Assistant on 12/19/24. +// + +import SwiftUI + +struct KeywordBadge: View { + let text: String + let colorScheme: ColorScheme + + var body: some View { + Text(text) + .font(.system(size: 12, weight: .medium)) + .foregroundColor(Color.text(colorScheme)) + .padding(.horizontal, 12) + .padding(.vertical, 6) + .background( + RoundedRectangle(cornerRadius: 8) + .fill(Color.primaryGreen20) + ) + } +} + +struct KeywordBadge_Previews: PreviewProvider { + static var previews: some View { + VStack(spacing: 16) { + KeywordBadge(text: "장학금", colorScheme: .light) + KeywordBadge(text: "교직부공지사항", colorScheme: .dark) + } + .padding() + } +} diff --git a/today-s-sound/Presentation/Features/NotificationList/AlertCardView.swift b/today-s-sound/Presentation/Features/NotificationList/AlertCardView.swift new file mode 100644 index 0000000..7972ecd --- /dev/null +++ b/today-s-sound/Presentation/Features/NotificationList/AlertCardView.swift @@ -0,0 +1,102 @@ +// +// AlertCardView.swift +// today-s-sound +// +// Created by Assistant on 12/19/24. +// + +import SwiftUI + +struct AlertCardView: View { + let alert: Alert + let colorScheme: ColorScheme + + private var cardColor: Color { + alert.isUrgent ? .urgentPink : .primaryGreen + } + + private var buttonBackgroundColor: Color { + Color.buttonBackground(colorScheme) + } + + var body: some View { + + VStack(spacing: 20) { + // 상단: 타이틀과 아이콘 + HStack(alignment: .top, spacing: 12) { + Image(systemName: alert.isUrgent ? "bell.fill" : "doc.fill") + .font(.system(size: 24)) + .foregroundColor(.white) + + VStack(alignment: .leading, spacing: 8) { + Text(alert.title) + .font(.system(size: 20, weight: .bold)) + .foregroundColor(.white) + .multilineTextAlignment(.leading) + + Text("2시간 전") + .font(.system(size: 16)) + .foregroundColor(.white.opacity(0.9)) + } + + Spacer() + } + + // 하단: 음성으로 듣기 버튼 + Button(action: { + SpeechService.shared.speak(text: alert.title) + }) { + HStack(spacing: 8) { + Image(systemName: "speaker.wave.2.fill") + .font(.system(size: 18)) + .foregroundStyle(Color.text(colorScheme)) + Text("음성으로 듣기") + .font(.system(size: 18, weight: .semibold)) + .foregroundColor(Color.text(colorScheme)) + } + .foregroundColor(Color.buttonBackground(colorScheme)) + .frame(maxWidth: .infinity) + .padding(.vertical, 14) + .background( + RoundedRectangle(cornerRadius: 12) + .fill(buttonBackgroundColor) + ) + } + } + .padding(24) + .background( + RoundedRectangle(cornerRadius: 16) + .fill(cardColor) + .shadow(color: .black15, radius: 8, x: 0, y: 4) + ) + } +} + +struct AlertCardView_Previews: PreviewProvider { + static var previews: some View { + VStack(spacing: 16) { + AlertCardView( + alert: Alert( + id: UUID(), + title: "일이삼사오육칠팔", + content: "공지 내용 예시", + date: Date().addingTimeInterval(-7200), + isUrgent: true + ), + colorScheme: .light + ) + + AlertCardView( + alert: Alert( + id: UUID(), + title: "잡코리아 채용 공고", + content: "채용 소식", + date: Date().addingTimeInterval(-10800), + isUrgent: false + ), + colorScheme: .dark + ) + } + .padding() + } +} diff --git a/today-s-sound/Presentation/Features/NotificationList/NotificationListView.swift b/today-s-sound/Presentation/Features/NotificationList/NotificationListView.swift index 7d61d70..177435f 100644 --- a/today-s-sound/Presentation/Features/NotificationList/NotificationListView.swift +++ b/today-s-sound/Presentation/Features/NotificationList/NotificationListView.swift @@ -37,70 +37,6 @@ struct NotificationListView: View { } } -struct AlertCardView: View { - let alert: Alert - let colorScheme: ColorScheme - - private var cardColor: Color { - alert.isUrgent ? .urgentPink : .primaryGreen - } - - private var buttonBackgroundColor: Color { - Color.buttonBackground(colorScheme) - } - - var body: some View { - - VStack(spacing: 20) { - // 상단: 타이틀과 아이콘 - HStack(alignment: .top, spacing: 12) { - Image(systemName: alert.isUrgent ? "bell.fill" : "doc.fill") - .font(.system(size: 24)) - .foregroundColor(.white) - - VStack(alignment: .leading, spacing: 8) { - Text(alert.title) - .font(.system(size: 20, weight: .bold)) - .foregroundColor(.white) - .multilineTextAlignment(.leading) - - Text("2시간 전") - .font(.system(size: 16)) - .foregroundColor(.white.opacity(0.9)) - } - - Spacer() - } - - // 하단: 음성으로 듣기 버튼 - Button(action: { - SpeechService.shared.speak(text: alert.title) - }) { - HStack(spacing: 8) { - Image(systemName: "speaker.wave.2.fill") - .font(.system(size: 18)) - .foregroundStyle(Color.text(colorScheme)) - Text("음성으로 듣기") - .font(.system(size: 18, weight: .semibold)) - .foregroundColor(Color.text(colorScheme)) - } - .foregroundColor(Color.buttonBackground(colorScheme)) - .frame(maxWidth: .infinity) - .padding(.vertical, 14) - .background( - RoundedRectangle(cornerRadius: 12) - .fill(buttonBackgroundColor) - ) - } - } - .padding(24) - .background( - RoundedRectangle(cornerRadius: 16) - .fill(cardColor) - .shadow(color: .black15, radius: 8, x: 0, y: 4) - ) - } -} struct NotificationListView_Previews: PreviewProvider { static var previews: some View { diff --git a/today-s-sound/Presentation/Features/SubscriptionList/StatusBadge.swift b/today-s-sound/Presentation/Features/SubscriptionList/StatusBadge.swift new file mode 100644 index 0000000..d7e5141 --- /dev/null +++ b/today-s-sound/Presentation/Features/SubscriptionList/StatusBadge.swift @@ -0,0 +1,35 @@ +// +// StatusBadge.swift +// today-s-sound +// +// Created by Assistant on 12/19/24. +// + +import SwiftUI + +struct StatusBadge: View { + let text: String + let colorScheme: ColorScheme + + var body: some View { + Text(text) + .font(.system(size: 14, weight: .medium)) + .foregroundColor(colorScheme == .dark ? .white : .primaryGreen) + .padding(.horizontal, 8) + .padding(.vertical, 4) + .background( + RoundedRectangle(cornerRadius: 20) + .fill(Color.badgeGreen) + ) + } +} + +struct StatusBadge_Previews: PreviewProvider { + static var previews: some View { + VStack(spacing: 16) { + StatusBadge(text: "등록중", colorScheme: .light) + StatusBadge(text: "일이삼사", colorScheme: .dark) + } + .padding() + } +} diff --git a/today-s-sound/Presentation/Features/SubscriptionList/SubscriptionListView.swift b/today-s-sound/Presentation/Features/SubscriptionList/SubscriptionListView.swift index 024c059..0535303 100644 --- a/today-s-sound/Presentation/Features/SubscriptionList/SubscriptionListView.swift +++ b/today-s-sound/Presentation/Features/SubscriptionList/SubscriptionListView.swift @@ -113,23 +113,6 @@ struct SubscriptionCardView: View { } } -struct StatusBadge: View { - let text: String - let colorScheme: ColorScheme - - - var body: some View { - Text(text) - .font(.system(size: 14, weight: .medium)) - .foregroundColor(colorScheme == .dark ? .white : .primaryGreen) - .padding(.horizontal, 8) - .padding(.vertical, 4) - .background( - RoundedRectangle(cornerRadius: 20) - .fill(Color.badgeGreen) - ) - } -} struct SubscriptionListView_Previews: PreviewProvider { static var previews: some View { From fdc10a4405a9d5ecb6ac269a2f056a3e612c7e08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=A7=80=ED=98=84?= <102128060+wlgusqkr@users.noreply.github.com> Date: Wed, 8 Oct 2025 20:07:29 +0900 Subject: [PATCH 05/13] =?UTF-8?q?[Refactor]=20#4=20=EA=B5=AC=EB=8F=85=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EB=8B=A8=EC=9C=84=EB=A1=9C=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AddSubscription/AddSubscriptionView.swift | 128 +++++------------- .../Components/HeaderBar.swift | 37 +++++ .../Components/InputFieldSection.swift | 93 +++++++++++++ .../{ => Components}/KeywordBadge.swift | 0 .../Components/ScreenTitle.swift | 33 +++++ .../Components/UrgentToggleRow.swift | 37 +++++ .../AddSubscription/ScreenTitle.swift | 33 +++++ .../Presentation/Features/Main/HomeView.swift | 17 --- 8 files changed, 265 insertions(+), 113 deletions(-) create mode 100644 today-s-sound/Presentation/Features/AddSubscription/Components/HeaderBar.swift create mode 100644 today-s-sound/Presentation/Features/AddSubscription/Components/InputFieldSection.swift rename today-s-sound/Presentation/Features/AddSubscription/{ => Components}/KeywordBadge.swift (100%) create mode 100644 today-s-sound/Presentation/Features/AddSubscription/Components/ScreenTitle.swift create mode 100644 today-s-sound/Presentation/Features/AddSubscription/Components/UrgentToggleRow.swift create mode 100644 today-s-sound/Presentation/Features/AddSubscription/ScreenTitle.swift diff --git a/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionView.swift b/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionView.swift index d6e1527..135079c 100644 --- a/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionView.swift +++ b/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionView.swift @@ -13,109 +13,45 @@ struct AddSubscriptionView: View { .ignoresSafeArea() VStack(spacing: 0) { - // 상단 바 - HStack { - Button(action: { - dismiss() - }) { - Image(systemName: "xmark") - .font(.title2) - .foregroundColor(Color.text(colorScheme)) - } - Spacer() - } - .padding(.horizontal, 24) - .padding(.vertical, 16) - - // 타이틀 - Text("새 웹페이지 추가") - .font(.system(size: 28, weight: .bold)) - .foregroundColor(colorScheme == .dark ? .white : .primaryGreen) - .frame(maxWidth: .infinity, alignment: .leading) - .padding(.horizontal, 24) - .padding(.bottom, 16) + HeaderBar(colorScheme: colorScheme, onClose: { dismiss() }) + ScreenTitle(text: "새 웹페이지 추가", colorScheme: colorScheme) ScrollView { VStack(spacing: 24) { - // URL 입력 섹션 - VStack(alignment: .leading, spacing: 12) { - Text("웹사이트 URL") - .font(.system(size: 16, weight: .semibold)) - .foregroundColor(Color.text(colorScheme)) - .background( - RoundedRectangle(cornerRadius: 12) - .fill(Color.secondaryBackground(colorScheme)) - ) - - TextField("https://www.example.com", text: $viewModel.urlText) - .padding() - .background( - RoundedRectangle(cornerRadius: 12) - .fill(Color.secondaryBackground(colorScheme)) - .stroke(Color.border(colorScheme), lineWidth: 1) + InputFieldSection( + title: "웹사이트 URL", + placeholder: "https://www.example.com", + description: "모니터링 할 웹페이지 URL을 입력하세요.", + text: $viewModel.urlText, + colorScheme: colorScheme + ) + + InputFieldSection( + title: "웹페이지 별명", + placeholder: "동국대학교 공지사항", + description: "웹 페이지를 식별할 명칭을 입력하세요.", + text: $viewModel.nameText, + colorScheme: colorScheme + ) + + InputFieldSection( + title: "키워드 필터", + placeholder: "장학금, 교직, 학생회", + description: "관심 키워드가 포함된 내용을 걸러낼 필요가 있으면 입력하세요.", + text: $viewModel.keywordsText, + colorScheme: colorScheme, + additionalContent: { + AnyView( + HStack(spacing: 8) { + KeywordBadge(text: "장학금", colorScheme: colorScheme) + KeywordBadge(text: "교직부공지사항", colorScheme: colorScheme) + } ) - .foregroundColor(Color.text(colorScheme)) - - Text("모니터링 할 웹페이지 URL을 입력하세요.") - .font(.system(size: 13)) - .foregroundColor(Color.secondaryText(colorScheme)) - } - - // 웹페이지 별명 섹션 - VStack(alignment: .leading, spacing: 12) { - Text("웹페이지 별명") - .font(.system(size: 16, weight: .semibold)) - .foregroundColor(Color.text(colorScheme)) - - TextField("동국대학교 공지사항", text: $viewModel.nameText) - .padding() - .background( - RoundedRectangle(cornerRadius: 12) - .fill(Color.secondaryBackground(colorScheme)) - .stroke(Color.border(colorScheme), lineWidth: 1) - ) - .foregroundColor(Color.text(colorScheme)) - - Text("웹 페이지를 식별할 명칭을 입력하세요.") - .font(.system(size: 13)) - .foregroundColor(Color.secondaryText(colorScheme)) - } - - // 키워드 필터 섹션 - VStack(alignment: .leading, spacing: 12) { - Text("키워드 필터") - .font(.system(size: 16, weight: .semibold)) - .foregroundColor(Color.text(colorScheme)) - - TextField("장학금, 교직, 학생회", text: $viewModel.keywordsText) - .padding() - .background( - RoundedRectangle(cornerRadius: 12) - .fill(Color.secondaryBackground(colorScheme)) - .stroke(Color.border(colorScheme), lineWidth: 1) - ) - .foregroundColor(Color.text(colorScheme)) - HStack(spacing: 8) { - KeywordBadge(text: "장학금", colorScheme: colorScheme) - KeywordBadge(text: "교직부공지사항", colorScheme: colorScheme) } + ) - Text("관심 키워드가 포함된 내용을 걸러낼 필요가 있으면 입력하세요.") - .font(.system(size: 13)) - .foregroundColor(Color.secondaryText(colorScheme)) - } - - // 긴급 알림으로 설정 토글 - HStack { - Text("긴급 알림으로 설정") - .font(.system(size: 16, weight: .semibold)) - .foregroundColor(Color.text(colorScheme)) - Spacer() - Toggle("", isOn: $viewModel.isUrgent) - .labelsHidden() - } - .padding() + UrgentToggleRow(isOn: $viewModel.isUrgent, colorScheme: colorScheme) // 하단 버튼 Button(action: { diff --git a/today-s-sound/Presentation/Features/AddSubscription/Components/HeaderBar.swift b/today-s-sound/Presentation/Features/AddSubscription/Components/HeaderBar.swift new file mode 100644 index 0000000..afca2dd --- /dev/null +++ b/today-s-sound/Presentation/Features/AddSubscription/Components/HeaderBar.swift @@ -0,0 +1,37 @@ +// +// HeaderBar.swift +// today-s-sound +// +// Created by Assistant on 12/19/24. +// + +import SwiftUI + +struct HeaderBar: View { + let colorScheme: ColorScheme + let onClose: () -> Void + + var body: some View { + HStack { + Button(action: onClose) { + Image(systemName: "xmark") + .font(.title2) + .foregroundColor(Color.text(colorScheme)) + } + Spacer() + } + .padding(.horizontal, 24) + .padding(.vertical, 16) + } +} + +struct HeaderBar_Previews: PreviewProvider { + static var previews: some View { + VStack(spacing: 0) { + HeaderBar(colorScheme: .light, onClose: {}) + HeaderBar(colorScheme: .dark, onClose: {}) + } + } +} + + diff --git a/today-s-sound/Presentation/Features/AddSubscription/Components/InputFieldSection.swift b/today-s-sound/Presentation/Features/AddSubscription/Components/InputFieldSection.swift new file mode 100644 index 0000000..07d56d4 --- /dev/null +++ b/today-s-sound/Presentation/Features/AddSubscription/Components/InputFieldSection.swift @@ -0,0 +1,93 @@ +// +// InputFieldSection.swift +// today-s-sound +// +// Created by Assistant on 12/19/24. +// + +import SwiftUI + +struct InputFieldSection: View { + let title: String + let placeholder: String + let description: String + @Binding var text: String + let colorScheme: ColorScheme + let additionalContent: (() -> AnyView)? + + init( + title: String, + placeholder: String, + description: String, + text: Binding, + colorScheme: ColorScheme, + additionalContent: (() -> AnyView)? = nil + ) { + self.title = title + self.placeholder = placeholder + self.description = description + self._text = text + self.colorScheme = colorScheme + self.additionalContent = additionalContent + } + + var body: some View { + VStack(alignment: .leading, spacing: 12) { + Text(title) + .font(.system(size: 16, weight: .semibold)) + .foregroundColor(Color.text(colorScheme)) +// .background( +// RoundedRectangle(cornerRadius: 12) +// .fill(Color.secondaryBackground(colorScheme)) +// ) + + TextField(placeholder, text: $text) + .padding() + .background( + RoundedRectangle(cornerRadius: 12) + .fill(Color.secondaryBackground(colorScheme)) + .stroke(Color.border(colorScheme), lineWidth: 1) + ) + .foregroundColor(Color.text(colorScheme)) + + if let additionalContent = additionalContent { + additionalContent() + } + + Text(description) + .font(.system(size: 13)) + .foregroundColor(Color.secondaryText(colorScheme)) + } + } +} + +struct InputFieldSection_Previews: PreviewProvider { + static var previews: some View { + VStack(spacing: 24) { + InputFieldSection( + title: "웹사이트 URL", + placeholder: "https://www.example.com", + description: "모니터링 할 웹페이지 URL을 입력하세요.", + text: .constant(""), + colorScheme: .light + ) + + InputFieldSection( + title: "키워드 필터", + placeholder: "장학금, 교직, 학생회", + description: "관심 키워드가 포함된 내용을 걸러낼 필요가 있으면 입력하세요.", + text: .constant(""), + colorScheme: .dark, + additionalContent: { + AnyView( + HStack(spacing: 8) { + KeywordBadge(text: "장학금", colorScheme: .dark) + KeywordBadge(text: "교직부공지사항", colorScheme: .dark) + } + ) + } + ) + } + .padding() + } +} diff --git a/today-s-sound/Presentation/Features/AddSubscription/KeywordBadge.swift b/today-s-sound/Presentation/Features/AddSubscription/Components/KeywordBadge.swift similarity index 100% rename from today-s-sound/Presentation/Features/AddSubscription/KeywordBadge.swift rename to today-s-sound/Presentation/Features/AddSubscription/Components/KeywordBadge.swift diff --git a/today-s-sound/Presentation/Features/AddSubscription/Components/ScreenTitle.swift b/today-s-sound/Presentation/Features/AddSubscription/Components/ScreenTitle.swift new file mode 100644 index 0000000..75831af --- /dev/null +++ b/today-s-sound/Presentation/Features/AddSubscription/Components/ScreenTitle.swift @@ -0,0 +1,33 @@ +// +// ScreenTitle.swift +// today-s-sound +// +// Created by Assistant on 12/19/24. +// + +import SwiftUI + +struct ScreenTitle: View { + let text: String + let colorScheme: ColorScheme + + var body: some View { + Text(text) + .font(.system(size: 28, weight: .bold)) + .foregroundColor(colorScheme == .dark ? .white : .primaryGreen) + .frame(maxWidth: .infinity, alignment: .leading) + .padding(.horizontal, 24) + .padding(.bottom, 16) + } +} + +struct ScreenTitle_Previews: PreviewProvider { + static var previews: some View { + VStack(spacing: 0) { + ScreenTitle(text: "새 웹페이지 추가", colorScheme: .light) + ScreenTitle(text: "새 웹페이지 추가", colorScheme: .dark) + } + } +} + + diff --git a/today-s-sound/Presentation/Features/AddSubscription/Components/UrgentToggleRow.swift b/today-s-sound/Presentation/Features/AddSubscription/Components/UrgentToggleRow.swift new file mode 100644 index 0000000..b639127 --- /dev/null +++ b/today-s-sound/Presentation/Features/AddSubscription/Components/UrgentToggleRow.swift @@ -0,0 +1,37 @@ +// +// UrgentToggleRow.swift +// today-s-sound +// +// Created by Assistant on 12/19/24. +// + +import SwiftUI + +struct UrgentToggleRow: View { + @Binding var isOn: Bool + let colorScheme: ColorScheme + + var body: some View { + HStack { + Text("긴급 알림으로 설정") + .font(.system(size: 16, weight: .semibold)) + .foregroundColor(Color.text(colorScheme)) + Spacer() + Toggle("", isOn: $isOn) + .labelsHidden() + } + .padding() + } +} + +struct UrgentToggleRow_Previews: PreviewProvider { + static var previews: some View { + VStack(spacing: 16) { + UrgentToggleRow(isOn: .constant(true), colorScheme: .light) + UrgentToggleRow(isOn: .constant(false), colorScheme: .dark) + } + .padding() + } +} + + diff --git a/today-s-sound/Presentation/Features/AddSubscription/ScreenTitle.swift b/today-s-sound/Presentation/Features/AddSubscription/ScreenTitle.swift new file mode 100644 index 0000000..75831af --- /dev/null +++ b/today-s-sound/Presentation/Features/AddSubscription/ScreenTitle.swift @@ -0,0 +1,33 @@ +// +// ScreenTitle.swift +// today-s-sound +// +// Created by Assistant on 12/19/24. +// + +import SwiftUI + +struct ScreenTitle: View { + let text: String + let colorScheme: ColorScheme + + var body: some View { + Text(text) + .font(.system(size: 28, weight: .bold)) + .foregroundColor(colorScheme == .dark ? .white : .primaryGreen) + .frame(maxWidth: .infinity, alignment: .leading) + .padding(.horizontal, 24) + .padding(.bottom, 16) + } +} + +struct ScreenTitle_Previews: PreviewProvider { + static var previews: some View { + VStack(spacing: 0) { + ScreenTitle(text: "새 웹페이지 추가", colorScheme: .light) + ScreenTitle(text: "새 웹페이지 추가", colorScheme: .dark) + } + } +} + + diff --git a/today-s-sound/Presentation/Features/Main/HomeView.swift b/today-s-sound/Presentation/Features/Main/HomeView.swift index 06c411b..5b86769 100644 --- a/today-s-sound/Presentation/Features/Main/HomeView.swift +++ b/today-s-sound/Presentation/Features/Main/HomeView.swift @@ -18,23 +18,6 @@ struct HomeView: View { .ignoresSafeArea() VStack(spacing: 0) { -// HStack { -// Button(action: {}) { -// Image(systemName: "bell") -// .font(.system(size: 48, weight: .medium)) -// .foregroundColor(colorScheme == .dark ? .white : Color.primaryGreen90) -// } -// Spacer() -// Button(action: {}) { -// Image(systemName: "line.3.horizontal") -// .font(.system(size: 48, weight: .medium)) -// .foregroundColor(colorScheme == .dark ? .white : Color.primaryGreen90) -// } -// } -// .padding(.horizontal, 24) -// .padding(.top, 16) -// -// Spacer() Spacer() // 오늘의 소리 타이틀 From 8a542bf2730d2c28c7c24176b4257f53fda12bb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=A7=80=ED=98=84?= <102128060+wlgusqkr@users.noreply.github.com> Date: Wed, 8 Oct 2025 20:20:57 +0900 Subject: [PATCH 06/13] =?UTF-8?q?[Refactor]=20#4=20=EC=B5=9C=EA=B7=BC=20?= =?UTF-8?q?=EA=B5=AC=EB=8F=85=20=EB=AA=A9=EB=A1=9D=20=EB=A6=AC=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Base/Component/ScreenSectionTitle.swift | 33 +++++++++++++++++++ .../AddSubscription/ScreenTitle.swift | 33 ------------------- .../NotificationListView.swift | 8 +---- 3 files changed, 34 insertions(+), 40 deletions(-) create mode 100644 today-s-sound/Presentation/Base/Component/ScreenSectionTitle.swift delete mode 100644 today-s-sound/Presentation/Features/AddSubscription/ScreenTitle.swift diff --git a/today-s-sound/Presentation/Base/Component/ScreenSectionTitle.swift b/today-s-sound/Presentation/Base/Component/ScreenSectionTitle.swift new file mode 100644 index 0000000..b681101 --- /dev/null +++ b/today-s-sound/Presentation/Base/Component/ScreenSectionTitle.swift @@ -0,0 +1,33 @@ +// +// ScreenSection.swift +// today-s-sound +// +// Created by 박지현 on 10/8/25. +// + +import SwiftUI + +/// 공통 타이틀 컴포넌트. 다양한 화면에서 재사용 가능 +struct ScreenSectionTitle: View { + let text: String + let colorScheme: ColorScheme + + var body: some View { + Text(text) + .font(.system(size: 28, weight: .bold)) + .foregroundColor(Color.text(colorScheme)) + .frame(maxWidth: .infinity, alignment: .leading) + .padding(.horizontal, 24) + .padding(.bottom, 16) + } +} + +struct ScreenSectionTitle_Previews: PreviewProvider { + static var previews: some View { + VStack(spacing: 16) { + ScreenSectionTitle(text: "최근 알림", colorScheme: .light) + ScreenSectionTitle(text: "구독 설정", colorScheme: .light) + } + .padding() + } +} diff --git a/today-s-sound/Presentation/Features/AddSubscription/ScreenTitle.swift b/today-s-sound/Presentation/Features/AddSubscription/ScreenTitle.swift deleted file mode 100644 index 75831af..0000000 --- a/today-s-sound/Presentation/Features/AddSubscription/ScreenTitle.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// ScreenTitle.swift -// today-s-sound -// -// Created by Assistant on 12/19/24. -// - -import SwiftUI - -struct ScreenTitle: View { - let text: String - let colorScheme: ColorScheme - - var body: some View { - Text(text) - .font(.system(size: 28, weight: .bold)) - .foregroundColor(colorScheme == .dark ? .white : .primaryGreen) - .frame(maxWidth: .infinity, alignment: .leading) - .padding(.horizontal, 24) - .padding(.bottom, 16) - } -} - -struct ScreenTitle_Previews: PreviewProvider { - static var previews: some View { - VStack(spacing: 0) { - ScreenTitle(text: "새 웹페이지 추가", colorScheme: .light) - ScreenTitle(text: "새 웹페이지 추가", colorScheme: .dark) - } - } -} - - diff --git a/today-s-sound/Presentation/Features/NotificationList/NotificationListView.swift b/today-s-sound/Presentation/Features/NotificationList/NotificationListView.swift index 177435f..45b8a47 100644 --- a/today-s-sound/Presentation/Features/NotificationList/NotificationListView.swift +++ b/today-s-sound/Presentation/Features/NotificationList/NotificationListView.swift @@ -13,13 +13,7 @@ struct NotificationListView: View { VStack(spacing: 0) { Spacer() - // 타이틀 - Text("최근 알림") - .font(.system(size: 28, weight: .bold)) - .foregroundColor(Color.text(colorScheme)) - .frame(maxWidth: .infinity, alignment: .leading) - .padding(.horizontal, 24) - .padding(.bottom, 16) + ScreenSectionTitle(text: "최근 알림", colorScheme: colorScheme) ScrollView { VStack(spacing: 16) { From 919f81edb2f3eff817c077dee777a0f3b8d5a769 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=A7=80=ED=98=84?= <102128060+wlgusqkr@users.noreply.github.com> Date: Wed, 8 Oct 2025 20:38:26 +0900 Subject: [PATCH 07/13] =?UTF-8?q?Refactor]=20#4=20=EA=B5=AC=EB=8F=85=20?= =?UTF-8?q?=EC=A4=91=EC=9D=B8=20=EB=AA=A9=EB=A1=9D=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=EB=A1=9C=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ctionTitle.swift => ScreenMainTitle.swift} | 6 +- .../Component/ScreenSubTitle.swift} | 6 +- .../AddSubscription/AddSubscriptionView.swift | 2 +- .../{Components => Component}/HeaderBar.swift | 0 .../InputFieldSection.swift | 0 .../KeywordBadge.swift | 0 .../UrgentToggleRow.swift | 0 .../NotificationListView.swift | 2 +- .../Component/AddSubscriptionButton.swift | 37 ++++++++ .../Component/EmptyStateView.swift | 26 +++++ .../{ => Component}/StatusBadge.swift | 0 .../Component/SubscriptionCardView.swift | 49 ++++++++++ .../Component/SubscriptionsListSection.swift | 31 ++++++ .../SubscriptionListView.swift | 94 ++----------------- 14 files changed, 160 insertions(+), 93 deletions(-) rename today-s-sound/Presentation/Base/Component/{ScreenSectionTitle.swift => ScreenMainTitle.swift} (78%) rename today-s-sound/Presentation/{Features/AddSubscription/Components/ScreenTitle.swift => Base/Component/ScreenSubTitle.swift} (76%) rename today-s-sound/Presentation/Features/AddSubscription/{Components => Component}/HeaderBar.swift (100%) rename today-s-sound/Presentation/Features/AddSubscription/{Components => Component}/InputFieldSection.swift (100%) rename today-s-sound/Presentation/Features/AddSubscription/{Components => Component}/KeywordBadge.swift (100%) rename today-s-sound/Presentation/Features/AddSubscription/{Components => Component}/UrgentToggleRow.swift (100%) create mode 100644 today-s-sound/Presentation/Features/SubscriptionList/Component/AddSubscriptionButton.swift create mode 100644 today-s-sound/Presentation/Features/SubscriptionList/Component/EmptyStateView.swift rename today-s-sound/Presentation/Features/SubscriptionList/{ => Component}/StatusBadge.swift (100%) create mode 100644 today-s-sound/Presentation/Features/SubscriptionList/Component/SubscriptionCardView.swift create mode 100644 today-s-sound/Presentation/Features/SubscriptionList/Component/SubscriptionsListSection.swift diff --git a/today-s-sound/Presentation/Base/Component/ScreenSectionTitle.swift b/today-s-sound/Presentation/Base/Component/ScreenMainTitle.swift similarity index 78% rename from today-s-sound/Presentation/Base/Component/ScreenSectionTitle.swift rename to today-s-sound/Presentation/Base/Component/ScreenMainTitle.swift index b681101..d64b248 100644 --- a/today-s-sound/Presentation/Base/Component/ScreenSectionTitle.swift +++ b/today-s-sound/Presentation/Base/Component/ScreenMainTitle.swift @@ -8,7 +8,7 @@ import SwiftUI /// 공통 타이틀 컴포넌트. 다양한 화면에서 재사용 가능 -struct ScreenSectionTitle: View { +struct ScreenMainTitle: View { let text: String let colorScheme: ColorScheme @@ -25,8 +25,8 @@ struct ScreenSectionTitle: View { struct ScreenSectionTitle_Previews: PreviewProvider { static var previews: some View { VStack(spacing: 16) { - ScreenSectionTitle(text: "최근 알림", colorScheme: .light) - ScreenSectionTitle(text: "구독 설정", colorScheme: .light) + ScreenMainTitle(text: "최근 알림", colorScheme: .light) + ScreenMainTitle(text: "구독 설정", colorScheme: .light) } .padding() } diff --git a/today-s-sound/Presentation/Features/AddSubscription/Components/ScreenTitle.swift b/today-s-sound/Presentation/Base/Component/ScreenSubTitle.swift similarity index 76% rename from today-s-sound/Presentation/Features/AddSubscription/Components/ScreenTitle.swift rename to today-s-sound/Presentation/Base/Component/ScreenSubTitle.swift index 75831af..12dde75 100644 --- a/today-s-sound/Presentation/Features/AddSubscription/Components/ScreenTitle.swift +++ b/today-s-sound/Presentation/Base/Component/ScreenSubTitle.swift @@ -7,7 +7,7 @@ import SwiftUI -struct ScreenTitle: View { +struct ScreenSubTitle: View { let text: String let colorScheme: ColorScheme @@ -24,8 +24,8 @@ struct ScreenTitle: View { struct ScreenTitle_Previews: PreviewProvider { static var previews: some View { VStack(spacing: 0) { - ScreenTitle(text: "새 웹페이지 추가", colorScheme: .light) - ScreenTitle(text: "새 웹페이지 추가", colorScheme: .dark) + ScreenSubTitle(text: "새 웹페이지 추가", colorScheme: .light) + ScreenSubTitle(text: "새 웹페이지 추가", colorScheme: .dark) } } } diff --git a/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionView.swift b/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionView.swift index 135079c..f89564f 100644 --- a/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionView.swift +++ b/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionView.swift @@ -15,7 +15,7 @@ struct AddSubscriptionView: View { VStack(spacing: 0) { HeaderBar(colorScheme: colorScheme, onClose: { dismiss() }) - ScreenTitle(text: "새 웹페이지 추가", colorScheme: colorScheme) + ScreenSubTitle(text: "새 웹페이지 추가", colorScheme: colorScheme) ScrollView { VStack(spacing: 24) { diff --git a/today-s-sound/Presentation/Features/AddSubscription/Components/HeaderBar.swift b/today-s-sound/Presentation/Features/AddSubscription/Component/HeaderBar.swift similarity index 100% rename from today-s-sound/Presentation/Features/AddSubscription/Components/HeaderBar.swift rename to today-s-sound/Presentation/Features/AddSubscription/Component/HeaderBar.swift diff --git a/today-s-sound/Presentation/Features/AddSubscription/Components/InputFieldSection.swift b/today-s-sound/Presentation/Features/AddSubscription/Component/InputFieldSection.swift similarity index 100% rename from today-s-sound/Presentation/Features/AddSubscription/Components/InputFieldSection.swift rename to today-s-sound/Presentation/Features/AddSubscription/Component/InputFieldSection.swift diff --git a/today-s-sound/Presentation/Features/AddSubscription/Components/KeywordBadge.swift b/today-s-sound/Presentation/Features/AddSubscription/Component/KeywordBadge.swift similarity index 100% rename from today-s-sound/Presentation/Features/AddSubscription/Components/KeywordBadge.swift rename to today-s-sound/Presentation/Features/AddSubscription/Component/KeywordBadge.swift diff --git a/today-s-sound/Presentation/Features/AddSubscription/Components/UrgentToggleRow.swift b/today-s-sound/Presentation/Features/AddSubscription/Component/UrgentToggleRow.swift similarity index 100% rename from today-s-sound/Presentation/Features/AddSubscription/Components/UrgentToggleRow.swift rename to today-s-sound/Presentation/Features/AddSubscription/Component/UrgentToggleRow.swift diff --git a/today-s-sound/Presentation/Features/NotificationList/NotificationListView.swift b/today-s-sound/Presentation/Features/NotificationList/NotificationListView.swift index 45b8a47..91d1326 100644 --- a/today-s-sound/Presentation/Features/NotificationList/NotificationListView.swift +++ b/today-s-sound/Presentation/Features/NotificationList/NotificationListView.swift @@ -13,7 +13,7 @@ struct NotificationListView: View { VStack(spacing: 0) { Spacer() - ScreenSectionTitle(text: "최근 알림", colorScheme: colorScheme) + ScreenMainTitle(text: "최근 알림", colorScheme: colorScheme) ScrollView { VStack(spacing: 16) { diff --git a/today-s-sound/Presentation/Features/SubscriptionList/Component/AddSubscriptionButton.swift b/today-s-sound/Presentation/Features/SubscriptionList/Component/AddSubscriptionButton.swift new file mode 100644 index 0000000..4b45718 --- /dev/null +++ b/today-s-sound/Presentation/Features/SubscriptionList/Component/AddSubscriptionButton.swift @@ -0,0 +1,37 @@ +// +// AddSubscriptionButton.swift +// today-s-sound +// +// Created by Assistant on 12/19/24. +// + +import SwiftUI + +struct AddSubscriptionButton: View { + let colorScheme: ColorScheme + let onTap: () -> Void + + var body: some View { + VStack(spacing: 12) { + Button(action: onTap) { + HStack { + Image(systemName: "plus.circle.fill") + .font(.system(size: 18)) + Text("새로운 웹페이지 추가") + .font(.system(size: 24, weight: .semibold)) + } + .foregroundColor(.white) + .frame(maxWidth: .infinity) + .padding(.vertical, 16) + .background( + RoundedRectangle(cornerRadius: 12) + .fill(Color.primaryGreen90) + ) + } + } + .padding(.horizontal, 16) + .padding(.bottom, 16) + } +} + + diff --git a/today-s-sound/Presentation/Features/SubscriptionList/Component/EmptyStateView.swift b/today-s-sound/Presentation/Features/SubscriptionList/Component/EmptyStateView.swift new file mode 100644 index 0000000..e7a9071 --- /dev/null +++ b/today-s-sound/Presentation/Features/SubscriptionList/Component/EmptyStateView.swift @@ -0,0 +1,26 @@ +// +// EmptyStateView.swift +// today-s-sound +// +// Created by Assistant on 12/19/24. +// + +import SwiftUI + +struct EmptyStateView: View { + let message: String + let colorScheme: ColorScheme + + var body: some View { + VStack(spacing: 12) { + Image(systemName: "tray") + .font(.system(size: 40, weight: .regular)) + .foregroundColor(Color.secondaryText(colorScheme)) + Text(message) + .foregroundColor(Color.secondaryText(colorScheme)) + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + } +} + + diff --git a/today-s-sound/Presentation/Features/SubscriptionList/StatusBadge.swift b/today-s-sound/Presentation/Features/SubscriptionList/Component/StatusBadge.swift similarity index 100% rename from today-s-sound/Presentation/Features/SubscriptionList/StatusBadge.swift rename to today-s-sound/Presentation/Features/SubscriptionList/Component/StatusBadge.swift diff --git a/today-s-sound/Presentation/Features/SubscriptionList/Component/SubscriptionCardView.swift b/today-s-sound/Presentation/Features/SubscriptionList/Component/SubscriptionCardView.swift new file mode 100644 index 0000000..f994394 --- /dev/null +++ b/today-s-sound/Presentation/Features/SubscriptionList/Component/SubscriptionCardView.swift @@ -0,0 +1,49 @@ +// +// SubscriptionCardView.swift +// today-s-sound +// +// Created by Assistant on 12/19/24. +// + +import SwiftUI + +struct SubscriptionCardView: View { + let subscription: Subscription + let colorScheme: ColorScheme + + var body: some View { + HStack(spacing: 12) { + VStack(alignment: .leading, spacing: 8) { + Text(subscription.name) + .font(.system(size: 20, weight: .semibold)) + .foregroundColor(Color.text(colorScheme)) + + Text(subscription.url) + .font(.system(size: 13)) + .foregroundColor(Color.secondaryText(colorScheme)) + .lineLimit(1) + + HStack(spacing: 8) { + StatusBadge(text: "등록중", colorScheme: colorScheme) + StatusBadge(text: "일이삼사", colorScheme: colorScheme) + } + } + + Spacer() + + Button(action: {}) { + Image(systemName: "bell") + .font(.system(size: 40)) + .foregroundColor(.green) + } + } + .padding(16) + .background( + RoundedRectangle(cornerRadius: 12) + .fill(Color.secondaryBackground(colorScheme)) + .shadow(color: .black5, radius: 4, x: 0, y: 2) + ) + } +} + + diff --git a/today-s-sound/Presentation/Features/SubscriptionList/Component/SubscriptionsListSection.swift b/today-s-sound/Presentation/Features/SubscriptionList/Component/SubscriptionsListSection.swift new file mode 100644 index 0000000..26cf5bc --- /dev/null +++ b/today-s-sound/Presentation/Features/SubscriptionList/Component/SubscriptionsListSection.swift @@ -0,0 +1,31 @@ +// +// SubscriptionsListSection.swift +// today-s-sound +// +// Created by Assistant on 12/19/24. +// + +import SwiftUI + +struct SubscriptionsListSection: View { + let subscriptions: [Subscription] + let colorScheme: ColorScheme + + var body: some View { + if subscriptions.isEmpty { + EmptyStateView(message: "구독 중인 페이지가 없어요.", colorScheme: colorScheme) + } else { + ScrollView { + VStack(spacing: 12) { + ForEach(subscriptions) { subscription in + SubscriptionCardView(subscription: subscription, colorScheme: colorScheme) + } + } + .padding(.horizontal, 16) + .padding(.top, 8) + } + } + } +} + + diff --git a/today-s-sound/Presentation/Features/SubscriptionList/SubscriptionListView.swift b/today-s-sound/Presentation/Features/SubscriptionList/SubscriptionListView.swift index 0535303..f91a8c8 100644 --- a/today-s-sound/Presentation/Features/SubscriptionList/SubscriptionListView.swift +++ b/today-s-sound/Presentation/Features/SubscriptionList/SubscriptionListView.swift @@ -6,6 +6,7 @@ struct SubscriptionListView: View { @StateObject private var viewModel = SubscriptionListViewModel() @Environment(\.colorScheme) var colorScheme @State private var showAddSubscription = false + var body: some View { NavigationView { ZStack { @@ -15,53 +16,17 @@ struct SubscriptionListView: View { VStack(alignment: .leading, spacing: 12) { Spacer() - // 타이틀 - Text("구독 설정") - .font(.system(size: 31, weight: .bold)) - .foregroundColor(Color.text(colorScheme)) - .frame(maxWidth: .infinity, alignment: .leading) - .padding(.horizontal, 24) - .padding(.bottom, 16) - - Text("구독 중인 페이지") - .font(.system(size:28, weight: .bold)) - .foregroundStyle(Color.primaryGreen) - .padding(.horizontal, 24) - - // 구독 목록 - ScrollView { - VStack(spacing: 12) { - ForEach(viewModel.subscriptions) { subscription in - SubscriptionCardView(subscription: subscription, colorScheme: colorScheme) - } - } - .padding(.horizontal, 16) - .padding(.top, 8) - } + ScreenMainTitle(text: "구독 설정", colorScheme: colorScheme) + ScreenSubTitle(text: "구독 중인 페이지", colorScheme: colorScheme) - // 하단 버튼 - VStack(spacing: 12) { - Button(action: { - showAddSubscription = true - }) { - HStack { - Image(systemName: "plus.circle.fill") - .font(.system(size: 18)) - Text("새로운 웹페이지 추가") - .font(.system(size: 24, weight: .semibold)) - } - .foregroundColor(.white) - .frame(maxWidth: .infinity) - .padding(.vertical, 16) - .background( - RoundedRectangle(cornerRadius: 12) - .fill(Color.primaryGreen90) - ) - } + SubscriptionsListSection( + subscriptions: viewModel.subscriptions, + colorScheme: colorScheme + ) + AddSubscriptionButton(colorScheme: colorScheme) { + showAddSubscription = true } - .padding(.horizontal, 16) - .padding(.bottom, 16) } } .navigationBarHidden(true) @@ -72,47 +37,6 @@ struct SubscriptionListView: View { } } -struct SubscriptionCardView: View { - let subscription: Subscription - let colorScheme: ColorScheme - - - - var body: some View { - HStack(spacing: 12) { - VStack(alignment: .leading, spacing: 8) { - Text(subscription.name) - .font(.system(size: 20, weight: .semibold)) - .foregroundColor(Color.text(colorScheme)) - - Text(subscription.url) - .font(.system(size: 13)) - .foregroundColor(Color.secondaryText(colorScheme)) - .lineLimit(1) - - HStack(spacing: 8) { - StatusBadge(text: "등록중", colorScheme: colorScheme) - StatusBadge(text: "일이삼사", colorScheme: colorScheme) - } - } - - Spacer() - - Button(action: {}) { - Image(systemName: "bell") - .font(.system(size: 40)) - .foregroundColor(.green) - } - } - .padding(16) - .background( - RoundedRectangle(cornerRadius: 12) - .fill(Color.secondaryBackground(colorScheme)) - .shadow(color: .black5, radius: 4, x: 0, y: 2) - ) - } -} - struct SubscriptionListView_Previews: PreviewProvider { static var previews: some View { From 11440fd5fd4392d465997486e0d01389ddc30856 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=A7=80=ED=98=84?= <102128060+wlgusqkr@users.noreply.github.com> Date: Wed, 8 Oct 2025 20:45:17 +0900 Subject: [PATCH 08/13] =?UTF-8?q?[Refactor]=20#4=20Home=EC=9D=84=20Compone?= =?UTF-8?q?nt=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Presentation/Features/Main/{ => Home}/HomeModel.swift | 0 .../Presentation/Features/Main/{ => Home}/HomeView.swift | 0 .../Presentation/Features/Main/{ => Home}/HomeViewModel.swift | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename today-s-sound/Presentation/Features/Main/{ => Home}/HomeModel.swift (100%) rename today-s-sound/Presentation/Features/Main/{ => Home}/HomeView.swift (100%) rename today-s-sound/Presentation/Features/Main/{ => Home}/HomeViewModel.swift (100%) diff --git a/today-s-sound/Presentation/Features/Main/HomeModel.swift b/today-s-sound/Presentation/Features/Main/Home/HomeModel.swift similarity index 100% rename from today-s-sound/Presentation/Features/Main/HomeModel.swift rename to today-s-sound/Presentation/Features/Main/Home/HomeModel.swift diff --git a/today-s-sound/Presentation/Features/Main/HomeView.swift b/today-s-sound/Presentation/Features/Main/Home/HomeView.swift similarity index 100% rename from today-s-sound/Presentation/Features/Main/HomeView.swift rename to today-s-sound/Presentation/Features/Main/Home/HomeView.swift diff --git a/today-s-sound/Presentation/Features/Main/HomeViewModel.swift b/today-s-sound/Presentation/Features/Main/Home/HomeViewModel.swift similarity index 100% rename from today-s-sound/Presentation/Features/Main/HomeViewModel.swift rename to today-s-sound/Presentation/Features/Main/Home/HomeViewModel.swift From 45807a82f129f568462cccbe154af81e01a4f690 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=A7=80=ED=98=84?= <102128060+wlgusqkr@users.noreply.github.com> Date: Thu, 9 Oct 2025 11:48:20 +0900 Subject: [PATCH 09/13] =?UTF-8?q?[Refactor/#4]=20lint=20=EC=98=A4=EB=A5=98?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .swiftlint.yml | 2 + Makefile | 2 +- today-s-sound/Core/Network/APIService.swift | 95 +++++------ today-s-sound/Core/Network/NetworkError.swift | 11 +- today-s-sound/Core/SpeechService.swift | 37 ++-- today-s-sound/Data/Models/Alert.swift | 11 +- today-s-sound/Data/Models/Subscription.swift | 7 +- today-s-sound/Layout.png | Bin 131979 -> 0 bytes .../Base/Component/ScreenMainTitle.swift | 34 ++-- .../Base/Component/ScreenSubTitle.swift | 34 ++-- .../AddSubscription/AddSubscriptionView.swift | 134 +++++++-------- .../AddSubscriptionViewModel.swift | 11 +- .../AddSubscription/Component/HeaderBar.swift | 38 ++--- .../Component/InputFieldSection.swift | 140 +++++++-------- .../Component/KeywordBadge.swift | 38 ++--- .../Component/UrgentToggleRow.swift | 38 ++--- .../Features/Main/Home/HomeView.swift | 4 +- .../Presentation/Features/Main/MainView.swift | 43 +++-- .../Features/Main/MainViewModel.swift | 59 ++++--- .../NotificationList/AlertCardView.swift | 161 +++++++++--------- .../NotificationListView.swift | 50 +++--- .../NotificationListViewModel.swift | 25 ++- .../Component/AddSubscriptionButton.swift | 44 +++-- .../Component/EmptyStateView.swift | 24 ++- .../Component/StatusBadge.swift | 40 ++--- .../Component/SubscriptionCardView.swift | 68 ++++---- .../Component/SubscriptionsListSection.swift | 32 ++-- .../SubscriptionListView.swift | 68 ++++---- .../SubscriptionListViewModel.swift | 23 ++- today-s-sound/Resources/Colors.swift | 111 ++++++------ 30 files changed, 677 insertions(+), 707 deletions(-) delete mode 100644 today-s-sound/Layout.png diff --git a/.swiftlint.yml b/.swiftlint.yml index cae063a..3135983 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -1,6 +1,8 @@ disabled_rules: - line_length - trailing_whitespace + - multiple_closures_with_trailing_closure + - todo included: - today-s-sound - Tests diff --git a/Makefile b/Makefile index 844a0d8..4e1d635 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # ===== Config ===== SCHEME ?= today-s-sound PROJECT ?= today-s-sound.xcodeproj -DEST ?= platform=iOS Simulator,name=iPhone 16 Pro +DEST ?= platform=iOS Simulator,name=iPhone 16 Pro,OS=18.6 CONFIG ?= Debug SDK ?= iphonesimulator diff --git a/today-s-sound/Core/Network/APIService.swift b/today-s-sound/Core/Network/APIService.swift index 6530873..4236ea5 100644 --- a/today-s-sound/Core/Network/APIService.swift +++ b/today-s-sound/Core/Network/APIService.swift @@ -1,72 +1,71 @@ - -import Foundation import Combine -import Moya import CombineMoya +import Foundation +import Moya // Example TargetType - replace with actual API endpoints enum TodaySoundAPI { - case fetchContent(id: String) + case fetchContent(id: String) } extension TodaySoundAPI: TargetType { - var baseURL: URL { URL(string: "https://your-api-url.com")! } + var baseURL: URL { URL(string: "https://your-api-url.com")! } - var path: String { - switch self { - case .fetchContent(let id): - return "/content/\(id)" - } + var path: String { + switch self { + case let .fetchContent(id): + "/content/\(id)" } + } - var method: Moya.Method { - switch self { - case .fetchContent: - return .get - } + var method: Moya.Method { + switch self { + case .fetchContent: + .get } + } - var task: Task { - switch self { - case .fetchContent: - return .requestPlain - } + var task: Task { + switch self { + case .fetchContent: + .requestPlain } + } - var headers: [String: String]? { - return ["Content-type": "application/json"] - } + var headers: [String: String]? { + ["Content-type": "application/json"] + } } protocol APIServiceType { - func request(_ target: TodaySoundAPI) -> AnyPublisher + func request(_ target: TodaySoundAPI) -> AnyPublisher } class APIService: APIServiceType { - private let provider: MoyaProvider + private let provider: MoyaProvider - init(provider: MoyaProvider = MoyaProvider()) { - self.provider = provider - } + init(provider: MoyaProvider = MoyaProvider()) { + self.provider = provider + } - func request(_ target: TodaySoundAPI) -> AnyPublisher { - return provider.requestPublisher(target) - .tryMap { response -> Data in - guard (200...299).contains(response.statusCode) else { - throw NetworkError.serverError(statusCode: response.statusCode) - } - return response.data - } - .decode(type: T.self, decoder: JSONDecoder()) - .mapError { error -> NetworkError in - if let networkError = error as? NetworkError { - return networkError - } else if error is DecodingError { - return .decodingFailed(error) - } else { - return .requestFailed(error) - } - } - .eraseToAnyPublisher() - } + func request(_ target: TodaySoundAPI) -> AnyPublisher { + provider.requestPublisher(target) + .tryMap { response -> Data in + guard (200 ... 299).contains(response.statusCode) else { + throw NetworkError.serverError(statusCode: response.statusCode) + } + return response.data + } + .decode(type: T.self, decoder: JSONDecoder()) + .mapError { error -> NetworkError in + if let networkError = error as? NetworkError { + return networkError + } else if error is DecodingError { + return .decodingFailed(error) + } else { + return .requestFailed(error) + } + } + .eraseToAnyPublisher() + } } diff --git a/today-s-sound/Core/Network/NetworkError.swift b/today-s-sound/Core/Network/NetworkError.swift index 0f41732..7090e7b 100644 --- a/today-s-sound/Core/Network/NetworkError.swift +++ b/today-s-sound/Core/Network/NetworkError.swift @@ -1,10 +1,9 @@ - import Foundation enum NetworkError: Error { - case invalidURL - case requestFailed(Error) - case decodingFailed(Error) - case serverError(statusCode: Int) - case unknown + case invalidURL + case requestFailed(Error) + case decodingFailed(Error) + case serverError(statusCode: Int) + case unknown } diff --git a/today-s-sound/Core/SpeechService.swift b/today-s-sound/Core/SpeechService.swift index 8b99d68..92a6c1c 100644 --- a/today-s-sound/Core/SpeechService.swift +++ b/today-s-sound/Core/SpeechService.swift @@ -1,26 +1,25 @@ - -import Foundation import AVFoundation +import Foundation class SpeechService { - static let shared = SpeechService() - private let synthesizer = AVSpeechSynthesizer() + static let shared = SpeechService() + private let synthesizer = AVSpeechSynthesizer() - private init() {} + private init() {} - func speak(text: String, language: String = "ko-KR") { - let utterance = AVSpeechUtterance(string: text) - utterance.voice = AVSpeechSynthesisVoice(language: language) - - // Stop any speaking in progress before starting a new one - if synthesizer.isSpeaking { - synthesizer.stopSpeaking(at: .immediate) - } - - synthesizer.speak(utterance) - } - - func stop() { - synthesizer.stopSpeaking(at: .immediate) + func speak(text: String, language: String = "ko-KR") { + let utterance = AVSpeechUtterance(string: text) + utterance.voice = AVSpeechSynthesisVoice(language: language) + + // Stop any speaking in progress before starting a new one + if synthesizer.isSpeaking { + synthesizer.stopSpeaking(at: .immediate) } + + synthesizer.speak(utterance) + } + + func stop() { + synthesizer.stopSpeaking(at: .immediate) + } } diff --git a/today-s-sound/Data/Models/Alert.swift b/today-s-sound/Data/Models/Alert.swift index e055738..ef17b00 100644 --- a/today-s-sound/Data/Models/Alert.swift +++ b/today-s-sound/Data/Models/Alert.swift @@ -1,10 +1,9 @@ - import Foundation struct Alert: Codable, Identifiable { - let id: UUID - let title: String - let content: String - let date: Date - let isUrgent: Bool + let id: UUID + let title: String + let content: String + let date: Date + let isUrgent: Bool } diff --git a/today-s-sound/Data/Models/Subscription.swift b/today-s-sound/Data/Models/Subscription.swift index 2d6307e..647634a 100644 --- a/today-s-sound/Data/Models/Subscription.swift +++ b/today-s-sound/Data/Models/Subscription.swift @@ -1,8 +1,7 @@ - import Foundation struct Subscription: Codable, Identifiable { - let id: UUID - let name: String - let url: String + let id: UUID + let name: String + let url: String } diff --git a/today-s-sound/Layout.png b/today-s-sound/Layout.png deleted file mode 100644 index 054c3d38fda06e472fb46c46687a1c03e8e43bdb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 131979 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⋙TBQkgm*y6o!G)d$0zIXWhp$|G*tZY&OB=MO?8j4c%OD%IiU_{@-kQl z*KgJop$6L67SU|99JRu{Isg7#WIAdFZ!P{Zt_5~l5!uP&g1SKi=^)$qO6L~>@}~*^ zN+|m*=0vHd(<${ty(|$olt{`&^syFYED|og(F)7`fHM zmqLQmwA1k~0q@kp#N=jxSS|Rnf{6e+x%93x*igY>Zkq|#KtwVzM~LB zD~)CUiefOYh_%-_END0b1ul9Uas)k)q$DX0TFKvDFJ+_Qv@3a6_jl^b8NxzB?^t;r z`Wh2@FFRY=Yb&P^6|*GX%_RsdKhank22U>)4`H6RBkKd3{aj@&Gg-6X8|dg`Y=6}q za%Hx`PcxZm9^6^?J|=ZjQEXJ6D2BqCIZXAEXBQwR%;kE&ky@sMy!0mkxBiN?PovO0+giLDQ^eVvq2{6J)zLL$@H6bsXi0DuUQ! zG6%`=XNB{#QQGvjbP?i5|0mI6!o%t)cYrMjtE6;`@4IP$2s|BiPt%@Z1J(>3oOjJa zNTQv64l?fiuqLuwvIG+-#_OGb^69Bdr(_#JWBE@=7JJ%tE-H2)n6Au8P|uKq z0Pwvx{AHHMI5!-c()V!Qa(?Gf?zcu|R24_-NM194ye(1B@gAr`mCyFKq%d#su+{vnIaIF1{AktWHE=G%a3cIERxhGVei6lYRG!yn#Bif95up%+yqOLU}BE z<`lhgtR_FRSSlc8r&q8lWw5J~DVRYly!JQ%`c19g^aId){jkAl2-(E#4lge)B{Wih zzg7+kh5`qzg7OUBit2oReO^G6;HqYiv#Sd9BW)9VJ9`DutPZEWaLhT)oVJM!JyZqx zA3QPJSk27#m6x7WX-0J`wGkF{=N_S(r}AYxF9f2Uo`tPXLPvI>a|WW1y5*_W);dGK zcG~6cC$wzODSBymH2u~3W%H|`Jw?FHw^Y#ll;Vq5mxrww*>>ClYe0#dg=^$jD*H|3 zUd7WsGJq%TytYnC*H=e24u@zw7|0YQ$>T8NUy^rlGBw|2K1J`UXDzsnh`U`ZevX}s zp?q-vta$hZk~?2B9Apc#mwC%{q0!Ihhz?4tU(D$nNn<7c{N!Wx=SJ$OLhS>&u%OXX zmRV&-O`JRYS?reD``M&E8rj@wJfGBUIQuWHt*1hAU?c`Pfc$lCdaqwC=<{b*e+@-Q z&BkiDybY{+@Xk~HjDZC7h6zTRx(`jyuX=!os{u$RY|07-U%8VziH7&~dwT5V0@k7; zY8wB}hVeO9od#hTEFlgA<(_@}t2$C)=18Tr6ctOh{Gf&XFat)rrh+P6`LPU%hs6r`k) z1}Q}eK|s10x{+p(8YBc!kcJ_oLmH$+x*O?`?ru1H-d}v*S?B!2Vhzmm?7H{e*LAHN znTxEI9Q8c3*eU@puPlsL#!T+O%|?Z*tgOc6H|T(&h3kofAETn0sz97xWiGDbpbfW% zJT$T-J!F7HSN+444t`kE z7d(LsXOiI>g40zi`8H`D{L@)+Gi>AJj#0*v(FbW07;2QW;r@96UVo_e&h8UxIkJ^y zN02-MAuR&_{efc6)R+lTl$C1=^ImcGAC8#tjJBssY?;pyqX2l;t^Q@<39=y8F%?7Z zM<=bJWugeO_({cf^CcNo6d0#sR$3)F1__cp;g2g!s9IUXo#m{5a*b0 zz0GX-@bG)_CDc*7!=tWAqj7dtpGMe$4m39eqG(dTcD>dVt(R1Ad&(8s$7+w1e?4%C zS|6t+gg-{2b>Wcc))QkWAo~u~aoPIi1JRMyo-(q^!Uz}=PoF|&*)x2QB{em5Y&4IMHCwuhii-T&+V8KFmAh9CFV>gs6Lm{LoZeQ# zLTK;57877*tPpTyxqSwUHCLgs8uEyR;3 zSxUYRALO0~X{KN)+YJ_>C0m;6`3m%=4D{Ep)xDR}lAeJiu^NgG~-}@PyM~m$ZnY~E2l)a~#0h9oRonf{w z5z+!+s?iF9*37sphRC^2>U)!6AS*ooG!q{D{loq~v*>i%&Pv;IEpgpatl`*cTX*|? z>8_pFYE*7#_7!pz^cykWX3?_>az z+AIyY-Nq&&*w6!YOc9hkxmIaj3PDg5D5)GjT{WuJ6cT#lB>gX;@%blm4k!R7`Avv`G{;&^`!0o0qRS=A_IQmU$F3`C&4$aOi9BxK^h8N9Zor3U$`3&w zVh{4Pt;TCU{)hUX1qXN`c=N@4a@y>RkBRJY@mlcN8g0f4hyhK|<+{{;U1&!hn&aA! zbpL4zxwZ&VIvxv55NJ<^qSgA%xlcx+48v9|`DQ{#6aH!eItXxB1UMc7!kIdduuh%b zX3kPJ0I&J6H{H`G2S#(mK!ky;nuVsXfjjnoEsjA$4ACLA=7k6cswd@8i1HrMB2!8Mt4{i(>VyUNJNQs&JjPX>sS1c>s_r&>g>x8kPqtZ@ zrs*AZsB?VCoM_>gC<>@{mMwOGVSt(7qQU3ffdHVcTMeYVOfdA$mr@Y$VQ+i!7e5Cw z)3s7NQmgQBou6b916@%9bG~NQC4vjCko;NdPA3eTn211-MIMPf1N|1~fsi&uu7^%z zj<7oHKdJmKbuuLh(hvI$>xDN*nuF1- z;u}ZRqjbWCP;4GCK~NL`}}1?SJZ^QEwL7A#p>K-LsRfLY?Gi`jqQoK)`kccR+& z7v4;fm_g7I%5GwzrI+@P|3T!EGoL#}p-&NH5MW0WkhL>UYpM(|gAOCN>`yQK)Q#=P zfZlY_sfe18xDbUbJ|b6T&*GW$X_A~~ufIuF-Ke*c^2K>a$J=d$v75m4OV!BeIPrWw zD&pHDPnI9;hwJS_oU7;e`K+3y8HdR=+&?~D3SK4k?nbLrtJQeRaHab1dj($>{n~Lp z(o7g$b)2=cQaE~xJi6>ZWB3TvTNEI|K^wnk!v#t&@Z4;cI3+5oTe-bUEV%4JjMp+( z4p|+9*Gn;!OrN}QdRvMCK&d%x!QfATQDDlDKP zZhv;Y{E9pvZ$+#h$~Ml*MJZ2P@tCYsqa#6 z8(4AgCY-86M?ILXsu;z8EFMqJGHYVIZD#+Ivjm^JmPxKlC*buDmy{_nb#D`8u{Ko1Xf|U-0 zn!Imhb%*QIv;>N=*$64+wAVfNLuv%YUt-nQXw)uFp%2?-*_S2jV%49D0K95W#U3MY zyK$AnHogXw_M(#(ArBj@gdFuni5gQ9>uNtP1hL?`LNHJ*@kku&t`D6kx^{Hu&@LVl zEyfzH$i*iWpfC{3_8ka44qV9o_DXHv?_zmec)Prfxxsy1X1c~&xVYh3{tzzI{%Y9OpGScY zK#a%cu>x|Ha*dXLCYmJy-77r-qR@{&qNIYjxy59HtT7vMf5v`Vo>c!10q-v_fd;r^!e)%85S*Ji0^#rEC2G`l`ncQW2Is?-vRCAv`;qR&+At z6^}zAcOz>@dI$Y<2%|b%J-mSE^iR6HmcY1Zr0VVi?dOR2F>;I!d@nPkpTag+V$?&y(J}zC;+&u(N(2C#qzeK!EFu^) zg;wAB{`@%Pk&Gqj->2$!@c^@h6QL0a z?{nGljxeLPncbK?%0St8cFB2uvk>`DvgqGObH$B%{E4Qxceg_sO7ftPDyZ?1~rysnsR;zIbBHs zya_2$soX5w2b1ry=|7V7M3=Del)Qs2M8v+%sHsV4`Tm8=!p+SMUtWw2K!QAdvMUEc zn$G`eeU$!*ROElPF?rA3_RwCnzKbTB4DOGGL0i_`&r2Wuakq5B$By~~ z`p#*RSspnjHa#;Wnpo*?(6+%Q5UVmO$hul685XqUF^~hA;Vac}sA0Z8Nc4#QXV z;AZ2(2l}~l(qF&3X2}0OycQa?HtnJmsU$7%tB8lwC{LI#xOjoh=@+PD_piW55cAg? z*lTT6nmqjNn4;_d)BqtH#?(3>zlwL_NnCNYy4DPcDL}bbJiCPvau)$nSx-}^g{c`5 z*PoZfu$~;_5g<-;3;y`hUEMg6Oo^PRaq~0nMlmDj+RucKC z-X;_IIIo)O>Vq2O)=)S=v>9OhoHP@H7mWf!v+c zdj3t|%8LaFTn}wJ-k0KtH_jS2`oNgxDSORRjFfDlhi-m@4p*xKMl&TpaK5QSj4u~F zB)2}V+hHM|fZ$YVJa-1bV6xV@#=5Jw!~*wQ@R8~VWC)y>kKg>zrUhRS+$T35s zL<4V*MNm8AL@E5HN#BPCO?IJqTgu*~oI2qWq`$5jV}{o*0qtNzxYbZCwOBLwcyc1_rC3JHD=Nh`;4K&6it+qn)4N_wiMyXh@52R`u8mh?4%XjmXL_Xs}=50`r zb@7qZ{A^-kVwN<(R7m`4sze4aL@LH@2DM~T$+8}GM$8`UZb*wyHR=F%Kr7B+qHwcr zshK?1G3dsQ{;S2(sWTIi?Ugr=|{vWbXc7@j4R^_mKV{G=N(e-crptY&1~fn`miwz zV7&$4XXOqe04{EPO(8_f%m@&YfBfd^hdG?Nlj?H)9#SYFKlSaR&}7mLgfeqlsm=!(UP!C@68i}? z_UWP)5&fq4i*Z5>#EYtX&|PE_Xoj3qG1NenBS|Z`;PEOqvQyu22{`#D^qg%fx)`&l z2&wBG{v>fPmys0RBPK8GzI36m2vUe zR{(ls1H79))nVinnNtwb#V8E^KKee<>*+wnG|x->*K9Az;7Cvnzbz1lTAz7s_ah6{ z0WzHKdxY~Qk&l%=L1}Hr6yt1vK~>|2N>n#KhzQ9k@ILy#mAD=7ldEB!NGL_MR!nV6j1J_1cH z!$@$-%-!wM=91oFY#7y~pN$cbl3HP@zZB()clr1LqkLl30L=MdPr47 zWIp>{9<5daWdBYtbT>9iUZkJ*dX>x!0pmb!^e2liGPxOGUK&p77OxO6I<`RAtq&+JU>$7}x z7QpxW54H~iMhg~xx8q$L?+;{b=RdWs2pAIdXxBYfU!5rp?Dknc2a{-;BY$~nG;THt z+_1{#+nGoxrNAP82G_6j?X4|0Nn-(Ht~MKKP`Nx*g=b(QyK1~ofU*uCK?$Ol68$FL zTU{3FEs1nc;mVomEA6}|AR@?!=KZ}w4IIE;5mY5KwUq^hDU3gBcaUkwDu`t<7 z|2d|Sbzn4|zBuM6|C^BT&_(9&xZ>YGPBcdjkP8lsXCJE`C;d|C0vKSDWAP;BhY3og zsXy4j*NHfwM5#n+f=!@|&Cctq1z)u^KL;t^ro`gGVN4UD7^moZfHrbP(?S(Ph2w5~ z?Xz&5*3?l)3h%(;{EEi8LdP%*`zNkK>WRiZn8+W7(!|Sy;?YO%Zo+8xTVyeui%C~m z>MzT=AIilFQa_Udg(SBBsK13cx-&68! zgft(p-9)Lir2_Im`aL#>PzWd4zPC$S>kQt8p%^}g+(^%Gcc2KACu%+M1_7Kq3S_P)8N zVV1-d<`|~2#}Pb~U<%!C&DrG>ZeCWv%W~vM?M}&T z!I?w~P3XHXytxSEnRI?g!z#NgyBvb=>FSye+QD_I%%~Ctmn{{Tm4V^R;@S zQ>4gjNph76Nuk@Rs#ng5%Ys~`ICl$k{d^?LtEQ1jqLC;EY`vhhwe`EQnwlC>dB3gH zz4IUY>_E0f1@OIVtvAw@vT+GXNfgG&V;OMjf? z|1y3|>orxzJ5{Tu_;v?~FTKy3b_83@4sut|$iE!s6d+g4-NM2UfwF1E@ZZaZbhOjw zflys{#Ld4oLb`m1`dldHuw9+Uo>Khc(K!a?-~KNfCmfj@L41w(mkX2zQ^MMMs14xX z*qIoH^DC41C~JTOPS*fL)48MgZ_f3|kiWxwcIqGhd!Iz0{-0Y$x)O{nTI;zrfT%(S z^5O!b%!BhmP6N7-gbP<`6t3xmBGsfs^_B8I5^wB3_HrtlG4fx;-m$3uSNw0KwETn# zH}V^JLgy>5P2p7J-KFOT$a`;^1N$TxkS_@Urn>fN{V6m_(;6hIGGTEOu*lA8eJ>4a?>OqnE+5BXeT`i=}6Ny!q6 zD*=K+yIc0zGlkr_%YDCM$@RYky=gxT3-)<*rx0h1cRoTWc_BTM3MgVs+MJK?BxtTj zgwBvpY0NcM|IbsP>9PO}u<>2CJ{kNqSnAkK)++fxCvqw(stk||0A>zu&C4P0DRw%> z-)5TYb<3pLwDjB(_%@wD;>+<=%;pkMCxEIA!+3 zg5Sy9zW)a~4V1lxz50kW-=l6~i!Z#@U>FQ~w>jr0Ks-;ns+s}(-gcjD0r!s;JR1cq zCz*k*@j@ge!ylua<)#nq)#y<&}DU2^6Ti;=q&sga6Kg6-7ehw$u*frrXq_v32dv?ZC@Nug+G>v zK$RiOOA!oz8vUItJG4d#bnb-DK0pB6={sVhj%ZA|nZFeU)lN&YxXmfrKxzU( zWE4k$SNNn^&y2IsEj<^v@}y=caBuga6-e_u0RTEN`{emdxN_MrJ!v;pRl?ors))xb zDOAHZ*+1EyQQ)4OoxQcS~m*pHVJ`=z43J0ejEoYAJJ!u>U7%fm3ROP@wRGW&V zXNne|!2lQ+r#_!HagX?Nk^ap7%#;#GX+Wqq%`Yi0MvbLx5b%eij$4flvxEMnc8!!5 zd|+GHGxTHx_Uvo-|N0HnaKS?r1@{tma0nKCN8bor?_13p4KqGDiQs$LorN5xR&E$~ z!3_=9(*k9NLvt1cEDDvtkL%>P!vc5$leuHbtYB(UFlgsFoD7bt&b~-N6xHqS<~B6n z=#vj%)&L~}BB@k>1Y5e-_IQ&DT|G$9H9RhV0WJp{X}gvxjUT2whps0p=3{gU+0X0n=NZ1LTGJc2jby{lCEkQ&&A@cpiQL4eDfgKnjKBr+7r)UWXHo+0E`#4B_XUd{bgY?s$2h0a z1#y5qCve>Gv#r5QkNo-x^<{3$PEG`Lek7zi3qV!9r2sytt55_57Y#XFsJX0NVyJuO z@9c+%vj=o*Q$;3Ko)6X}rt=?6e#-)(XB1H5^`8#oX;o=ZO2G0C<)P@_^c`$>1Bkyl zF_HcCUCe8BCL3@Y0BBDEG7J)Axk+%3M8SXp9-=?YsG*EbymqxW;rgL_ZOc^ftmm`N zw(`wGyHNDl7{($ub5H{GU)P`#Fc;{)Ef=G~eM%((6w`Pdq_3-bAi+Vn>uc#%uQ z_8neGc>UaLC%36xQw2p`pxiba+^KDh5z|-3^gX#> z34!V7t%LWR6vGs$&AP}yGvs(LdLK|13`>%>34KNnG0-L^swXZ+F5Xh6P1YtX;~A-} z-6kCWqe=s>Z5w@Q6AqkVaB1SV0|)Ej7foV}M`}#u(kE#pew9^zV(w?|3eS!=3bod> z)$9)ip7wFWrt(lM-J{`e4Za@K+hF5`^0Q-~614yd|MYJW~t7|w)j zNOP+2vxHspo7!H>8EL1hE2e$9`R*2RKF|~uFdh;rT(WqeLoV@UTUVU5S;(hagN08^U1tqwX1F8m2rEfYBlOQO;hkx z(`b!~+9Ub=?Q!qCTJ^HQo#DEc&CcgJ%gC_&bCuK|PfOZBLxr|iyXSw5?8tUds2QsC zR-OzljSQ5)W>2rBvil-m)2y@qxY_xIZ7Eq_a4%98-Xme*cJ(hrKs|8NX;dfr`7H0_ zpYwrxmNvV#Ss!+{Zj$$9M7H_hTBg6z4;cV&wJFw4i`WQ0A#q(}Dy1h1DZ{6X+~ z%M0PRENXhf@D)6!lfQ&UB%=(~zjReg{jU?hPYXnWRLXyHw8(Wh+oHB}&4-ew>pzPF zco8DgYtHsovhz^sN-v`bN_h3%7wl(A=O%D6n@)|s>Q;w(i{3%g`F0)~$DHN93yBC& zl6(0jTt;0Q=}bfle}rv3llubbsnKz3$>pT(x-|r{vO^zmQQy_+p^rwtA5Zwuq|*Le z-b7~1A~`)LFjMBrbUd7QTk0MD?!I-dl~h2WgUC@5yv4tuPb$R=AZtw;)WIwbo(bn^ z7b<$aS&#RuB(oPI#Qc`+ZiUx)7G$-uHBRG(@(_0p1;LBKkB+U{eZ_A&z*v~2=+%QJ z*V)5Nb3AqMPfYXvUsCOxmq^%n@-_qtK(K1U+4Aui&GJeA(bSrjvHxk_fB#lMxIq9a zL1rj&$5EM=$8FwNo(E97Q?WloH%!mWw#@gMjn_VpU!uL?8Ge$=*jaS_==AQ&`t%!b zg_V`ke}kMxBBLcHP*8;MKVk|r{-C2ztj(+3Vb4{JRDA2*`Sb3$MCJ9@*FRUB45#k+ z-f-q+Y<;}Av+H+8;by;RTU+1w@`9U$%D%!7gaU;|sbk;qHir%b*x*#Lcm1+k@?-9q z`^u|JWRJS+`3G*vMcn*lMduNr;qa6b&NJP&C%D-ha0TqNz=^$#-%Al8X`%5M?%8T& z*ttO1jkh8>3pT8{= zb&z++DW5I{P z{%XbBdmC%;??f!PuD^oI=>#s%3hYdHtu&$v**C9e_Yw8ur8NFRe)(Kb%-|;XncJ^9vWOd}Bl4HDD-wT3UL8{X z=YV4%m*Kw!8Q5WA+vyqYqfLCKq1#FG=j&0uTt5OT?Xs!c`87A9smF%uBIX@@lWoS_ z-A%}Ev;OK~exDnvOO_NZ8(yGzqWFz5a~s1vv=&ABc4nU76PF!$nx3NmnA7&A3%>E1f(Uc86ab4=-qFX=*7};qBNAc# z9!}O;rHM(6@y{i3Pd@bis;Kw8Y@ptjaDCQwZ_a9e(A)X1PpOyR#JpAN?fk;=T-*ck z()R;;>-Ta7ZUGTRxhVswcB)e zv~S(hxuw|**=G*Y(rk})f~=L~&}LzE$-p-sz4hIk;`TY0S5>Z8WqP*(j`u1Ccf-A7 z)$~zY?c+4xw?(B2Isq4k$iC2N6|WJm#n5C>746s48R3m;%EYFOS?^TFT_(5bA3YnE z3H&%1cjvzgqzcuq>2uc~CQ1=a5S;OM`c)&iM~;w= zmliO5?6r`zkeBMCzwc|^LOG_MTA1980cZhyK5*17241J`(>v8s>IidC5e1$a-`!kV zHnw?xl0p~%)w&S=B<;JNBU-^Ti^D}M8N)pL^>3%B3+_lxnwgj3bDis*XoTWKg#j17 z*4?%LTnhwGAHt(~tIz>&ohijrH5lqQbi^T|Il#ep#`Zlv^m?m6``tbF?RX|lHuqRr z9YCa7G`Xg?$=J0auqhN^+buOPE1Ed)`W{+fCio}B(X>Syr?lv|@bpSAaGYHtj0-@0#R#t~o}=5!9_1-ji2+`89!U}CC@9{6f>qD=<~b--X(^9w&8 zYnN!*>Xdf+NS|k7ibxgDrTE(Sx#M1OP1w_w-fFAfce=SBtKa9``3wXUI!0Z`=dbSt z%oeIhF0xda_C6(O)JC2w$9bgY?U`0a=)Z}r0Rb}8uy833W_C6jScVY z7kS}~YmOn;M&5a$_oQHHnnqU^)HE|(L`W^IjlMZcqY&zCEk8sb4q;a$YSiW_%0Zp@H@%QNU1^oxE8{iG=Mrh# za@W^d#X?wiaEZcUC;c>ZnXC&Jo~C|Ya5Z{mbu5RAI^2a0zervEKnwMA8&u8f_5M7_ zL3`d(^^fprm>?5=<@ENqTR)wxI9pC=@oz!z>)o2hRN@>Y4|rU&x)UEFV-*mr2Y<;!)+*V(YZQUs7fGN_nr~O_47=Cewt5oo#+Ft zK^dNRa#HuFt$JHM%q1gQgZl-P@q=3FG%iU=jV{%q0T*>!#Jl`na;3!egN3fr)Dy$5 zTK(#`^(VbDJ5~vj#VW(A4;J>b6v7_T2%uGGNk-m+=LkqvnQ+}^hYn8C`F{&MIOj@n z0L3ukMOnl)m4X5t)@ZAY1J~uEe@@JzwuZ|U8Q_=)VXH!@MHK<}16j{u_Kzg)!{di` zux}SL3jE#~a%UU4E#7xW^j<+^+*VT{XOw!EvhSh$CdI76Mb#nkV`h5%Ge%de5_S6P5LVlO}84WOa~NNJflfuU8wNTQmYHMeW6;Mf}-ygas)KmbA6qFKMC@~zIn*% z#`|Y?1fPt9`0oMMz!xqRHVb(OI)^o zVZ1;^4|RrO7_G|vgfU+HZ;_;&zWDMZ9=Z@g!J<$<9(weDyQAeF(v)#7!sbggc=jX6 zm$beAcCcFtZ6O#b2@;B8yAEZt3~c1cySR-mj-3jV_QzLyDk2D=h5 zV4xUf`*04@*%5Swf;SG&D8?lUk}`O=e)rNtnil2{;_GFDpgA5KkYSVq0!E?69n=!3 zXlkd|57?yYPY82&1*d;{pWJ1Qzp^JM*tScTKY3Lv^ZrhjlgOTPw86U9?eo6f#@S_% z4V*fRgJ`ABhWum{XZLOLi zea7N0Z*QN#P+J~TzauovI4hkc5&D}YMn{PzGYz{zrRB*(I4s`Ggi>{z1+Yxk7G`a-{~RPf)oF!?>fz-{_%_K~GmD3j4& zL{~z337GLc4#xbVWKG!zAJN%_TL|#r@X;+3w;FGGz&{M zeUh#ScklmV43m8DSg06FoI6j`BQc76SDDgWOX0M)Oy?2QxE7k)c{D&W_K?sOy=2;b z`O2l#=)JNUg)Li&Yn{I{*OC~ABp%W4D`P(No3Nv@I|U*&h8RK0D0hYhG@?)Tlr#-8 zl4e6sK0>uqM;L2nep>YInHI9bxwW3hXQBFIJO!nRkFH=2LBG@}o6>5mdyRC+nNj|v z4c+U+QCd6NiV#fFVVzQyptwLXm$0Z0_w8(+GUH-g!b7G0T?=e9>b}sQ{77kGGACx) z+%{h3@FM3aM#i+4(S?eGLp%6xqv)QMua@J`-t&U#4}EntMCUYR&`|Q4+BTvL{D>t? zduxJ8W)7k4^6kUlpQvfvMkd-}%XpPOUv3vc^yfCe^-2D!Zdl@epQa*o@izYK*jM3{ zdJReHMf!|D`7pul7H@JuSep7S^L*4efL7XF%;Ka%rcy^P%N}Z@_jWzl$pggnu9jK_ zr%7gitj6t26y`?OPO*R6eerSQ-$3)Ng;-v~8KqITSpcNE`QIz=6rKi`V0>-p*P0{>i&Z$d=3IW@@(;wEYKEu2n&J^IT(V~(f$-#j%F+|`wecz2?_ z;Pq;JUg}52Xh)M*`*Y5KJapkAkpSm6kERH9Uk9J26QrtRIq<1d7~{%p{cgfTtp4a` z3!}9%k~TQvKwD5vgLE0YQ&6Dz@W#uQ$m^w-)yJ+~&mMj&uOd0eL?4#SNm_;y(-*yY z$iC;k&S6`crSzehOZm zF?8VQFT%YRh4_Z163U?%HCu6?0Yn3<`Wr8Y>%DC5! z>XX7(@M@yjK|<2a%fY?mCw1>NXT33oB2@B}mi7IT1mFI~)|KldienNDRqB()z*Wom zA}!!6*IZ)}GHH)#%zi_kE_C9CW@@tO`z5p#HQC6h=G-C_mUqyA&p7N<0ogV^%opFk z_3AL-)Zi7r42`wJz?{=WIoPX}U z&z3ClQ*TSUt~y_M=H!*@ku{8t5Y7|3_xO=?qkbD_of>W2z|=am)OqDZ&{VS}Su*=` z8XDn!@KHY4a9Wm@TX`7<9V380Sme4D`nGY8GQP>IJ2ut83ZE~OA36Ko^i|o&kE#0( zv330=A{jC(5b-T|EQG7+&&nFbrgPAY>Ls6JLd_EOa{JHrfwtTK&{#vFY8-9)2>drI zBE|-;9@}y=!W9(4JMa7y{dp1siq1$SUg_!b_?Ku&d}wb|;%004#MnZ$Udbb8zz7bT zL4&x1it`)e2;(5FbKTfvg;}+kiRj#n({%k6A^4YnvJQNH>5OkbH*jSeF04oEF-F@H zaS3-16GzUY zCL?GaOI@3`wYK8+bIxd3taX}^Hl)8l`nQM%tyh;Kr?Na=SokneNlGH~DEHIY`rdL@ zptGO;-#QzLzun+?r{uR3gO?mdw0PE9!=U9PKdi1N*{t0x*HB$MW-CFU#=*mZPUNS2 z4V^c-)>9~ZST%>e$cDl>tJm_ytIVG_-M0H0;s1U)#K({dnsB>N6HxdVUwl5gXLsSQ zCY@IJ(FVWaQ|xoPGP`OtCNXJ&Sy#AxW$FWEJLmpDPaWk!qx0P9W>=|W*%!65wKrJ_ zf93lm1xP39rm*09g}qadMS3$#xWkx{r|8y`Q<8xq$vN9idJIG+tM5xR&o`DiFE4MT);gqj)+|Ygy877m<|z+Bm$p11hgi%dW8`x8zz>PR{Gu;{EAk1KYQZM=OtMm}sxN@N6w;#h0c(%9EF% zwb-CjI{X!eyJ&FPcTHfvb@2KZE9%5WVcN=iTC+xBOt4bk+CTvLD8Q!3h=ah>IPGb# zp)o#ak(1*1LJfdzx6LdS8CoNxIe1ctMT8kK}m*L?J= zZ0Yatr|H5xrFL(f3*FBNgLPq}bdWsbh7K!to=(K~G#R6rWDD1=cMY;z;0?3qrC$nO ze?A!LrqpgM;-)?H3JAsT%%ztzvw>6yaq6a4B)z_NYcPsA#7N3KB4>gRG<%T=)0NI; zW)9N7F&4(x$4Z6N2DV4p@j@~v@3?kpjikACw3h1Is^H0n;s+3T2Z7);9_lb`s@D0d zEtLg2^dSMauo{ER7C+WRzzAjK=Q9MVgKit@wCk;X=xWVqhU!od`#;j}R-fA^6k9$T zSk;{&cb6jGf#Y-m1TFA5bTaE8!*-rrlhBX{VRO}FOz@I{{6o20@zX!kPm=1EKuuZ0 zQ5QMx6!8UZ3>{U}Dam&3EsSKFaT)!xn)Eri(TAk2L`XpWuez6y(m%> zA6}bY(M=5tsdzfH+qqvYYBWkWM>R~W^;<#YYU;XnP{`Q=QPGDlnY@=*v&8=`!(iBZe`O4hA_Qxwg?%Pe%k5|JM!wxWOe> zT|m7r`NgN)2-3#orB&MsT`2Km3yxP{9G5Kmke}KiT=mC!CL5)w+{zl;uQf3JVekVH zc5DP%u!#V<(s$%#qiXp4h2Vr^Z+@f0-j`Ybm=M=a8HsU9!`g{|$<7l7Hlv7lmPW?Q zpPnm^$E7#$XseDz?|1MQ;Exz^yllYdL>yR6M%~n^lffdBp?_<7O&M36f}*%MYlIwT zp$_#Xf%KY~t4^ehnB}pGs8=Kwf&^XB&8DbVo7)_2f#cL$A*=CoSb&it2SVaB*dvXR zC%s9g#0+PcKgD);sTqDAYg2Hwe(CYRrT^h!we4q9KRGi$_Q%1+&vjJGFu4ut1xjto z)fC4qGIgW*YzNk z>r}6)6|aPIs|d#rwS^Vu;Q5`Xj{$dIQm&(p-9{ z5Iy$|-bFV3ckMVjq$o~)kkgi=zvmImVga_g*S`S)3%uO2-S5KooctQraS@`CVqCiF z;9rz8M1A^jiiiE{FCfYPZ|OBB;tDeSWu5QcY|=P=wWJmP^x9+RPO%z0saih0m-`hl z!O8BJBEcvj33f(SJ5UxA@aK8bBuH0O@_oY)Rf&Q11*)Nn$T4Db%_5kTF(u{vNX84Y z3EWb_l_I0O4s!Qg+?iK27WTb1Mzjw44~5H0$V88T9wUiNi4^W%>kyq(bw|BFws#!+^whCYRo%*iG0T@p*HBut zdi}{5rO)TV@xxQ{^Fl(Jcy^ul0gVfFbr&LH7b%_Vo?zA9Ir#hR{(hk@e(-HjTSsvv zvqXFfqo_mKsh8f|@25dH+4SS9NcU$d2b)3rgv%tao0Jz@`I+iyu@MIHuRgpcG7#l@ zPf89gN3}*7=AsBBR|~{dgE7^kJ`Oj?M%4|h41_LZKadKD6kW<4eFxll0$>00zq*1p zN44TaQ7&ED&Au-f>?H3dT*sB@3E>iEzHu03rBN9ow3V21BE6~xLDH23>Yb6)aTO{* zXV7Ej%S?j8e>#=~`D#pC_+6L5en)(Fiu*)sDx4uv$KI)$bQotY%w))!KP&K@!q2H9 z;_Nr-VvsbX8>|114gRjlj>`(CS6P+dS6V-@M*VB_;nlbCr*8wzIbt3Y?P}2YdpFk{ zL8|;Z72@z~Xpe;kg*(CRT-0A>b6jG-#Ys@W%Cxs6*en=U{jD-v(cYejfWrXATo_yF zG*GLX!&Zjsohk1r0hz z(W--(hu7EkbL^tbCTZ~c906ybZiZv4)B?Y-NfQ~6P`}3^XKMi3!Xn{20rJBb3?hO| zEuHn zu47F{g!yfUOpK(*d*84aXJv7H7iq!;JbG5bYV_f1nw&W>nBugeDBMaVpv)+`JAZ3t zi~}>lK`{R>5jiv#^*v;m2D`|kd{CXd1XIWILUsEN(< zRU$+kR*KLgyfJuGiauLOLF%+ZU~4&>q4?eiW84TX@1{oY@r!_Q=R)NAtly^`g-J!s zfdO1w#0(mNfC3tWh>QPHibkPX>l{H>@QlcB*XKha*UTi_WV2g|Q)H^_#K&huQQjz7 zlUA!QQ#aU%!r>6r|;AxXVq4oRF?UNo{|8ZL7)L^J7DBwcTd^L5QH7noi@|L z{?L$gHs%%#rE;QH?GHLBDYi}GC&arNAm3dfG~aYWJY05eWhYR5&(I!)VThx5Tybo(AN_tsWpQ{HV*1ctCwcWX>7=gn z3@k^uL+^ErAhl>6x8$dM9u;bx@r9o|4;&{duG1`TzWI=%J*shBC;?q_6xfJ3A?6*` zT=G0~qDJ>^ttz{}eD5??0>Vc?{bAqi+2-gIx99}`iY#dQ2iuXMvfTgH+r0&XVT!6ZTj$V7e^z zP>S;^@7%Vnsje1sjLzBbq7^uIkZ_>)@ctU=Vd!I2$#r&9w*9F>m55%EbuAOszEqk* zMnH4l)vao}3|ck)et}2?$Em;Ed+*DTcwk7PG)5(mR&jznX(4jpD|B$85jl+9WwfEV z+OODDSz85(7Pz_#sp3c1x8oAYb;gu|7K-Q1?7Tnu@yIh!iE%Ya;Qp)Mv|WrT4)%8{ z2DLy-dTl+Z*(Wz%>*Z;-Q^2eB?qUByb%CqnIqTfHswpig{SrOfz^N5u3&85XOEB? z3yxcPnnlqbCWA%ZEt%$Fsla9UaTTxQym$zu3=BiHV&TjvLI7U7079p9Lzf584Qm#q-c^0Ii>g7xx8s5^v@`1zVl|)%kI5UBfJU~wMfh0Z4p>| zfqE6@uO#jNmDIlc+g+vuWX2`hR6hqB+>~mu?rMQY95L^R4E!zrq5>~w?YT6@&jPSV zZd&U}D-H%gddxQ75YfM2vCKrpU{ia^MAJs%gePJh1pR}y_y}bJm8I#hgBDWFm1KT#Wjue7uWBgg3dI0NT!<%}#Yl;sm%frf` zx+RZ^x4G6x!~=$V|L2-{~pM= z#r`g*BL9Ebdh4(#zpZb47`j0Oq+|@FLn-N@QKXSBL8LnbWMBXVlvF7NWE{Fdx%|7Fo7LIY<-1}NXfc7&XWHoYQI3c(z~FhK$loItx0#0K6S z!sDWa&}3_}W?J~4ZoXB$p1=J8f6#~|l40ExZdm#1pga*W$m28Na?2dXS>%W}gy(lx zU^s;T#4e6}TMt$+Ea)?LZ39j|%qc{FI*2!6#qMsciMv2IFT}~s7_~Q)S$4jve@ngRgzqvOcJY~Y=@Ck1x3>;?o-*9U^S$zaEO=G~uO2uVH;8?Bg;})#AW*zUvKuq8nE#v_qg*^RCiRLP%hw=av(fEAU8dQP{_MAX_)LSKPcnNylNZM4R>l^kd_{%rn(W$DopiHAKq z-pOyRldzM;YpW@y(JXuXAIV>;2B<^jz14?pjClqF0MDxVH0sR#0zBBc^-EauKmc+1 zUkAGo$SZ7$hRD|-w6CN4JD)z1?3)fs7cSBX6(VWn8ZAY>gL1!(wSmAxnjz81NU zHn7R!uL#1J9Z2R2@LWDi&zq+>-ZQy;&}3fk{XN8_@)mNW=i_7*zYE6|8_0MiK3@f% z@DtK#Z@g3_s#(nH6?v59KB);@a8i_b4R1IJ5>FxX7y0E#k;NB&N&+c?43nTGb~9be zOTsT?Y4|}LY1svJz+@SV7mvYecUVA2j}g2oLHQi{)m3gEw_R zo;RD$zHfTMBcOmvr9_vAVxs(4l+ndR zh`fDbJ;sY2j~^z=FYBl8wZY34kY?oCQ1DufkO_JnrU{KurejgUM?+`cxOzs{XUXKN zS0jHz_CV}XbLRE(9F=1(d+Mg_U|qQ$^Kuj3OXL<)(sIO3dJ~FZXI*qU$%F?S23ta!rk>DfgKrwsI6DLs6R-#@rq9;FpinU#JZ^TZUxK+TvHEPwntwRH<6tpl7Kbja?eligMf zd5DJ*L@aYZesP)hG_un|J0yjSHF&+w@z1eMV_mS%yvRr`x<8fSY8~*Hf8|u2fY&n9 zA;XIg&g*PF)D`%C&|}5nLt=B?dijbwJcDFpKW5Adubb?dx~bb8%BZLRnr>MNAYbVQ z_YU(4rn|=%KBJeZ^Qp$to!CjS_i;g3_15Igs{|fdI?N{}_wUW8p>xlOi)aoiTUp zJveN_zY{rgi(J0)@XYEqJ(mesM0B=|JkMYOXr-oL$~l_sYB4+;X;0yfxwSXkD=uxa zZ)6-#R+$7v4g&4AsGf3@Y5ewo+R8?*{99=+BHCa%Gk(1Dz6~!+B}8gewwPhKh2j47 z&=r{>8YSXSw?OBVxq<$Y;LN8)XkreUHb_pR1Q^=YyxTM}c&;WExig4rgW^JS^I<>Z zNU{Xe5Lwal7^zsQX{m5AWg0dfYPx*5GOso_5O{HL%j4k;@UL4zyey$PUrJ*g^IqaJWT zX#RTXd7nNLBJbVth+gU;A(;VS09N0PkYtrc;14oat|-+UnOPI+!*DxBTEY)bc%=}0 zZJis=mI?I-)4u$@4WDPw5w`#zhn*wID(k`NQY;|Bk_CMO+J6A2=_?E&OE3U`A6ol9 zkq55>&Hf9%`>#SX!XW=a@%d+ci>9^ipTCNl_6(MoOTBtwK*R$le3%P=2j5SOa(gWG zTr|nmz34Rf<8S+r9FrM zIr-GCM9!$TOl=H_U-ZuEbn1p&D8Dc!_(M^vHGg!!XZf*`XJZx(_=E{Qa63C zt)uq^O~IN$3V5oZw~-x1`Y6hOzQ3w9JfIgmwT+%=wy|O1Y0t@rJJ64pI!4w9TzW-? z4z7^Odpj(LRq2H2^T27+dmI)~x_N-G$T$-fA7(=z5MXZZ%T5>Sm%cq;j5p=cE+-Qi z70)Z?T^rVHa(MtGo7Vw+>Vzg*A-6;AnPkj-gtS9MxU}^~EPYPZ9!G^M&`jSvHcBCT zstD-L`G>Ho@iAB^!wXhVf?wLO?=VRg;Z_~pkRwpoHTFg#A8yJM|CDArslLpGCtd{X z5S+$FO|OOmvp|}5)i;0S>i8F%LX)y`1ODk<3%}F`4koFMAMyZy9QiDxn)k#!T+P}T z0PD7i$%%R)?{J*r9=9>=|3o_e7x<&c5Jm|*0ZG>iKSahM{@N&Ob@wFlKCW?{{=v@k z+I0EvuL_M1NtJB5KU2kAbdOl>yITpoNUOeEB0l4%nC>_Kx~_bYr+b?UvR}$DpiM4! zlFch)~B4(QUIurCkmO#n}U|KFyx z!0lA09_DsZmf0f}fsIcu zHg%BSQpMd2%o}_k+ok&?DKuRfWY|4|?#8goH5*^)K^1qg2TK!YZd9`e9X9P!6zW6AX*_*3If+1ew4Qh8%r zk&y?!SObjtydLKHulmq2HHv zqzdB3ik5!ejKdG`W0SuP@=qboX2;xg>>g*BGl;VhU_S2(zXeAr7{s?ngi;EGH^Crc z6C#=N;5Ttc-8YdkI(?Wfc&+w21t7XOVGdagDS~`?KJAn2q4%WyY57xMI|hS+GR^Qw z^2wNRxJ9{d_~Ms=X=0@C(3~W`OD5}?Xgie2G~es%OVT^kd}t1cJdbt)pkd|joeKIeQ=I%oeQKrvYY&fnIVv& z3o@QZO~WY9_nMFkf9YXbB{^5j1qp?UL`Xkm1~P{11S&+903OCO+VhGwk?jVu`NnmF zK@z`X7_w@gX@M3_X%qv|K+#>0pkr=3u7$D}WV6h=N|GGSBJDRA1IGHz*CsHQk0Y>T z&%ggJTq;N|F)(Di*m}Du9cbG=Pl9eAe!@(zhTCl4Kad~1BvS%>k}aF&XFmKMZiPCf z%NX@xI4b0Nm7+T?7tvWF zBkU%nwlQBWhu}P<)Wwg&$)S=MM&%bR(lDTg%P;0oKvT=VI$n=rWx9LkJFiRTbr0H5 zgnbyYeD0e3T>Y@yP2rQ-1Ve$iYyR&|sf-l2ChGL2pAR+B9-n`gvpkY>w6D3b_5)uN zYsYmj30AN6+bEi>@(Ye*@ZC?%g!1E<1L1r*7rnhQSQk?rXE9|$6BIbi$iLa>@Wj*O zIEIa8U_29&dGj8@+)e5;{?kxurOZZhG#&yk1pw~7)<`>uBk6r2`*0_!kd}8#lW#<; zvW`1%IUF!pO%}6zKz__K5Ug&~##}sLzbnw{-Z*@>7f+D8@wil6`C-{4=(EA}#G$^N z#6`s0V+2#sUjL&i*VB{G>42lPFAF4S7tvZR!gn~y&2u?iCKFl$dS7x=ItTh4r|5my z`)Z+sX9!e192$(rGx#XvApvIlkm9n-m8P55-4MdRi`P97^l{_M;gnY#G#Y0-+gM2x ztx$q0O}gHvaqD_ATV;~;W&EM>A9C`tDTX|O<17k3)CR;zV6=ap;oAXmO!;puiv;`R zzM&wINY~uO@nVX|neswXrHsKd)~L*1ZZn_qt2ZZd?y$cLmhIqXNs53;K4Qz!3HbxG z@bt7gE3G^@j>7+~;Q$(W`UC%kJRuqoPONU^Dp1b#6P&0X8L~Pp-}nEU&uHY-^}X3e zo{ivRhfH|F>xufLKG&eyaT;-!cMQW~b7HN+(5Y~%zsNP{A}z7y@U~q#)*U-_sUIU% z{i+9q{i!Z!VxzP!%zPYXB}7^TcSc(-ln|9$pVxle$US)%6$^lElltz^k&zLyV7KPu zoC1)i=EneqJ`5*m3;Cp|5WdR>^L@O8KdbuU;BUT4+;#J26(g@_pu_z?^u18@CE)cd zEm(sVp$X8~Dk5VuN#_dJdyRWYQHeIr3ro~J%lKWs=h@@bjx0V6HedGY9kN%{vqx#M zUljJx3g@!|F0@U+*UM-6t)-r-J<81fXh_&Fk0q{7hjL4-auEIb7-tuC(774(3TdhR zC`G7Ey1SgW0c3Ec$Wr-q|2N1k zN|y$_MTaPOoS3H7(un|0yaJ(w9995GyFzS%)r|wEntb}zJ|XNpE>v;xC_`4Jl(vXG zPUav*ayiY*THf(b7yBr^^A2y9VDND-k>~PbvsS#(+~d7vMt$m0ZDT#RmUG{q%qJLT zJnHY5r97R?XsTk&v!MyV4JM+?D({6{-CDN9Doi@=fJI&GoiZ!LOEh?*O-zYa^k(bKwR> zm73B!N(<|3sOP`~HYXlwT3Z#ue&o9`*PP8gH_qrD_U4SF7SFQL&%<^0uir%&M|G*} zl=r*}(~}xm2@E^ZQ_6~>OsoR`1lg!d)bb9VQC9V&UM8rav0>}$(|zoGl%Q|LhXvy6 zeyx?1+mzcv{=0ud=jv*P$f9pYmb5;wNfyR!!_}PY>(rxo1VvB$NO-C5&_)cX6j2*F z*&^bx1V~^MzFp*j95rew%RvYI>N;V%Iv6h4UC+Idso8KnWX9Ea-?YaH(ZL)CTbDlA z*jc#Gb!2sK?SRnOOXoSw_+g^D4XeC2vt6Ri!%VPc9MT@gz9vh+DRfuJd)BTL!&wVg zrXd(9-va6yM4o1$th%}Pc&<&1Ltj$WTIVnE{H=76$Jq5@af1&E_h^+E(FWcYQ&~Nf zWr8(GQ})PCjXc3Q72Uv}U4$5@%k;^g9J(E7qB#veqN2BlvN?eiiqTm}mNe(xL0#Nz znaWbXE|FCK+U|Ld=(gN!zkG(Z@Yjv&87kPLRu!nY(M82y3|8^BgKs-TTZo118BU+~;9{ z(>oJo!~V+A+Y{p0u>4c8x7P@_hrY7&)oP502hDBJ9o;-r+M3Cq_6n?3cbOf|>%afU z3|rUU{$yW@ozFn-qp(K0(3z6YlfL7bdQ;{HIN|Vo(IYG>gSdT-Y;>^pZYL%C{0^}Z zr4#q*9oiidWdArLoI<_8e{bnSC4hi@76zzxg`d@7==1nC)GVg7GmF@$qwbwO_yD8f z_aSikZSZuW(!t_6hbvRv-K13S!|}e11Dnv5$^oIST;<@VUXzZJJv28rLk78 zqy1`=;nG1aHUQec!R9IsNiQe*K4BKEEP^Uy1EwHGMx}u?3E{&+?%}X1gV9s?&>vZ>MLIpf=XBadXT zin&j!n`1;nX)Y90xjHkb&ho{lt>OjW@&BZc$_f%xw2$JbzOiMwfR#r17%z*Gx*!c_ zt6@;pZG#>omIV_fb;OrM$?dXhn+jPmuqb=u*=*_Rf2wxrjApWFem*`c_*d-dEaAXr z`Jdh)V2)I;=qoqCo!g1hFaAo=+jHQ^5?iv5*kT6X=h7o+t42w@Ax10xlD zm92>q{>-Y>*y$6F@YA5Ihm@NVN-oFlg^uIRz`1ZdCzj=a)Tci(Snpgid4?@w`fjMb zX-v{q`$H#iH+1K{-e!kt{*P}}i_p&Fe8s&n1?l0bCJFdI!jqf7_z3O$kq{Re{}FoJ!SB@12r}?_^1NE zXf)o^b%+!l!P8o-8$rw-s14GXWe<;hk>!bZz!8$vxlvr%!8np}{l+MXafQ`yiYPna zjoKkH^c11IMQ}5dYM9c=u_5R=fsr649PXZ#$vS$En{z#J|G}u3134m$LmWD)pP$+*Sott0dH)Ix;&ke`+8)7RqENtg(7dlcVy@hV4?G6Jk53c zhP9LX2TatRYp0guI|-m@h}99qr_UoG9CbErINkDzIyf8IoSsE3Y#)YPn6|hdo*iD6 zzqnvN;}@E&kuz$1v3Jl{EcPv3>Uq+lNz-ahs)(=Qhtr?pNzXR-DWA-YV>R+$j|utJ z_`WSSovr+6lcB==bgMI?Iizpo#<9kYbM{z-Er;gp--iZzjBASU$#tWJD)B4ywL4L!(6x2ye8FfmSB19`SbYjvv;bo(~?6$MeIBYpm}if zH*{HO+W{hzV*(PGo-xUL_pHf(Jl!R?oJ=j#Xn(!``1DDNV4yV*8G_N*gVYp@|#sFUt6Nyw`@mpYDyLd2DU~ zgzPFm+W(4nNRKv>0h67S=YMf#l zdzYVV@Me9b@M|oo)6LO4XZ6HR(9wHFtTq~z!ELvk;->M7B+BeNO`=7q&I$$)g*zmHF zdsF_e=TU6PK?mFGtk2YuhcWWIPi@tsR*HUzbQ!Py(+8`Jf1yoLEBcze#EA;Pa%dh9 z1xJM0@qPJ5#>Ajn79Kj1aB;={Vn3!#BK40^by@s7r0115ghcfrE~M-NC8%q$i)Pzb zjJ1urFJ7AUfC+)`RR7xJ!N-OXaqJ!H3Du88Bum$9y!X~pz21ixr{3xE*j1Ymadn`b z_TI?yaFxi}@8jo3_o)UvxNM&Y@gW!^AJr>TG%CE^J#o`1?pynt@#fB_=ZRQypYc;& z0Y_d$`6b`C8SUnSA1Z zuDH1^{3+kdb;*F$OOH8D^wY(1GA)zJix@-=5f^Ff#*Y=tkSO(jytU3YszC4pQFS;S zFl|#AS4A=QvHD@ZdXng)QS%20Cm3RJHKuQj_-Gx@&Q0=_%%b#WZ{zj$-J_mt?pTv8dd6ht@|-4%>e6V-C5! zss*e@@$s>6&q}H_VKU80=X5O=KFJl9!E`I*Y-(IU@YH_5r|*Wtrok*h>Rq(#Ss?Ry za`k5pk+!?uG>9p{Egp@rI%GVF71SUb6jk+qre~&Mb?$*bWokA3l^pTA8DD;s>qSgk zJy(fvS)320K*3XXCk^e^`f$nLLr^C^v+!~GQO;q9v0LZyzQ5n$JF%U-5~aslYb0$E zeCeO`v0?Y$Nrxcl$5>sjpI!@)C*P+>%+z{h{zAJHt?%wyVY&oT6A|@G-8dmDu>`Jb z?gbFflMfvixj2nlUxSnQy)`%*dWGwBU=uF%;%`or73)%;Wi8xc5Mmaut}R!I1W`M8 z=*5e<;#joBUxwK4TS8q^bgpAja(Q&(BLb1WZfSV$cb1)4eAH*l*uCla#Mie!zpf`i zGb)sTD-iyD3T63xxyKXlgKNr*2-H%eT*SUB3oSA?Qlx=+?!d13JSmPQN0&eQ%(sR| zK&0;rt_7&xvxy-l>1?FY)p_^^B|2^> z<^o*G98z^+Ig0^B=lVR85a7{Pz@2(rcM5@bDGnuBWDM)N*%b5LA** z|E*qBF?QYOa5Jc`{4W7kx`L$ajp#$ZPl)2kY{8+Y=RRYM!#50iJmf{z@UM2B#O^l3 z*6G%~Co9K7$BqVB7%3oXR!vFr7BLjX%6$_3pp}&Vc3N>27BXT^8+l~=J zduICil9n=s&UUM!(xZ_WBh^WiSOLGdIqC~JdOGl+y!Ba8={;HF<&D6_an4ACHw>7? z`xQo<^ju9qi29cc`7l6m((Abwk-7yyt9i(o)c!CXS{bQ1o!|-QHUP&F_a`$d{>Qj= za+H)vxr!U#{P)GdJa|6Pg9Q@b6-AIG0OVn1cdd6K|Gx_@afMDl81mrUxG!J5DGDP? z_)lR6PW9Z;>&APEGm1q&5{WS00j(IGUG;=8=>lu&yN0QIIW99 zOEyB2a2~YAX2`vi33b6~fRk$jqxo<%+$!^Q1nQ$UaP6K-SW)M}S#gDV-=zOX;XHV+ zd3LotOurQ%B7JlrWcuNtD~Wft{&LVG!IL!jr!CIKl40rf~2hReZzrAu7FjJhF=k*6N-@+DulbZ#d#k_tPd;4edy~rewQa6Hwo{B z8UK>fljy;?Vf6!;k%Fa0Ou;G2;>olvfDvP$Te3B3{6W;D^df=Q57ibnoB!m#5H z$=6TXAqM($Wt*z`PA8wP7b^d|SN2|DIFo^7<9Iyrfw+;$ss6nImd%9{%_$p{z2;>f ztVu-QT?rKy{8%#DXMUvsM7ZZk1M}}|T@=5($PI6_CZTUm%+*NpOj7iuedstJJ(o6^ zK`5b(FHgKOsIubzI;$54&tMWP;ON+F6T$2Xd$8es^eE1@lyCe39p?&3c z*h<3%_A2|e$Nj6_pTfC>vQ(=+2K>psA%T8BaYae%Bcgastk%w(^FtWfQ#e>TibwY% zQkcNP2@8*~+K1w{_x7JMCw&wgl*xpidn`(0*K3{y=w4GMKN^mD1M>3JUlrj`^-m=AvdDiX*~D*_mGKG>BmJaR0#P{7ITKauFe zWB{?hSlXSnJTEVB%iGHmdPAn41GOQFHW(X8GxT15PlnDF@G}}I$)-L;b0!he<-*mA z(WGcP@$A3a|BvD2<3QuYpFQ%AQ$P#!Vo&}G(31d&VS<*p`EzODYJ(;pbw1pd7ZQw- zlUu4s6Tj7`>5EWN*5W3=V-#|kzFmxdp-N+3>CLAGs1wZTgT<$|`X~+1b636NU-#*S zKsWc4P|#Ier5}1nCdKkf`#vmv+l?pFuLeyf$^`#K;DV|8M+3bo0rm@%OyBF#u?5~r zE6)8=s_A^VEhftTmy+K8HTXU@0Q_Lmk6wZ2{1g?co3}s%c2Cg~KlE`2(%S0c+`Syo zkIp-3?HV}d_&SZj_YK)q0N_^MVgWxAYQ4|kJx|Wtu_dEYqvf!#xc_bPWjwm+)E_2iQUm4FSd zC(d6brf`fpz1!hQZXR3*lu3P|Rgwzb7NW;BV$CcO8I7yt?dv5Wy<$*FL2hzbFK+gk zQr)S<|HEJZu>!?9|1ZNeJWz52Ci@sHWr58h&&cN&s#{hNZgKuny-WcKm6(sx0)hiM zi!6N}M#qg%df&mJoeu66>waDA8D)!b&!a&1FF5km%f}xyoo6wXD)lmw`G@&yF9k#$7bASuk_&?plUZ{EEkeko>{pK@ zE8R@UpKm&91D_6}*bCrUan~VkxKD?C&9b+bu_m@rfe-*qj9k|$^g;;0B5gdP`d`+e zkMrc1<@#f6uegZT_P4;@(bxWSw8jSg<^@YLJDggZOFGlUhq|1z0j_&5k=G!LObfXm zhJ}M2+?Di**^6yj5gc`LIb0%Uuz?o6eXA5QY!uu_tYiUFqYx(;qt^_;hK+ z?WX!ZyS(@7mrq6YVR*Q}V*IuADVHrf`;;F8ZbR!6OD&?kyV-b__6&?ycUmX9^l6k1 z67lv~E8VoPxUj;Woa43AFoCH-c5ncwjS1eNZr<@Jv^z9PcNAucgyXU`~0 zwAQhtKF<#C-q}d9eg0>trw-pe$f0H6n=4uy@%K&K<}s;{@z&1g1(xw+n#b9v`ZbxF zh{3WS0wqFmgPVe;$$#VnTNg`Sz(mQqS-aEJIP$hW;a^U&&NKv7e>6Qr-%j)fjxM?q z#!U3~dSExQ0b2x{yk80#c-Ffc!>XhLwy&!!1}d1ED-yTU)-f^Lly6ZV^lb0Pr)w-Q z_1*bp#}V~eS7_>$h>bE3N@(vg!b*r!R!;8T=@?JKjn&Vi0&R@}4e4CiDYi@%HL~oSi^dhSOHxu2VqQhJzp8S5;mKMP z{O%G&@GcqO>hjm#j)?IZ=_z*O{-6#&f(>3LNW}zce;npTP)un0FPjozk-8z*oV_KDWC_`U>ka%6?xr5hLTELC2pq&7qRe?D6R!|9i`C8T?K5Hls z$DO2+wXJoA{7b3&RnA7sRN=nW$Gucim8H7p4F`sb-Y?Q8#g7Z8>N9nkYWx#TOlofX zE+Tx`h`rZKN8Jj06W0fu-!sb{*;mHZ=)}A>95<78-B@sLrS>8-ipRp#?~K=FEJIRY))*IZuGZ3 zB%4kL@t;IWV`leCKCF|nK-wLR6}mRlD+?oB-oi|F+n;-E{P1_|Nb9&mcFr2qqb7Rx zUbIfO*9a4bNfwEzqOt6(9ub<-1@H9{>Bf4aL_I32T(an*Uqgq}Ma z{H#bnXOQ0>MlG9{^XP-_nxip0PFQsy!j$lm&nk&K8a3ITo;GI<-p9*APFotEg*7&c zMK;@P=&fa#UVcy~-j9W1-Z5Rgl^Z>`_X!-MEtpi5%-3kB&JPwXF#vvI)>NM|rVoo) zBQIuph#%>&8zoC3Ohc;N)$z7X>|6ah`d-y`(jWpMzxw6M6y}~ zw={U1GTSJ#8N}`DoorRCP^l~WOS|9KY(KjtMJYVe=6JrbQ8>)YV%h7!XRufyHdat) z>ewUz&l2o#UHzD8v}p7%k6?Q{%^pIui`8k*uAxSuVt_$mzKy`+J#jvR!{L5?AjwG5 zT^<{2$R@c9p|xU8=H+(+@19uo?u5nZFjA(X7@K+YYEIcZ*Lm%h=}rcC)??HbeY~Q*PhuHW|C5yPTPdla5pIT}aw5-bhY9q2h z9?G8^Wq+3Fq|K%FJ@5EybN$a5PtI8^o77cVzK3j*-Ycky8aGSts>_SDI9@WLSSBG8 zb3-qSqMeBhe6GQFUvwxfJjQSPn9VBo+35@`-cD2Jq`saTJ2Lj?8RDY3!l5c4aJ8t> zpX*Or(upRU`_q}_;mK5k{4T6rHgz=hNJctIlN45eY!gE_)8g0c0{>L8`J2%wKGLetzO>f zqUw^53v~O@OF3PBbAw#aEHzo~Z|g=JWUlO<>&JchGkw)no8*Yp*oo8SJXDbS^dbZ! z++VLJ_sG6pzUK5L!eM|2^G>ysyDNMAic+$I@~AxFyU*~C^4_ek5Zm`O>;A9*=!dN* z2~{Ak&cTFFCmtpbe^X{oeS)z$pTEh_5nPTl(Z5hnR{k^a6zUX3h>bf0Lwgy6EB}j(E-2{XBMW{e%yteJWrZ+v8n|&oNJ>N3PwjTG2*Dng{2@D7u63e5*ki8$Bxx0WGW{ahU_dYo_~8Mhic2}BK5?<9)$@H^EY@fU99uEiHV#0pbh z%o#d*`*x()6F$cp&bXcU$jectES_|T`utpfzEtwOrX@#ySuT3Ee>q4@@)zB6HJa(b zho2ff!^@?UuC^K+>8K!iDW#&D0z!F+n#G#5-4oYJ`0dT3)&R0sMkmOzUw1?kWo_gW zygRx_;T_JgvyhSMYGHQYpatTdP#wyk-4Itj>@r*2v#)%{JGnqHQ6taW>UY;fjh$dn zAyxT=FdEA%b}eJPMAp}G+xkIcQF&_hy-)k!5`EwOO0FlQXkc=V-;~ua`>7o?H|{v1 zvrbUBh4N@uFtIQraXL6zWbtCaq>vj`QU7FE?J$aMK-9#M{>ul4#}pSUK1S?OgODr$ z9_~MsM#M^VQ+>sn&gf~&g3_xlexdKs(o}gEW>)7}yf>5;h*Yt(`W=`Q^a~bB8Lu@| zB5?;R-PxG6rCMlrt*87G52HF{RW}Es@@nWydy0$qF zb5ZD2!!Oz@omWeVE=6pWJR4nYuAi>|YE_XXpL%(2Rn1+mfBI=Ae_5lG5_0+H#O{$9 zqs!;>VtGa<@_imc@(qw#WYNs4JFxiJJu{&An;`$~NMF0eE`5|I4gy;0Cw#5xiHU$J z|2-je4>wloa?nP-A~&6roo~dCrL6Q!ko_DZM8boGJZq_Z_UR;r2t()7|n$5m_b}8X9(x_(259*pcKixsk=3`HmPu$P(wlCH@f^~zZ z7J^!do5J_=3=opyGHe-xZqcjlXZ0OxTJ`2Hi`lhD6)@!#T1yrh*YzdTl!{V1DLT$2~ z-D8`$0i+w`v6FG~gdV<~dh(m1NoQB72zBWvV^OVhm5gQg zOuTjb!2Y?txumh+CttcGay>M^7Kgu(QGcP3V2i;Hks=+bsfZ@+}1x zOE;JfE)9e4s3D!MoTfdOW8tvWt=aux@#qqS9%VB#A6!^xrAP+aHlI#!73Avy|07S2 z=467UE9#B6%7nYuMqM>60`0mwe$~i3n9;b5t)F~s-s;|Bn&Wdf+$Bq)PlkE^U3z~u z4z0i0>O%zQnG;vA+_13jaEkIu8q@KDww?_QH#sHcD_z#?|5DB=MSe$6yFlsQ-7$q* zc|5=2F;0f$XHc4i|MKCt4zqXA>&H9#9i*#>Ab2qqb=_aDDX{$!o!rh2FBU(hlNEsZ zA1FA^w7f|Q-jzs%COna*SNjBY01jt8Vt*^2l%`U5iH&2kBRXCS{;7pc6!&hX?q?c= zt+5NXa3*8an?~pk#C>J$Jf3Hms|I!BAZ>tu|%xxKAr7O zL8)Ue!DS@6-btR+V}0MTl$+W?D9fv)H2hW;`)_R;N_02ql#(Al7*!;k0AA1bc2v&V zfB)gu!mxovLDBOw!}+gpZ`PJFsF?Y)NF z{ZXNQmLz+$F#`z;#L+{L=cT+9{$)0oP`r&Fvt>%>w&ypoqt_3Gp=uig3vu0Qp zm!>m=aT+hdOY*)y4=C0$kUm$-L&`vgezZ%vc4t)q0}Vg(%{U`D_R;gav|va0et?Vj z2!j3GiJ$VbMW%+l)_YM`qGhxT$^vT{XS_|GBul^HfKHBWtYZ@r)x5oB~8Wax+~aC=N$Rp$CSmutJ0%2ViN_TPMV2<{ z%kS-Y8Cb5O=2=X@*Wl_}wjF&P{RGO^sC;0G>Bt*xe577t#~roKL8df-5oD#1WM6zj z6+q0pa+z!XhwtZdIzbxmvc6WgF>};nGh*XchUh^Z{ozL?Q|Q}vS+B*t_GXK$jPW2n zQ~P#nX8G&xpDlI@+5c2`Usc-xz|n3qn= zs(%&;$&AF;u9|-RZPoBvWRSz!Psdl)_P#d+COpGxZ+R>%u&UMx$+IEb=1)!55_XQ^ zB5>iQsZmwF4xJgGX-rZ*2;Ru8=<9`LQ|*5SwgAWdKQ=K^S3~VTkh z3jFI9X_I>^Y3mFtrzfKvYj3f^A~eh(JB&*Q@VEV!!)mO;6YX!`O$Kk6iI@es|5PXT zN_xTU_(sdH;ohko7MeleJ8?X94%;Ts_I?>uZse1ELDp=D_f9-`9K|pyXaF)sz7blf zYY88$amXlZhROZzstvXJg1o&dclN+0IL5aEujMBRpbttUQfM^{&K&YY2X@j=cfm^> z+rezU_J$`a@LIdt`E$R4Cyv9{TYkE0Y^MLRb=KK7s*;6VqN}rXzxksLv>!TXUvPhL09=7!FzUl!gVh z)mM8ej~B?>Ovlzg6YTKnt?$x-5BFR00JlGDR+-8zYme+3JL70eRqq0W!spJ~T1AMj znmrp}9Q-EK9x*o{W(CNH@}U`|XP&qH~?m4QBtYN%e1M+FXEo2cEM3LoSmPiCx+ zqG3584p~WV-b(r#fa4^UzjFMzun`Ec}S?zg@;*DAFsQKeXUOYbM?xlT^whg zW9SOZ_8N#lz!_A8*@3DK#nTbD%5J5Da~LU2j(%N=W0t>J4&L-TxWAv1MHJ5do8&y%JC< zc|7_$r_o$|>Ef@Y7A~FU&n&_a`+WA})AjN>=@1o<0eU@u(hFb;4T&rQ)_WzK9y>Y2 zAi!kBe|8a}vHs)YMES+8r_7^}BNN|T#i_fs07e+g4yQyo7zn=ftAA#Y1l94q4F%9Z+I!$BdZZolY`7Qj4QE- z#=xBv0nyIV>fs1Ksd1n0b#^!+nqesZiQs+S z0A~^?NI*-uzG=B~Amy+^K*J7_)g|+Hl95{*1zHvqOT?{9>HZp&CJ7+zPLiM}cVZ1T z4Renc%_~}Myr8yPf2tn*I&Nad2JhbRU1ie}=$E$aHuH)4pHw=CvOR_dEnGDIA}{gb z6`6g}5r68y4$(>j(|e~164&`2NUf+QUaV)IhRQk*kG(QtSO26?^D6Bp$hqLeyzxE7 zoF+zO|JSCCCFMBvpusRgQVg%w*3_V|c;Y;sV6rLl8;3uyjbKikLuF*R=$@CM2*On} z@a$nJIh7IQ(xm-Y`h;!7IvG^*%`5kmoOx3Tsz?T2$6EZ5UNV0PtE-W*HndH17lwWJ z&1m=y2A|k$XCIqc)gI4L-R>#%9+ZYp&N{U8r&dZ)vnZ&uATdsiCA!Npe))Lw&^H@F z#UO8gi@QfXbI^qa3I8IYN_!s(Dj-E!w5k3Jm)^obIyIAbDw8!&+|Ly zrct)-xJRYQKKAY)q&zsN!BDktpiE6t%|@E*W!v9mNbG>*~ywm zB^7Etj7maOpb?}kd)Sfl@6yju6ZNpZg1+A5KN~u=QMI`xcp0e%QYUpJEofA|@JF z@vRKQ9k%w05kvRZ(?UPhsM=o-C0E6M*H^GQnq{#xL2@pZ0~8f2wr=ojhoFbEX^f`s z%3RL2i2mr{{~r7={*jKJxHbyDz5QvMnqqQ|4hB+K4?ucpzkQ2aF7MX^Z}Ze6EC7a& zCU44mgr1uKZ+<57-1QCkp9cw*N<3f?z4v|t$_|mR&d0Ma%h-z;-+x9hy=~v>N9>rl zIe3h|I5zT0<92Q^toAD68l?C(Q5Jmrb~Iug_Ipzn>TEO^h8S}UG`)I8!%R6PH6MrH zuUE*5+R&y?M0U^ffju5B6BMQ*Z7q3N=EzGW(()fO~34V+_~w|kt{Mk-*hZ)L+N`WP!5_CU=B#3 z5{SMqaS9@OlEq0+gza?>To)17RCY^K#ljtx!s$4Omm9I#3@f*|Ue6jFU=mxjInj^w z5Ooz2v=~=Y9ipeA;@s)C7nu_~TXFq#t)AEir5Q%BI`IwomZC6y@>X7OCCJk3xaI#~ zulUpQDH*HzY{-hj?j30mGHc3#bhmu*Ws^d~Y+yGEOM_6To1g^S$Y90D^RYpOW^%(T zJ_qgzHvdXJZ{HbECf@KsRFfvu=w`fslm97l}t`3;3!ycN-Ms#t=2^Mg2)1;5okc;Tm+xMrF zWZR2eHtiX5xn0@g+LY^0=RD;C&wY}-@@9FzGK#~S3fF9iFAz5=^`CRtM!QDQAuXT9 zwIDGS2Fh{S&^A5r;hG~_AMC^@M1T4l006A6=YY*JYOVuNubI8h)f)lRg=Ec#G|{59 zuL6lfnbymzYbE=9jcFg3Oi;5_r;cD#jxIfG~8twgpBV?VrmE z^E}hBuZ4TMhNx(GRy`h1TzEn-@&FKfM4^331557kbQ^Q4j1x`Jh8~gy*gWxl!~S zkCs|~xSm5CsEsG)wiaJ%nvyY{IBq&|rDcMgf%j{$QQD@(lTmaI6%oD>?o>vLdXrKq zUWvy_OZVkv#GeusBU%Sp=zIieJFzNS+0e(J^h@apV>g~$Y+jBkq(~V>ap&V_GhZ-u z`XneJ$c&)Jqet62=HB_Qk+H;Ws@>8@IsrnIYQmC4q`XBLEAO!Gn?BtZO9qhq_ki#& z!7-G}kY+}V+Rc;md+d$|-`tDbQn35HzSmQy<59G7nq%!=QEIE*U{9?g-*X&zdlSvk z?I<71alQOc?f`i~4Vxe|(IMkaUx{=_VQG(C_rs0VnqVoYDWw2P9M{GEcaLmcd?mCn zcUTN6W((KtBvNARK8X%6v@FdLy&WuUlG_+&mu*VpXm4>MHdo#{XXmd2$mAWGK}A;k zO0dim8;F+C#bpWt>_ak3`BC{tMN4m$tQ9LI_<&Qr@7iMq0BHGnL0QGJ&KcCor= zpCa7c+(7hxL`Kq|C(_8DeDdwjl*e@DBR=43+k*+8V5)O?5k!UJOzR1PZ=}TAZws0w z6XtbYo~A-%sju#(aoG&^J6Poih=j-5w;^%0p~<{JRMk^rv9oZu96(f5Jm_=`+AHh= z^3v0!hf<-RL1V~llYy|V#vb6Jgq1yAuG!QF?w<`n6(`n2Uz+ufQ{L%8QgwzAU&9-X zLn7*|)icUFE>E^I9inY_xZfAIYr>42sJqhMxO?j{`I3cJl5<5kDbP%3u!vr$X_-0; ziJ=w3`pBD;R|lpZ-k00f?@=k>6vF45s}4$l9b^1nz9ihnNHLod7+++URgh0Fp3xsD zTI7r$$N_X7PA$QTipE)v$C zLJgW;DT|-48*G|slB1q^EB1pXCe{~V3hQfbQFrnVOlr38n6((vCKcS zb2Jp99;z;sr==-_ZO_`1`X9aROg>wYdAc2>d5-~4lHe-;1WxYhf1=s)g4tP7;k$k- zYFPkYJkg><*O`ii|0n<+3w5GSKSgrT9gz6Lf;8NhAgC}1@cV2Bd~DvzICR%4s3!4; zGCU3mGeAl0MFm#*H;U}Fx&Rn2*Ez7sg-KdE@`!CPtJhAjdS7)^2i;z6NrR*O`Z$bG zw-JhiclbNr?MnKpm0b?{hKQ@ldJ*wSZMK>$___Np+&w8VxT}leq9dA-gPs(Y%(N?e zBKNg7owm@Xl_7``uOGs|C6_}c4Y6C0>gp&qhNHU19^P!3Pz`LVD%i~BPiAM)Dzl9< zytVh^<$TtwM-4%Z)yTZ^iPUEftoYIoOmHis z;yDXH*CnMy9pTX0SxcQ4#&LC~i7}0rv5+VzALV0C5@TI=43k7|zH;g6O@KHzc>hK! z_iTQK8j~|N4{ft8TXtohNoIG)*l;4;i&1@lI@U+U)&2!GHDCE8Y`Y!2E@$MN%85J+ z5`^bRT62ZN_bn!VcItlkhE^8F8)PK=B*A_>qyCTx=UF<^7N?`*oapi3cedxJ9qm&k zS@>o79kN+X>_gd@_DLbneR&d1)g(W!a5trzOc*`+ZulC)th=$)!B|JIv^D`_2jty*P9o+@|XRg9@e6aOowFk&5 z17UJVUCeE!QW-29Bbbgwo8CiTgQ$62vub4)JeC^zC-mm_@<3CNNPM|hU-te|9!Zfj zC7=0`&yNLCxMf^F^4=-`7&KbT-S5BS@X_xmKSFuzJ!IiQ@O5!fC)*dSWE2@7LQy)K+Ehm)x6eEEr|*H?OODUtNPiJ*&?PP`tA- zz1YxJ5fa0<<1sn%o|nC+Wkg6Z)`aS-^NDH{354PlpK zg$7{E`rjp(RYqVnwS8^lF79DSNT#y=LK#g zm5Zf@I-gbgu>O;l0JM@S=PD22^Vyk||DX{$;$VQC-ah@B&?pL|tez7;Ccz*ZI^Zz-1iyf%{olfv!o9LpTR;k3%T~f3!LpnJl20^aaeO zsm=jUZ(sxO;!+JiAZjPVDM1ym`P9w6umg72U@+_)FqS&ATtNLXAV4F*LdB{SnC4{K zKDZWtYUr~Ff*S1HesIZ>cS8MDa7kN^1t!%32&?{-SR()z6g#< zm5Eh9=!E)VaA#$kJlaYKoMaVN$Np-$zSq)Iolw7Ll*-pNiS@mp%bFRtrEs2m9=>|5 zw|39NQ!bl7Xnkn7z2!a_0ilbjco-uDdgn`zKow?yeyj7kpb#o(Bo{A@Dq>I%_?GYC zDFht&l7Tr$8SW?oLN=}y4{L-ArZ-`%5l}ZE+O0(DFzzlmS$EjD`>TZ(v@nKm$lww{ z#}XE*SGXmCqpbUhTR-V)Kzo*)@U{fU+U0VmAM_bq8xRqrR~=d} z2s-}1c#7Gp&?4S~$mvWeqIUr5^nEd%z-)$7dA zKA@w|o=Yn=2Mkg$y9sUpENYx_OA-fO9ZrvDG91%Y19279mj(+5lNcW(7mZc~2Cda{ zip7Fie!|#n65KJ>{_&hQ7`k^!*(GtnekJb|V+`1*%#x6TV2X>Mn?XSh!3BoiT-vD# zK-ZzHK)3;j4`TsO2#y!%;*DV7(X{}&k_V|_1i-0CNu#HL>9_u{L~Q6M4IZBBF=ZEr zK;Ts*r_5|3&tJlDpLR`6fjM2Ug5n}0Bdv|j#qSJ)Qu2jWRi>1|@u~d0JQk%7IG6*x zBYgUk(x9e)UO@q)UDq=)-@FyLhluOkVA1D}#1qZyO8z@ru9Vf8@hLFMF6dNeGG~8( ze>hV|ZN=(Bo|*>Nxv|{^oZTp0{LX2wMXMRUWOnm0un1`oaJ*Y{sp8~pLb`9>@M|~K z! z3b~|MPayxPZ|`c|o<{ z`Tmx|=f{49X{t8}&K0ET_t-2w?&>x{aGmMzD-YH_O}cUS0fP(4SN^lD5$~^CQ0XAp vuL#?IZwdn;D%EI+X?@$k^6RN`2f4u*ufEoj05@Et0)HB6+L%`=R`>n`i#%vH diff --git a/today-s-sound/Presentation/Base/Component/ScreenMainTitle.swift b/today-s-sound/Presentation/Base/Component/ScreenMainTitle.swift index d64b248..fd1699c 100644 --- a/today-s-sound/Presentation/Base/Component/ScreenMainTitle.swift +++ b/today-s-sound/Presentation/Base/Component/ScreenMainTitle.swift @@ -1,5 +1,5 @@ // -// ScreenSection.swift +// ScreenMainTitle.swift // today-s-sound // // Created by 박지현 on 10/8/25. @@ -9,25 +9,25 @@ import SwiftUI /// 공통 타이틀 컴포넌트. 다양한 화면에서 재사용 가능 struct ScreenMainTitle: View { - let text: String - let colorScheme: ColorScheme + let text: String + let colorScheme: ColorScheme - var body: some View { - Text(text) - .font(.system(size: 28, weight: .bold)) - .foregroundColor(Color.text(colorScheme)) - .frame(maxWidth: .infinity, alignment: .leading) - .padding(.horizontal, 24) - .padding(.bottom, 16) - } + var body: some View { + Text(text) + .font(.system(size: 28, weight: .bold)) + .foregroundColor(Color.text(colorScheme)) + .frame(maxWidth: .infinity, alignment: .leading) + .padding(.horizontal, 24) + .padding(.bottom, 16) + } } struct ScreenSectionTitle_Previews: PreviewProvider { - static var previews: some View { - VStack(spacing: 16) { - ScreenMainTitle(text: "최근 알림", colorScheme: .light) - ScreenMainTitle(text: "구독 설정", colorScheme: .light) - } - .padding() + static var previews: some View { + VStack(spacing: 16) { + ScreenMainTitle(text: "최근 알림", colorScheme: .light) + ScreenMainTitle(text: "구독 설정", colorScheme: .light) } + .padding() + } } diff --git a/today-s-sound/Presentation/Base/Component/ScreenSubTitle.swift b/today-s-sound/Presentation/Base/Component/ScreenSubTitle.swift index 12dde75..5065b2d 100644 --- a/today-s-sound/Presentation/Base/Component/ScreenSubTitle.swift +++ b/today-s-sound/Presentation/Base/Component/ScreenSubTitle.swift @@ -1,5 +1,5 @@ // -// ScreenTitle.swift +// ScreenSubTitle.swift // today-s-sound // // Created by Assistant on 12/19/24. @@ -8,26 +8,24 @@ import SwiftUI struct ScreenSubTitle: View { - let text: String - let colorScheme: ColorScheme + let text: String + let colorScheme: ColorScheme - var body: some View { - Text(text) - .font(.system(size: 28, weight: .bold)) - .foregroundColor(colorScheme == .dark ? .white : .primaryGreen) - .frame(maxWidth: .infinity, alignment: .leading) - .padding(.horizontal, 24) - .padding(.bottom, 16) - } + var body: some View { + Text(text) + .font(.system(size: 28, weight: .bold)) + .foregroundColor(colorScheme == .dark ? .white : .primaryGreen) + .frame(maxWidth: .infinity, alignment: .leading) + .padding(.horizontal, 24) + .padding(.bottom, 16) + } } struct ScreenTitle_Previews: PreviewProvider { - static var previews: some View { - VStack(spacing: 0) { - ScreenSubTitle(text: "새 웹페이지 추가", colorScheme: .light) - ScreenSubTitle(text: "새 웹페이지 추가", colorScheme: .dark) - } + static var previews: some View { + VStack(spacing: 0) { + ScreenSubTitle(text: "새 웹페이지 추가", colorScheme: .light) + ScreenSubTitle(text: "새 웹페이지 추가", colorScheme: .dark) } + } } - - diff --git a/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionView.swift b/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionView.swift index f89564f..14af7a6 100644 --- a/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionView.swift +++ b/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionView.swift @@ -1,86 +1,82 @@ - import SwiftUI struct AddSubscriptionView: View { - @StateObject private var viewModel = AddSubscriptionViewModel() - @Environment(\.colorScheme) var colorScheme - @Environment(\.dismiss) var dismiss + @StateObject private var viewModel = AddSubscriptionViewModel() + @Environment(\.colorScheme) var colorScheme + @Environment(\.dismiss) var dismiss - - var body: some View { - ZStack { - Color.background(colorScheme) - .ignoresSafeArea() + var body: some View { + ZStack { + Color.background(colorScheme) + .ignoresSafeArea() - VStack(spacing: 0) { - HeaderBar(colorScheme: colorScheme, onClose: { dismiss() }) + VStack(spacing: 0) { + HeaderBar(colorScheme: colorScheme, onClose: { dismiss() }) - ScreenSubTitle(text: "새 웹페이지 추가", colorScheme: colorScheme) + ScreenSubTitle(text: "새 웹페이지 추가", colorScheme: colorScheme) - ScrollView { - VStack(spacing: 24) { - InputFieldSection( - title: "웹사이트 URL", - placeholder: "https://www.example.com", - description: "모니터링 할 웹페이지 URL을 입력하세요.", - text: $viewModel.urlText, - colorScheme: colorScheme - ) + ScrollView { + VStack(spacing: 24) { + InputFieldSection( + title: "웹사이트 URL", + placeholder: "https://www.example.com", + description: "모니터링 할 웹페이지 URL을 입력하세요.", + text: $viewModel.urlText, + colorScheme: colorScheme + ) - InputFieldSection( - title: "웹페이지 별명", - placeholder: "동국대학교 공지사항", - description: "웹 페이지를 식별할 명칭을 입력하세요.", - text: $viewModel.nameText, - colorScheme: colorScheme - ) + InputFieldSection( + title: "웹페이지 별명", + placeholder: "동국대학교 공지사항", + description: "웹 페이지를 식별할 명칭을 입력하세요.", + text: $viewModel.nameText, + colorScheme: colorScheme + ) - InputFieldSection( - title: "키워드 필터", - placeholder: "장학금, 교직, 학생회", - description: "관심 키워드가 포함된 내용을 걸러낼 필요가 있으면 입력하세요.", - text: $viewModel.keywordsText, - colorScheme: colorScheme, - additionalContent: { - AnyView( - HStack(spacing: 8) { - KeywordBadge(text: "장학금", colorScheme: colorScheme) - KeywordBadge(text: "교직부공지사항", colorScheme: colorScheme) - } - ) - } - ) + InputFieldSection( + title: "키워드 필터", + placeholder: "장학금, 교직, 학생회", + description: "관심 키워드가 포함된 내용을 걸러낼 필요가 있으면 입력하세요.", + text: $viewModel.keywordsText, + colorScheme: colorScheme, + additionalContent: { + AnyView( + HStack(spacing: 8) { + KeywordBadge(text: "장학금", colorScheme: colorScheme) + KeywordBadge(text: "교직부공지사항", colorScheme: colorScheme) + } + ) + } + ) - UrgentToggleRow(isOn: $viewModel.isUrgent, colorScheme: colorScheme) + UrgentToggleRow(isOn: $viewModel.isUrgent, colorScheme: colorScheme) - // 하단 버튼 - Button(action: { - // TODO: 등록 로직 추가 - dismiss() - }) { - Text("등록 승인 요청") - .font(.system(size: 16, weight: .semibold)) - .foregroundColor(.white) - .frame(maxWidth: .infinity) - .padding(.vertical, 16) - .background( - RoundedRectangle(cornerRadius: 12) - .fill(Color.primaryGreen90) - ) - } - } - .padding(.horizontal, 16) - .padding(.top, 8) - .padding(.bottom, 16) - } - } + // 하단 버튼 + Button(action: { + dismiss() + }) { + Text("등록 승인 요청") + .font(.system(size: 16, weight: .semibold)) + .foregroundColor(.white) + .frame(maxWidth: .infinity) + .padding(.vertical, 16) + .background( + RoundedRectangle(cornerRadius: 12) + .fill(Color.primaryGreen90) + ) } + } + .padding(.horizontal, 16) + .padding(.top, 8) + .padding(.bottom, 16) + } + } } + } } - struct AddSubscriptionView_Previews: PreviewProvider { - static var previews: some View { - AddSubscriptionView() - } + static var previews: some View { + AddSubscriptionView() + } } diff --git a/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionViewModel.swift b/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionViewModel.swift index 62e1124..f5f1a77 100644 --- a/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionViewModel.swift +++ b/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionViewModel.swift @@ -1,10 +1,9 @@ - -import Foundation import Combine +import Foundation class AddSubscriptionViewModel: ObservableObject { - @Published var urlText: String = "" - @Published var nameText: String = "" - @Published var keywordsText: String = "" - @Published var isUrgent: Bool = false + @Published var urlText: String = "" + @Published var nameText: String = "" + @Published var keywordsText: String = "" + @Published var isUrgent: Bool = false } diff --git a/today-s-sound/Presentation/Features/AddSubscription/Component/HeaderBar.swift b/today-s-sound/Presentation/Features/AddSubscription/Component/HeaderBar.swift index afca2dd..f9664a6 100644 --- a/today-s-sound/Presentation/Features/AddSubscription/Component/HeaderBar.swift +++ b/today-s-sound/Presentation/Features/AddSubscription/Component/HeaderBar.swift @@ -8,30 +8,28 @@ import SwiftUI struct HeaderBar: View { - let colorScheme: ColorScheme - let onClose: () -> Void + let colorScheme: ColorScheme + let onClose: () -> Void - var body: some View { - HStack { - Button(action: onClose) { - Image(systemName: "xmark") - .font(.title2) - .foregroundColor(Color.text(colorScheme)) - } - Spacer() - } - .padding(.horizontal, 24) - .padding(.vertical, 16) + var body: some View { + HStack { + Button(action: onClose) { + Image(systemName: "xmark") + .font(.title2) + .foregroundColor(Color.text(colorScheme)) + } + Spacer() } + .padding(.horizontal, 24) + .padding(.vertical, 16) + } } struct HeaderBar_Previews: PreviewProvider { - static var previews: some View { - VStack(spacing: 0) { - HeaderBar(colorScheme: .light, onClose: {}) - HeaderBar(colorScheme: .dark, onClose: {}) - } + static var previews: some View { + VStack(spacing: 0) { + HeaderBar(colorScheme: .light, onClose: {}) + HeaderBar(colorScheme: .dark, onClose: {}) } + } } - - diff --git a/today-s-sound/Presentation/Features/AddSubscription/Component/InputFieldSection.swift b/today-s-sound/Presentation/Features/AddSubscription/Component/InputFieldSection.swift index 07d56d4..446872b 100644 --- a/today-s-sound/Presentation/Features/AddSubscription/Component/InputFieldSection.swift +++ b/today-s-sound/Presentation/Features/AddSubscription/Component/InputFieldSection.swift @@ -8,86 +8,86 @@ import SwiftUI struct InputFieldSection: View { - let title: String - let placeholder: String - let description: String - @Binding var text: String - let colorScheme: ColorScheme - let additionalContent: (() -> AnyView)? - - init( - title: String, - placeholder: String, - description: String, - text: Binding, - colorScheme: ColorScheme, - additionalContent: (() -> AnyView)? = nil - ) { - self.title = title - self.placeholder = placeholder - self.description = description - self._text = text - self.colorScheme = colorScheme - self.additionalContent = additionalContent - } - - var body: some View { - VStack(alignment: .leading, spacing: 12) { - Text(title) - .font(.system(size: 16, weight: .semibold)) - .foregroundColor(Color.text(colorScheme)) + let title: String + let placeholder: String + let description: String + @Binding var text: String + let colorScheme: ColorScheme + let additionalContent: (() -> AnyView)? + + init( + title: String, + placeholder: String, + description: String, + text: Binding, + colorScheme: ColorScheme, + additionalContent: (() -> AnyView)? = nil + ) { + self.title = title + self.placeholder = placeholder + self.description = description + _text = text + self.colorScheme = colorScheme + self.additionalContent = additionalContent + } + + var body: some View { + VStack(alignment: .leading, spacing: 12) { + Text(title) + .font(.system(size: 16, weight: .semibold)) + .foregroundColor(Color.text(colorScheme)) // .background( // RoundedRectangle(cornerRadius: 12) // .fill(Color.secondaryBackground(colorScheme)) // ) - TextField(placeholder, text: $text) - .padding() - .background( - RoundedRectangle(cornerRadius: 12) - .fill(Color.secondaryBackground(colorScheme)) - .stroke(Color.border(colorScheme), lineWidth: 1) - ) - .foregroundColor(Color.text(colorScheme)) - - if let additionalContent = additionalContent { - additionalContent() - } + TextField(placeholder, text: $text) + .padding() + .background( + RoundedRectangle(cornerRadius: 12) + .fill(Color.secondaryBackground(colorScheme)) + .stroke(Color.border(colorScheme), lineWidth: 1) + ) + .foregroundColor(Color.text(colorScheme)) - Text(description) - .font(.system(size: 13)) - .foregroundColor(Color.secondaryText(colorScheme)) - } + if let additionalContent { + additionalContent() + } + + Text(description) + .font(.system(size: 13)) + .foregroundColor(Color.secondaryText(colorScheme)) } + } } struct InputFieldSection_Previews: PreviewProvider { - static var previews: some View { - VStack(spacing: 24) { - InputFieldSection( - title: "웹사이트 URL", - placeholder: "https://www.example.com", - description: "모니터링 할 웹페이지 URL을 입력하세요.", - text: .constant(""), - colorScheme: .light - ) - - InputFieldSection( - title: "키워드 필터", - placeholder: "장학금, 교직, 학생회", - description: "관심 키워드가 포함된 내용을 걸러낼 필요가 있으면 입력하세요.", - text: .constant(""), - colorScheme: .dark, - additionalContent: { - AnyView( - HStack(spacing: 8) { - KeywordBadge(text: "장학금", colorScheme: .dark) - KeywordBadge(text: "교직부공지사항", colorScheme: .dark) - } - ) - } - ) + static var previews: some View { + VStack(spacing: 24) { + InputFieldSection( + title: "웹사이트 URL", + placeholder: "https://www.example.com", + description: "모니터링 할 웹페이지 URL을 입력하세요.", + text: .constant(""), + colorScheme: .light + ) + + InputFieldSection( + title: "키워드 필터", + placeholder: "장학금, 교직, 학생회", + description: "관심 키워드가 포함된 내용을 걸러낼 필요가 있으면 입력하세요.", + text: .constant(""), + colorScheme: .dark, + additionalContent: { + AnyView( + HStack(spacing: 8) { + KeywordBadge(text: "장학금", colorScheme: .dark) + KeywordBadge(text: "교직부공지사항", colorScheme: .dark) + } + ) } - .padding() + ) } + .padding() + } } diff --git a/today-s-sound/Presentation/Features/AddSubscription/Component/KeywordBadge.swift b/today-s-sound/Presentation/Features/AddSubscription/Component/KeywordBadge.swift index 593b599..3aebc41 100644 --- a/today-s-sound/Presentation/Features/AddSubscription/Component/KeywordBadge.swift +++ b/today-s-sound/Presentation/Features/AddSubscription/Component/KeywordBadge.swift @@ -8,28 +8,28 @@ import SwiftUI struct KeywordBadge: View { - let text: String - let colorScheme: ColorScheme + let text: String + let colorScheme: ColorScheme - var body: some View { - Text(text) - .font(.system(size: 12, weight: .medium)) - .foregroundColor(Color.text(colorScheme)) - .padding(.horizontal, 12) - .padding(.vertical, 6) - .background( - RoundedRectangle(cornerRadius: 8) - .fill(Color.primaryGreen20) - ) - } + var body: some View { + Text(text) + .font(.system(size: 12, weight: .medium)) + .foregroundColor(Color.text(colorScheme)) + .padding(.horizontal, 12) + .padding(.vertical, 6) + .background( + RoundedRectangle(cornerRadius: 8) + .fill(Color.primaryGreen20) + ) + } } struct KeywordBadge_Previews: PreviewProvider { - static var previews: some View { - VStack(spacing: 16) { - KeywordBadge(text: "장학금", colorScheme: .light) - KeywordBadge(text: "교직부공지사항", colorScheme: .dark) - } - .padding() + static var previews: some View { + VStack(spacing: 16) { + KeywordBadge(text: "장학금", colorScheme: .light) + KeywordBadge(text: "교직부공지사항", colorScheme: .dark) } + .padding() + } } diff --git a/today-s-sound/Presentation/Features/AddSubscription/Component/UrgentToggleRow.swift b/today-s-sound/Presentation/Features/AddSubscription/Component/UrgentToggleRow.swift index b639127..4b1a99e 100644 --- a/today-s-sound/Presentation/Features/AddSubscription/Component/UrgentToggleRow.swift +++ b/today-s-sound/Presentation/Features/AddSubscription/Component/UrgentToggleRow.swift @@ -8,30 +8,28 @@ import SwiftUI struct UrgentToggleRow: View { - @Binding var isOn: Bool - let colorScheme: ColorScheme + @Binding var isOn: Bool + let colorScheme: ColorScheme - var body: some View { - HStack { - Text("긴급 알림으로 설정") - .font(.system(size: 16, weight: .semibold)) - .foregroundColor(Color.text(colorScheme)) - Spacer() - Toggle("", isOn: $isOn) - .labelsHidden() - } - .padding() + var body: some View { + HStack { + Text("긴급 알림으로 설정") + .font(.system(size: 16, weight: .semibold)) + .foregroundColor(Color.text(colorScheme)) + Spacer() + Toggle("", isOn: $isOn) + .labelsHidden() } + .padding() + } } struct UrgentToggleRow_Previews: PreviewProvider { - static var previews: some View { - VStack(spacing: 16) { - UrgentToggleRow(isOn: .constant(true), colorScheme: .light) - UrgentToggleRow(isOn: .constant(false), colorScheme: .dark) - } - .padding() + static var previews: some View { + VStack(spacing: 16) { + UrgentToggleRow(isOn: .constant(true), colorScheme: .light) + UrgentToggleRow(isOn: .constant(false), colorScheme: .dark) } + .padding() + } } - - diff --git a/today-s-sound/Presentation/Features/Main/Home/HomeView.swift b/today-s-sound/Presentation/Features/Main/Home/HomeView.swift index 5b86769..dd265fc 100644 --- a/today-s-sound/Presentation/Features/Main/Home/HomeView.swift +++ b/today-s-sound/Presentation/Features/Main/Home/HomeView.swift @@ -18,7 +18,7 @@ struct HomeView: View { .ignoresSafeArea() VStack(spacing: 0) { - Spacer() + Spacer() // 오늘의 소리 타이틀 Text("오늘의 소리") @@ -48,7 +48,7 @@ struct HomeView: View { .font(.system(size: 35, weight: .medium)) .foregroundColor(colorScheme == .dark ? .white : Color.primaryGreen90) } - + Text(String(format: "%.1f x", viewModel.playbackRate)) .font(.system(size: 48, weight: .bold)) .foregroundColor(Color.text(colorScheme)) diff --git a/today-s-sound/Presentation/Features/Main/MainView.swift b/today-s-sound/Presentation/Features/Main/MainView.swift index ada8a85..ea5e415 100644 --- a/today-s-sound/Presentation/Features/Main/MainView.swift +++ b/today-s-sound/Presentation/Features/Main/MainView.swift @@ -1,34 +1,33 @@ - import SwiftUI struct MainView: View { - @StateObject private var viewModel = MainViewModel() + @StateObject private var viewModel = MainViewModel() - var body: some View { - TabView { - HomeView() - .tabItem { - Image(systemName: "house.fill") - Text("메인") - } + var body: some View { + TabView { + HomeView() + .tabItem { + Image(systemName: "house.fill") + Text("메인") + } - NotificationListView() - .tabItem { - Image(systemName: "bell.fill") - Text("알림") - } + NotificationListView() + .tabItem { + Image(systemName: "bell.fill") + Text("알림") + } - SubscriptionListView() - .tabItem { - Image(systemName: "bookmark.fill") - Text("구독") - } + SubscriptionListView() + .tabItem { + Image(systemName: "bookmark.fill") + Text("구독") } } + } } struct MainView_Previews: PreviewProvider { - static var previews: some View { - MainView() - } + static var previews: some View { + MainView() + } } diff --git a/today-s-sound/Presentation/Features/Main/MainViewModel.swift b/today-s-sound/Presentation/Features/Main/MainViewModel.swift index 9959781..68c87e4 100644 --- a/today-s-sound/Presentation/Features/Main/MainViewModel.swift +++ b/today-s-sound/Presentation/Features/Main/MainViewModel.swift @@ -1,34 +1,33 @@ - -import Foundation import Combine +import Foundation class MainViewModel: ObservableObject { - @Published var playbackRate: Double = 1.0 - @Published var currentCategoryName: String = "동국대학교 공지사항" - @Published var recentAlerts: [Alert] = [] - - private var cancellables = Set() - - init() { - loadMockAlerts() - } - - func increaseRate() { - playbackRate = min(2.0, (playbackRate * 10 + 1).rounded() / 10) - } - - func decreaseRate() { - playbackRate = max(0.5, (playbackRate * 10 - 1).rounded() / 10) - } - - func playAlert(_ alert: Alert) { - SpeechService.shared.speak(text: alert.title) - } - - private func loadMockAlerts() { - recentAlerts = [ - Alert(id: UUID(), title: "일이삼사오육칠팔", content: "공지 내용 예시", date: Date().addingTimeInterval(-7200), isUrgent: true), - Alert(id: UUID(), title: "잡코리아 채용 공고", content: "채용 소식", date: Date().addingTimeInterval(-10800), isUrgent: false) - ] - } + @Published var playbackRate: Double = 1.0 + @Published var currentCategoryName: String = "동국대학교 공지사항" + @Published var recentAlerts: [Alert] = [] + + private var cancellables = Set() + + init() { + loadMockAlerts() + } + + func increaseRate() { + playbackRate = min(2.0, (playbackRate * 10 + 1).rounded() / 10) + } + + func decreaseRate() { + playbackRate = max(0.5, (playbackRate * 10 - 1).rounded() / 10) + } + + func playAlert(_ alert: Alert) { + SpeechService.shared.speak(text: alert.title) + } + + private func loadMockAlerts() { + recentAlerts = [ + Alert(id: UUID(), title: "일이삼사오육칠팔", content: "공지 내용 예시", date: Date().addingTimeInterval(-7200), isUrgent: true), + Alert(id: UUID(), title: "잡코리아 채용 공고", content: "채용 소식", date: Date().addingTimeInterval(-10800), isUrgent: false) + ] + } } diff --git a/today-s-sound/Presentation/Features/NotificationList/AlertCardView.swift b/today-s-sound/Presentation/Features/NotificationList/AlertCardView.swift index 7972ecd..f859322 100644 --- a/today-s-sound/Presentation/Features/NotificationList/AlertCardView.swift +++ b/today-s-sound/Presentation/Features/NotificationList/AlertCardView.swift @@ -8,95 +8,94 @@ import SwiftUI struct AlertCardView: View { - let alert: Alert - let colorScheme: ColorScheme - - private var cardColor: Color { - alert.isUrgent ? .urgentPink : .primaryGreen - } - - private var buttonBackgroundColor: Color { - Color.buttonBackground(colorScheme) - } + let alert: Alert + let colorScheme: ColorScheme + + private var cardColor: Color { + alert.isUrgent ? .urgentPink : .primaryGreen + } + + private var buttonBackgroundColor: Color { + Color.buttonBackground(colorScheme) + } + + var body: some View { + VStack(spacing: 20) { + // 상단: 타이틀과 아이콘 + HStack(alignment: .top, spacing: 12) { + Image(systemName: alert.isUrgent ? "bell.fill" : "doc.fill") + .font(.system(size: 24)) + .foregroundColor(.white) - var body: some View { - - VStack(spacing: 20) { - // 상단: 타이틀과 아이콘 - HStack(alignment: .top, spacing: 12) { - Image(systemName: alert.isUrgent ? "bell.fill" : "doc.fill") - .font(.system(size: 24)) - .foregroundColor(.white) - - VStack(alignment: .leading, spacing: 8) { - Text(alert.title) - .font(.system(size: 20, weight: .bold)) - .foregroundColor(.white) - .multilineTextAlignment(.leading) - - Text("2시간 전") - .font(.system(size: 16)) - .foregroundColor(.white.opacity(0.9)) - } - - Spacer() - } + VStack(alignment: .leading, spacing: 8) { + Text(alert.title) + .font(.system(size: 20, weight: .bold)) + .foregroundColor(.white) + .multilineTextAlignment(.leading) - // 하단: 음성으로 듣기 버튼 - Button(action: { - SpeechService.shared.speak(text: alert.title) - }) { - HStack(spacing: 8) { - Image(systemName: "speaker.wave.2.fill") - .font(.system(size: 18)) - .foregroundStyle(Color.text(colorScheme)) - Text("음성으로 듣기") - .font(.system(size: 18, weight: .semibold)) - .foregroundColor(Color.text(colorScheme)) - } - .foregroundColor(Color.buttonBackground(colorScheme)) - .frame(maxWidth: .infinity) - .padding(.vertical, 14) - .background( - RoundedRectangle(cornerRadius: 12) - .fill(buttonBackgroundColor) - ) - } + Text("2시간 전") + .font(.system(size: 16)) + .foregroundColor(.white.opacity(0.9)) } - .padding(24) + + Spacer() + } + + // 하단: 음성으로 듣기 버튼 + Button(action: { + SpeechService.shared.speak(text: alert.title) + }) { + HStack(spacing: 8) { + Image(systemName: "speaker.wave.2.fill") + .font(.system(size: 18)) + .foregroundStyle(Color.text(colorScheme)) + Text("음성으로 듣기") + .font(.system(size: 18, weight: .semibold)) + .foregroundColor(Color.text(colorScheme)) + } + .foregroundColor(Color.buttonBackground(colorScheme)) + .frame(maxWidth: .infinity) + .padding(.vertical, 14) .background( - RoundedRectangle(cornerRadius: 16) - .fill(cardColor) - .shadow(color: .black15, radius: 8, x: 0, y: 4) + RoundedRectangle(cornerRadius: 12) + .fill(buttonBackgroundColor) ) + } } + .padding(24) + .background( + RoundedRectangle(cornerRadius: 16) + .fill(cardColor) + .shadow(color: .black15, radius: 8, x: 0, y: 4) + ) + } } struct AlertCardView_Previews: PreviewProvider { - static var previews: some View { - VStack(spacing: 16) { - AlertCardView( - alert: Alert( - id: UUID(), - title: "일이삼사오육칠팔", - content: "공지 내용 예시", - date: Date().addingTimeInterval(-7200), - isUrgent: true - ), - colorScheme: .light - ) - - AlertCardView( - alert: Alert( - id: UUID(), - title: "잡코리아 채용 공고", - content: "채용 소식", - date: Date().addingTimeInterval(-10800), - isUrgent: false - ), - colorScheme: .dark - ) - } - .padding() + static var previews: some View { + VStack(spacing: 16) { + AlertCardView( + alert: Alert( + id: UUID(), + title: "일이삼사오육칠팔", + content: "공지 내용 예시", + date: Date().addingTimeInterval(-7200), + isUrgent: true + ), + colorScheme: .light + ) + + AlertCardView( + alert: Alert( + id: UUID(), + title: "잡코리아 채용 공고", + content: "채용 소식", + date: Date().addingTimeInterval(-10800), + isUrgent: false + ), + colorScheme: .dark + ) } + .padding() + } } diff --git a/today-s-sound/Presentation/Features/NotificationList/NotificationListView.swift b/today-s-sound/Presentation/Features/NotificationList/NotificationListView.swift index 91d1326..ad8ae0a 100644 --- a/today-s-sound/Presentation/Features/NotificationList/NotificationListView.swift +++ b/today-s-sound/Presentation/Features/NotificationList/NotificationListView.swift @@ -1,39 +1,37 @@ - import SwiftUI struct NotificationListView: View { - @StateObject private var viewModel = NotificationListViewModel() - @Environment(\.colorScheme) var colorScheme + @StateObject private var viewModel = NotificationListViewModel() + @Environment(\.colorScheme) var colorScheme - var body: some View { - NavigationView { - ZStack { - Color.background(colorScheme) - .ignoresSafeArea() + var body: some View { + NavigationView { + ZStack { + Color.background(colorScheme) + .ignoresSafeArea() - VStack(spacing: 0) { - Spacer() - ScreenMainTitle(text: "최근 알림", colorScheme: colorScheme) + VStack(spacing: 0) { + Spacer() + ScreenMainTitle(text: "최근 알림", colorScheme: colorScheme) - ScrollView { - VStack(spacing: 16) { - ForEach(viewModel.alerts) { alert in - AlertCardView(alert: alert, colorScheme: colorScheme) - } - } - .padding(.horizontal, 16) - .padding(.top, 8) - } - } + ScrollView { + VStack(spacing: 16) { + ForEach(viewModel.alerts) { alert in + AlertCardView(alert: alert, colorScheme: colorScheme) + } } - .navigationBarHidden(true) + .padding(.horizontal, 16) + .padding(.top, 8) + } } + } + .navigationBarHidden(true) } + } } - struct NotificationListView_Previews: PreviewProvider { - static var previews: some View { - NotificationListView() - } + static var previews: some View { + NotificationListView() + } } diff --git a/today-s-sound/Presentation/Features/NotificationList/NotificationListViewModel.swift b/today-s-sound/Presentation/Features/NotificationList/NotificationListViewModel.swift index 197947c..e6f9faf 100644 --- a/today-s-sound/Presentation/Features/NotificationList/NotificationListViewModel.swift +++ b/today-s-sound/Presentation/Features/NotificationList/NotificationListViewModel.swift @@ -1,19 +1,18 @@ - -import Foundation import Combine +import Foundation class NotificationListViewModel: ObservableObject { - @Published var alerts: [Alert] = [] + @Published var alerts: [Alert] = [] - init() { - loadMock() - } + init() { + loadMock() + } - private func loadMock() { - alerts = [ - Alert(id: UUID(), title: "일이삼사오육칠팔", content: "본문 예시", date: Date().addingTimeInterval(-7200), isUrgent: true), - Alert(id: UUID(), title: "잡코리아 채용 공고", content: "본문 예시 2", date: Date().addingTimeInterval(-10800), isUrgent: false), - Alert(id: UUID(), title: "동국대 도서관 휴관 안내", content: "본문 예시 3", date: Date().addingTimeInterval(-14400), isUrgent: true) - ] - } + private func loadMock() { + alerts = [ + Alert(id: UUID(), title: "일이삼사오육칠팔", content: "본문 예시", date: Date().addingTimeInterval(-7200), isUrgent: true), + Alert(id: UUID(), title: "잡코리아 채용 공고", content: "본문 예시 2", date: Date().addingTimeInterval(-10800), isUrgent: false), + Alert(id: UUID(), title: "동국대 도서관 휴관 안내", content: "본문 예시 3", date: Date().addingTimeInterval(-14400), isUrgent: true) + ] + } } diff --git a/today-s-sound/Presentation/Features/SubscriptionList/Component/AddSubscriptionButton.swift b/today-s-sound/Presentation/Features/SubscriptionList/Component/AddSubscriptionButton.swift index 4b45718..ca739ce 100644 --- a/today-s-sound/Presentation/Features/SubscriptionList/Component/AddSubscriptionButton.swift +++ b/today-s-sound/Presentation/Features/SubscriptionList/Component/AddSubscriptionButton.swift @@ -8,30 +8,28 @@ import SwiftUI struct AddSubscriptionButton: View { - let colorScheme: ColorScheme - let onTap: () -> Void + let colorScheme: ColorScheme + let onTap: () -> Void - var body: some View { - VStack(spacing: 12) { - Button(action: onTap) { - HStack { - Image(systemName: "plus.circle.fill") - .font(.system(size: 18)) - Text("새로운 웹페이지 추가") - .font(.system(size: 24, weight: .semibold)) - } - .foregroundColor(.white) - .frame(maxWidth: .infinity) - .padding(.vertical, 16) - .background( - RoundedRectangle(cornerRadius: 12) - .fill(Color.primaryGreen90) - ) - } + var body: some View { + VStack(spacing: 12) { + Button(action: onTap) { + HStack { + Image(systemName: "plus.circle.fill") + .font(.system(size: 18)) + Text("새로운 웹페이지 추가") + .font(.system(size: 24, weight: .semibold)) } - .padding(.horizontal, 16) - .padding(.bottom, 16) + .foregroundColor(.white) + .frame(maxWidth: .infinity) + .padding(.vertical, 16) + .background( + RoundedRectangle(cornerRadius: 12) + .fill(Color.primaryGreen90) + ) + } } + .padding(.horizontal, 16) + .padding(.bottom, 16) + } } - - diff --git a/today-s-sound/Presentation/Features/SubscriptionList/Component/EmptyStateView.swift b/today-s-sound/Presentation/Features/SubscriptionList/Component/EmptyStateView.swift index e7a9071..1004f8e 100644 --- a/today-s-sound/Presentation/Features/SubscriptionList/Component/EmptyStateView.swift +++ b/today-s-sound/Presentation/Features/SubscriptionList/Component/EmptyStateView.swift @@ -8,19 +8,17 @@ import SwiftUI struct EmptyStateView: View { - let message: String - let colorScheme: ColorScheme + let message: String + let colorScheme: ColorScheme - var body: some View { - VStack(spacing: 12) { - Image(systemName: "tray") - .font(.system(size: 40, weight: .regular)) - .foregroundColor(Color.secondaryText(colorScheme)) - Text(message) - .foregroundColor(Color.secondaryText(colorScheme)) - } - .frame(maxWidth: .infinity, maxHeight: .infinity) + var body: some View { + VStack(spacing: 12) { + Image(systemName: "tray") + .font(.system(size: 40, weight: .regular)) + .foregroundColor(Color.secondaryText(colorScheme)) + Text(message) + .foregroundColor(Color.secondaryText(colorScheme)) } + .frame(maxWidth: .infinity, maxHeight: .infinity) + } } - - diff --git a/today-s-sound/Presentation/Features/SubscriptionList/Component/StatusBadge.swift b/today-s-sound/Presentation/Features/SubscriptionList/Component/StatusBadge.swift index d7e5141..2c05c4b 100644 --- a/today-s-sound/Presentation/Features/SubscriptionList/Component/StatusBadge.swift +++ b/today-s-sound/Presentation/Features/SubscriptionList/Component/StatusBadge.swift @@ -8,28 +8,28 @@ import SwiftUI struct StatusBadge: View { - let text: String - let colorScheme: ColorScheme - - var body: some View { - Text(text) - .font(.system(size: 14, weight: .medium)) - .foregroundColor(colorScheme == .dark ? .white : .primaryGreen) - .padding(.horizontal, 8) - .padding(.vertical, 4) - .background( - RoundedRectangle(cornerRadius: 20) - .fill(Color.badgeGreen) - ) - } + let text: String + let colorScheme: ColorScheme + + var body: some View { + Text(text) + .font(.system(size: 14, weight: .medium)) + .foregroundColor(colorScheme == .dark ? .white : .primaryGreen) + .padding(.horizontal, 8) + .padding(.vertical, 4) + .background( + RoundedRectangle(cornerRadius: 20) + .fill(Color.badgeGreen) + ) + } } struct StatusBadge_Previews: PreviewProvider { - static var previews: some View { - VStack(spacing: 16) { - StatusBadge(text: "등록중", colorScheme: .light) - StatusBadge(text: "일이삼사", colorScheme: .dark) - } - .padding() + static var previews: some View { + VStack(spacing: 16) { + StatusBadge(text: "등록중", colorScheme: .light) + StatusBadge(text: "일이삼사", colorScheme: .dark) } + .padding() + } } diff --git a/today-s-sound/Presentation/Features/SubscriptionList/Component/SubscriptionCardView.swift b/today-s-sound/Presentation/Features/SubscriptionList/Component/SubscriptionCardView.swift index f994394..d0c957f 100644 --- a/today-s-sound/Presentation/Features/SubscriptionList/Component/SubscriptionCardView.swift +++ b/today-s-sound/Presentation/Features/SubscriptionList/Component/SubscriptionCardView.swift @@ -8,42 +8,40 @@ import SwiftUI struct SubscriptionCardView: View { - let subscription: Subscription - let colorScheme: ColorScheme - - var body: some View { - HStack(spacing: 12) { - VStack(alignment: .leading, spacing: 8) { - Text(subscription.name) - .font(.system(size: 20, weight: .semibold)) - .foregroundColor(Color.text(colorScheme)) - - Text(subscription.url) - .font(.system(size: 13)) - .foregroundColor(Color.secondaryText(colorScheme)) - .lineLimit(1) - - HStack(spacing: 8) { - StatusBadge(text: "등록중", colorScheme: colorScheme) - StatusBadge(text: "일이삼사", colorScheme: colorScheme) - } - } + let subscription: Subscription + let colorScheme: ColorScheme + + var body: some View { + HStack(spacing: 12) { + VStack(alignment: .leading, spacing: 8) { + Text(subscription.name) + .font(.system(size: 20, weight: .semibold)) + .foregroundColor(Color.text(colorScheme)) + + Text(subscription.url) + .font(.system(size: 13)) + .foregroundColor(Color.secondaryText(colorScheme)) + .lineLimit(1) + + HStack(spacing: 8) { + StatusBadge(text: "등록중", colorScheme: colorScheme) + StatusBadge(text: "일이삼사", colorScheme: colorScheme) + } + } - Spacer() + Spacer() - Button(action: {}) { - Image(systemName: "bell") - .font(.system(size: 40)) - .foregroundColor(.green) - } - } - .padding(16) - .background( - RoundedRectangle(cornerRadius: 12) - .fill(Color.secondaryBackground(colorScheme)) - .shadow(color: .black5, radius: 4, x: 0, y: 2) - ) + Button(action: {}) { + Image(systemName: "bell") + .font(.system(size: 40)) + .foregroundColor(.green) + } } + .padding(16) + .background( + RoundedRectangle(cornerRadius: 12) + .fill(Color.secondaryBackground(colorScheme)) + .shadow(color: .black5, radius: 4, x: 0, y: 2) + ) + } } - - diff --git a/today-s-sound/Presentation/Features/SubscriptionList/Component/SubscriptionsListSection.swift b/today-s-sound/Presentation/Features/SubscriptionList/Component/SubscriptionsListSection.swift index 26cf5bc..34846ac 100644 --- a/today-s-sound/Presentation/Features/SubscriptionList/Component/SubscriptionsListSection.swift +++ b/today-s-sound/Presentation/Features/SubscriptionList/Component/SubscriptionsListSection.swift @@ -8,24 +8,22 @@ import SwiftUI struct SubscriptionsListSection: View { - let subscriptions: [Subscription] - let colorScheme: ColorScheme + let subscriptions: [Subscription] + let colorScheme: ColorScheme - var body: some View { - if subscriptions.isEmpty { - EmptyStateView(message: "구독 중인 페이지가 없어요.", colorScheme: colorScheme) - } else { - ScrollView { - VStack(spacing: 12) { - ForEach(subscriptions) { subscription in - SubscriptionCardView(subscription: subscription, colorScheme: colorScheme) - } - } - .padding(.horizontal, 16) - .padding(.top, 8) - } + var body: some View { + if subscriptions.isEmpty { + EmptyStateView(message: "구독 중인 페이지가 없어요.", colorScheme: colorScheme) + } else { + ScrollView { + VStack(spacing: 12) { + ForEach(subscriptions) { subscription in + SubscriptionCardView(subscription: subscription, colorScheme: colorScheme) + } } + .padding(.horizontal, 16) + .padding(.top, 8) + } } + } } - - diff --git a/today-s-sound/Presentation/Features/SubscriptionList/SubscriptionListView.swift b/today-s-sound/Presentation/Features/SubscriptionList/SubscriptionListView.swift index f91a8c8..a10f7fb 100644 --- a/today-s-sound/Presentation/Features/SubscriptionList/SubscriptionListView.swift +++ b/today-s-sound/Presentation/Features/SubscriptionList/SubscriptionListView.swift @@ -1,45 +1,41 @@ - import SwiftUI - struct SubscriptionListView: View { - @StateObject private var viewModel = SubscriptionListViewModel() - @Environment(\.colorScheme) var colorScheme - @State private var showAddSubscription = false - - var body: some View { - NavigationView { - ZStack { - Color.background(colorScheme) - .ignoresSafeArea() - - VStack(alignment: .leading, spacing: 12) { - - Spacer() - ScreenMainTitle(text: "구독 설정", colorScheme: colorScheme) - ScreenSubTitle(text: "구독 중인 페이지", colorScheme: colorScheme) - - SubscriptionsListSection( - subscriptions: viewModel.subscriptions, - colorScheme: colorScheme - ) - - AddSubscriptionButton(colorScheme: colorScheme) { - showAddSubscription = true - } - } - } - .navigationBarHidden(true) - } - .sheet(isPresented: $showAddSubscription) { - AddSubscriptionView() + @StateObject private var viewModel = SubscriptionListViewModel() + @Environment(\.colorScheme) var colorScheme + @State private var showAddSubscription = false + + var body: some View { + NavigationView { + ZStack { + Color.background(colorScheme) + .ignoresSafeArea() + + VStack(alignment: .leading, spacing: 12) { + Spacer() + ScreenMainTitle(text: "구독 설정", colorScheme: colorScheme) + ScreenSubTitle(text: "구독 중인 페이지", colorScheme: colorScheme) + + SubscriptionsListSection( + subscriptions: viewModel.subscriptions, + colorScheme: colorScheme + ) + + AddSubscriptionButton(colorScheme: colorScheme) { + showAddSubscription = true + } } + } + .navigationBarHidden(true) + } + .sheet(isPresented: $showAddSubscription) { + AddSubscriptionView() } + } } - struct SubscriptionListView_Previews: PreviewProvider { - static var previews: some View { - SubscriptionListView() - } + static var previews: some View { + SubscriptionListView() + } } diff --git a/today-s-sound/Presentation/Features/SubscriptionList/SubscriptionListViewModel.swift b/today-s-sound/Presentation/Features/SubscriptionList/SubscriptionListViewModel.swift index daa2b11..c3cb4ac 100644 --- a/today-s-sound/Presentation/Features/SubscriptionList/SubscriptionListViewModel.swift +++ b/today-s-sound/Presentation/Features/SubscriptionList/SubscriptionListViewModel.swift @@ -1,18 +1,17 @@ - -import Foundation import Combine +import Foundation class SubscriptionListViewModel: ObservableObject { - @Published var subscriptions: [Subscription] = [] + @Published var subscriptions: [Subscription] = [] - init() { - loadMock() - } + init() { + loadMock() + } - private func loadMock() { - subscriptions = [ - Subscription(id: UUID(), name: "동국대학교 공지사항", url: "https://www.dongguk.edu"), - Subscription(id: UUID(), name: "네이버 연합뉴스 속보", url: "https://news.naver.com") - ] - } + private func loadMock() { + subscriptions = [ + Subscription(id: UUID(), name: "동국대학교 공지사항", url: "https://www.dongguk.edu"), + Subscription(id: UUID(), name: "네이버 연합뉴스 속보", url: "https://news.naver.com") + ] + } } diff --git a/today-s-sound/Resources/Colors.swift b/today-s-sound/Resources/Colors.swift index 92b7aa5..dc07531 100644 --- a/today-s-sound/Resources/Colors.swift +++ b/today-s-sound/Resources/Colors.swift @@ -8,67 +8,70 @@ import SwiftUI // MARK: - Brand Colors + extension Color { - /// 메인 브랜드 그린 색상 (Primary Green) - static let primaryGreen = Color(red: 0 / 255, green: 223 / 255, blue: 119 / 255) - - /// 긴급 알림 핑크 색상 (Urgent Pink) - static let urgentPink = Color(red: 1.0, green: 0.298, blue: 0.729, opacity: 1.0) - - /// 배지 배경 그린 색상 (Badge Background Green) - static let badgeGreen = Color(red: 52 / 255, green: 199 / 255, blue: 89 / 255, opacity: 0.16) - - /// 카드 그레이 색상 (Card Grey) - static let cardGrey = Color(red: 245 / 255, green: 245 / 255, blue: 245 / 255) + /// 메인 브랜드 그린 색상 (Primary Green) + static let primaryGreen = Color(red: 0 / 255, green: 223 / 255, blue: 119 / 255) + + /// 긴급 알림 핑크 색상 (Urgent Pink) + static let urgentPink = Color(red: 1.0, green: 0.298, blue: 0.729, opacity: 1.0) + + /// 배지 배경 그린 색상 (Badge Background Green) + static let badgeGreen = Color(red: 52 / 255, green: 199 / 255, blue: 89 / 255, opacity: 0.16) + + /// 카드 그레이 색상 (Card Grey) + static let cardGrey = Color(red: 245 / 255, green: 245 / 255, blue: 245 / 255) } // MARK: - Semantic Colors + extension Color { - /// 배경색 (다크모드 대응) - static func background(_ colorScheme: ColorScheme) -> Color { - colorScheme == .dark ? .black : .white - } - - /// 보조 배경색 (다크모드 대응) - static func secondaryBackground(_ colorScheme: ColorScheme) -> Color { - colorScheme == .dark ? Color(white: 0.15) : Color(white: 0.95) - } - - /// 텍스트 색상 (다크모드 대응) - static func text(_ colorScheme: ColorScheme) -> Color { - colorScheme == .dark ? .white : .black - } - - /// 보조 텍스트 색상 (다크모드 대응) - static func secondaryText(_ colorScheme: ColorScheme) -> Color { - colorScheme == .dark ? .white.opacity(0.6) : .black.opacity(0.6) - } - - /// 테두리 색상 (다크모드 대응) - static func border(_ colorScheme: ColorScheme) -> Color { - colorScheme == .dark ? .white.opacity(0.2) : .gray.opacity(0.3) - } - - /// 버튼 배경색 (다크모드 대응) - static func buttonBackground(_ colorScheme: ColorScheme) -> Color { - colorScheme == .dark ? .black : .white - } + /// 배경색 (다크모드 대응) + static func background(_ colorScheme: ColorScheme) -> Color { + colorScheme == .dark ? .black : .white + } + + /// 보조 배경색 (다크모드 대응) + static func secondaryBackground(_ colorScheme: ColorScheme) -> Color { + colorScheme == .dark ? Color(white: 0.15) : Color(white: 0.95) + } + + /// 텍스트 색상 (다크모드 대응) + static func text(_ colorScheme: ColorScheme) -> Color { + colorScheme == .dark ? .white : .black + } + + /// 보조 텍스트 색상 (다크모드 대응) + static func secondaryText(_ colorScheme: ColorScheme) -> Color { + colorScheme == .dark ? .white.opacity(0.6) : .black.opacity(0.6) + } + + /// 테두리 색상 (다크모드 대응) + static func border(_ colorScheme: ColorScheme) -> Color { + colorScheme == .dark ? .white.opacity(0.2) : .gray.opacity(0.3) + } + + /// 버튼 배경색 (다크모드 대응) + static func buttonBackground(_ colorScheme: ColorScheme) -> Color { + colorScheme == .dark ? .black : .white + } } // MARK: - Opacity Variants + extension Color { - /// Primary Green with 90% opacity - static let primaryGreen90 = Color.primaryGreen.opacity(0.9) - - /// Primary Green with 20% opacity - static let primaryGreen20 = Color.primaryGreen.opacity(0.2) - - /// Black with 15% opacity - static let black15 = Color.black.opacity(0.15) - - /// Black with 25% opacity - static let black25 = Color.black.opacity(0.25) - - /// Black with 5% opacity - static let black5 = Color.black.opacity(0.05) + /// Primary Green with 90% opacity + static let primaryGreen90 = Color.primaryGreen.opacity(0.9) + + /// Primary Green with 20% opacity + static let primaryGreen20 = Color.primaryGreen.opacity(0.2) + + /// Black with 15% opacity + static let black15 = Color.black.opacity(0.15) + + /// Black with 25% opacity + static let black25 = Color.black.opacity(0.25) + + /// Black with 5% opacity + static let black5 = Color.black.opacity(0.05) } From 6e77b19070f7f8cf179a9877a45c9d759e6a484a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=A7=80=ED=98=84?= <102128060+wlgusqkr@users.noreply.github.com> Date: Tue, 28 Oct 2025 20:06:25 +0900 Subject: [PATCH 10/13] commit --- .swiftlint.yml | 14 +-- today-s-sound/Core/Auth/UserSession.swift | 14 +++ today-s-sound/Core/Network/APIService.swift | 71 ------------ .../Core/Network/APITargetType.swift | 15 +++ today-s-sound/Core/Network/Config.swift | 10 ++ .../Network/Provider/AuthInterceptor.swift | 108 ++++++++++++++++++ .../Core/Network/Provider/NetworkKit.swift | 14 +++ .../Core/Network/Service/APIService.swift | 44 +++++++ .../Core/Network/Targets/AnonymousAPI.swift | 29 +++++ .../Core/Network/Targets/AuthAPITarget.swift | 39 +++++++ today-s-sound/Data/Models/AnonymousUser.swift | 17 +++ .../PostsDemo/AnonymousTestView.swift | 70 ++++++++++++ 12 files changed, 361 insertions(+), 84 deletions(-) create mode 100644 today-s-sound/Core/Auth/UserSession.swift delete mode 100644 today-s-sound/Core/Network/APIService.swift create mode 100644 today-s-sound/Core/Network/APITargetType.swift create mode 100644 today-s-sound/Core/Network/Config.swift create mode 100644 today-s-sound/Core/Network/Provider/AuthInterceptor.swift create mode 100644 today-s-sound/Core/Network/Provider/NetworkKit.swift create mode 100644 today-s-sound/Core/Network/Service/APIService.swift create mode 100644 today-s-sound/Core/Network/Targets/AnonymousAPI.swift create mode 100644 today-s-sound/Core/Network/Targets/AuthAPITarget.swift create mode 100644 today-s-sound/Data/Models/AnonymousUser.swift create mode 100644 today-s-sound/Presentation/Features/PostsDemo/AnonymousTestView.swift diff --git a/.swiftlint.yml b/.swiftlint.yml index 3135983..3f8e0d8 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -1,13 +1 @@ -disabled_rules: - - line_length - - trailing_whitespace - - multiple_closures_with_trailing_closure - - todo -included: - - today-s-sound - - Tests -excluded: - - Pods - - Carthage - - DerivedData -reporter: "xcode" +데 \ No newline at end of file diff --git a/today-s-sound/Core/Auth/UserSession.swift b/today-s-sound/Core/Auth/UserSession.swift new file mode 100644 index 0000000..3b1fd44 --- /dev/null +++ b/today-s-sound/Core/Auth/UserSession.swift @@ -0,0 +1,14 @@ +import Foundation + +final class UserSession: ObservableObject { + @Published var accessToken: String = "" + @Published var refreshToken: String = "" + @Published var autoLogin: Bool = true + + func clear() { + accessToken = "" + refreshToken = "" + } +} + + diff --git a/today-s-sound/Core/Network/APIService.swift b/today-s-sound/Core/Network/APIService.swift deleted file mode 100644 index 4236ea5..0000000 --- a/today-s-sound/Core/Network/APIService.swift +++ /dev/null @@ -1,71 +0,0 @@ -import Combine -import CombineMoya -import Foundation -import Moya - -// Example TargetType - replace with actual API endpoints -enum TodaySoundAPI { - case fetchContent(id: String) -} - -extension TodaySoundAPI: TargetType { - var baseURL: URL { URL(string: "https://your-api-url.com")! } - - var path: String { - switch self { - case let .fetchContent(id): - "/content/\(id)" - } - } - - var method: Moya.Method { - switch self { - case .fetchContent: - .get - } - } - - var task: Task { - switch self { - case .fetchContent: - .requestPlain - } - } - - var headers: [String: String]? { - ["Content-type": "application/json"] - } -} - -protocol APIServiceType { - func request(_ target: TodaySoundAPI) -> AnyPublisher -} - -class APIService: APIServiceType { - private let provider: MoyaProvider - - init(provider: MoyaProvider = MoyaProvider()) { - self.provider = provider - } - - func request(_ target: TodaySoundAPI) -> AnyPublisher { - provider.requestPublisher(target) - .tryMap { response -> Data in - guard (200 ... 299).contains(response.statusCode) else { - throw NetworkError.serverError(statusCode: response.statusCode) - } - return response.data - } - .decode(type: T.self, decoder: JSONDecoder()) - .mapError { error -> NetworkError in - if let networkError = error as? NetworkError { - return networkError - } else if error is DecodingError { - return .decodingFailed(error) - } else { - return .requestFailed(error) - } - } - .eraseToAnyPublisher() - } -} diff --git a/today-s-sound/Core/Network/APITargetType.swift b/today-s-sound/Core/Network/APITargetType.swift new file mode 100644 index 0000000..e80a60f --- /dev/null +++ b/today-s-sound/Core/Network/APITargetType.swift @@ -0,0 +1,15 @@ +import Foundation +import Moya + +protocol APITargetType: TargetType {} + +extension APITargetType { + var baseURL: URL { + guard let url = URL(string: Config.baseURL) else { + fatalError("Invalid Base URL") + } + return url + } +} + + diff --git a/today-s-sound/Core/Network/Config.swift b/today-s-sound/Core/Network/Config.swift new file mode 100644 index 0000000..492e6c4 --- /dev/null +++ b/today-s-sound/Core/Network/Config.swift @@ -0,0 +1,10 @@ +import Foundation + +enum Config { + static var baseURL: String { + // TODO: 환경에 맞게 교체 (예: Debug/Release 분기) + return "https://your-api-url.com" + } +} + + diff --git a/today-s-sound/Core/Network/Provider/AuthInterceptor.swift b/today-s-sound/Core/Network/Provider/AuthInterceptor.swift new file mode 100644 index 0000000..87e7f2d --- /dev/null +++ b/today-s-sound/Core/Network/Provider/AuthInterceptor.swift @@ -0,0 +1,108 @@ +import Foundation +import Alamofire +import Moya + +final class AuthInterceptor: RequestInterceptor { + private let userSession: UserSession + + private lazy var refreshProvider: MoyaProvider = { + let session = Session(configuration: .default) // no interceptor + return MoyaProvider(session: session) + }() + + private var isRefreshing = false + private var waiting: [(RetryResult) -> Void] = [] + private let lock = NSLock() + + init(userSession: UserSession) { self.userSession = userSession } + + func adapt(_ urlRequest: URLRequest, + for session: Session, + completion: @escaping (Result) -> Void) { + var req = urlRequest + let path = req.url?.path ?? "" + + let bypass: Set = [ + "/api/auth/login", + "/api/auth/refresh" + ] + + if bypass.contains(path) { + if req.value(forHTTPHeaderField: "Authorization") != nil { + req.setValue(nil, forHTTPHeaderField: "Authorization") + } + return completion(.success(req)) + } + + if !userSession.accessToken.isEmpty { + req.setValue("Bearer \(userSession.accessToken)", forHTTPHeaderField: "Authorization") + } + completion(.success(req)) + } + + func retry(_ request: Request, + for session: Session, + dueTo error: Error, + completion: @escaping (RetryResult) -> Void) { + + let path = request.request?.url?.path ?? "nil" + let status = request.response?.statusCode ?? -1 + + if path == "/api/auth/refresh" { + completion(.doNotRetry); return + } + + guard status == 401 || status == 403 || status == 419 else { + completion(.doNotRetry); return + } + + guard userSession.autoLogin, !userSession.refreshToken.isEmpty else { + DispatchQueue.main.async { self.userSession.clear() } + completion(.doNotRetry) + return + } + + lock.lock() + if isRefreshing { + waiting.append(completion) + lock.unlock() + return + } + isRefreshing = true + waiting.append(completion) + lock.unlock() + + refreshProvider.request(.refresh(refreshToken: userSession.refreshToken)) { [weak self] result in + guard let self else { return } + var queuedResult: RetryResult = .doNotRetry + + switch result { + case .success(let res): + if (200..<300).contains(res.statusCode), + let dto = try? JSONDecoder().decode(RefreshResponseDTO.self, from: res.data), + dto.isSuccess, let data = dto.data { + DispatchQueue.main.async { + self.userSession.accessToken = data.accessToken + self.userSession.refreshToken = data.refreshToken + } + queuedResult = .retry + } else { + DispatchQueue.main.async { self.userSession.clear() } + } + + case .failure: + DispatchQueue.main.async { self.userSession.clear() } + } + + self.lock.lock() + let queued = self.waiting + self.waiting.removeAll() + self.isRefreshing = false + self.lock.unlock() + + queued.forEach { $0(queuedResult) } + } + } +} + + diff --git a/today-s-sound/Core/Network/Provider/NetworkKit.swift b/today-s-sound/Core/Network/Provider/NetworkKit.swift new file mode 100644 index 0000000..68d70dc --- /dev/null +++ b/today-s-sound/Core/Network/Provider/NetworkKit.swift @@ -0,0 +1,14 @@ +import Foundation +import Moya +import Alamofire + +enum NetworkKit { + static func provider(userSession: UserSession, + plugins: [PluginType] = []) -> MoyaProvider { + let interceptor = AuthInterceptor(userSession: userSession) + let session = Session(interceptor: interceptor) + return MoyaProvider(session: session, plugins: plugins) + } +} + + diff --git a/today-s-sound/Core/Network/Service/APIService.swift b/today-s-sound/Core/Network/Service/APIService.swift new file mode 100644 index 0000000..756c299 --- /dev/null +++ b/today-s-sound/Core/Network/Service/APIService.swift @@ -0,0 +1,44 @@ +import Combine +import CombineMoya +import Foundation +import Moya + +protocol APIServiceType { + func request(_ target: Target) -> AnyPublisher + func createAnonymous(deviceSecret: String) -> AnyPublisher +} + +class APIService: APIServiceType { + private let anonymousProvider: MoyaProvider + + init(userSession: UserSession = UserSession()) { + self.anonymousProvider = NetworkKit.provider(userSession: userSession) + } + + func request(_ target: Target) -> AnyPublisher { + Fail(error: .requestFailed(NSError(domain: "NotImplemented", code: -1))).eraseToAnyPublisher() + } + + func createAnonymous(deviceSecret: String) -> AnyPublisher { + anonymousProvider.requestPublisher(.createAnonymous(deviceSecret: deviceSecret)) + .tryMap { response -> Data in + guard (200 ... 299).contains(response.statusCode) else { + throw NetworkError.serverError(statusCode: response.statusCode) + } + return response.data + } + .decode(type: AnonymousUserResponse.self, decoder: JSONDecoder()) + .mapError { error -> NetworkError in + if let networkError = error as? NetworkError { + return networkError + } else if error is DecodingError { + return .decodingFailed(error) + } else { + return .requestFailed(error) + } + } + .eraseToAnyPublisher() + } +} + + diff --git a/today-s-sound/Core/Network/Targets/AnonymousAPI.swift b/today-s-sound/Core/Network/Targets/AnonymousAPI.swift new file mode 100644 index 0000000..1f53c64 --- /dev/null +++ b/today-s-sound/Core/Network/Targets/AnonymousAPI.swift @@ -0,0 +1,29 @@ +import Foundation +import Moya + +enum AnonymousAPI { + case createAnonymous(deviceSecret: String) +} + +extension AnonymousAPI: APITargetType { + + var path: String { + switch self { + case .createAnonymous: + return "/api/users/anonymous" + } + } + + var method: Moya.Method { .post } + + var task: Task { + switch self { + case let .createAnonymous(deviceSecret): + return .requestParameters(parameters: ["deviceSecret": deviceSecret], encoding: JSONEncoding.default) + } + } + + var headers: [String : String]? { ["Content-Type": "application/json"] } +} + + diff --git a/today-s-sound/Core/Network/Targets/AuthAPITarget.swift b/today-s-sound/Core/Network/Targets/AuthAPITarget.swift new file mode 100644 index 0000000..8630db0 --- /dev/null +++ b/today-s-sound/Core/Network/Targets/AuthAPITarget.swift @@ -0,0 +1,39 @@ +import Foundation +import Moya + +enum AuthAPITarget { + case refresh(refreshToken: String) +} + +extension AuthAPITarget: APITargetType { + + var path: String { + switch self { + case .refresh: + return "/api/auth/refresh" + } + } + + var method: Moya.Method { .post } + + var task: Task { + switch self { + case let .refresh(rt): + return .requestParameters(parameters: ["refreshToken": rt], encoding: JSONEncoding.default) + } + } + + var headers: [String : String]? { ["Content-Type": "application/json"] } +} + +struct RefreshResponseDTO: Codable { + let isSuccess: Bool + let data: RefreshTokensDTO? +} + +struct RefreshTokensDTO: Codable { + let accessToken: String + let refreshToken: String +} + + diff --git a/today-s-sound/Data/Models/AnonymousUser.swift b/today-s-sound/Data/Models/AnonymousUser.swift new file mode 100644 index 0000000..8cd60e4 --- /dev/null +++ b/today-s-sound/Data/Models/AnonymousUser.swift @@ -0,0 +1,17 @@ +import Foundation + +struct AnonymousUserResponse: Codable { + let errorCode: Int? + let message: String + let result: AnonymousUserResult +} + +struct AnonymousUserResult: Codable { + let userId: String + + enum CodingKeys: String, CodingKey { + case userId = "user_id" + } +} + + diff --git a/today-s-sound/Presentation/Features/PostsDemo/AnonymousTestView.swift b/today-s-sound/Presentation/Features/PostsDemo/AnonymousTestView.swift new file mode 100644 index 0000000..5aa5828 --- /dev/null +++ b/today-s-sound/Presentation/Features/PostsDemo/AnonymousTestView.swift @@ -0,0 +1,70 @@ +import SwiftUI +import Combine + +final class AnonymousTestViewModel: ObservableObject { + @Published var deviceSecret: String = UUID().uuidString + @Published var userId: String = "" + @Published var log: String = "" + + private let api = APIService() + private var cancellables: Set = [] + + func createAnonymous() { + log = "요청 중..." + api.createAnonymous(deviceSecret: deviceSecret) + .receive(on: DispatchQueue.main) + .sink { [weak self] completion in + switch completion { + case .finished: + break + case let .failure(error): + self?.log = "실패: \(error)" + } + } receiveValue: { [weak self] response in + self?.userId = response.result.userId + self?.log = "성공: user_id=\(response.result.userId)" + } + .store(in: &cancellables) + } +} + +struct AnonymousTestView: View { + @StateObject private var vm = AnonymousTestViewModel() + + var body: some View { + Form { + Section(header: Text("디바이스 시크릿")) { + TextField("deviceSecret", text: $vm.deviceSecret) + .textInputAutocapitalization(.never) + .autocorrectionDisabled() + } + Section(header: Text("동작")) { + Button("익명 사용자 생성") { + vm.createAnonymous() + } + } + if !vm.userId.isEmpty { + Section(header: Text("결과 user_id")) { + Text(vm.userId) + .font(.system(.body, design: .monospaced)) + } + } + Section(header: Text("로그")) { + Text(vm.log) + .font(.footnote) + .foregroundColor(.gray) + } + } + .navigationTitle("익명 생성 테스트") + } +} + +#if DEBUG +struct AnonymousTestView_Previews: PreviewProvider { + static var previews: some View { + NavigationView { AnonymousTestView() } + } +} +#endif + + From e3a5f8311bce0c8a9153dc59f09731154f5d1dc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=A7=80=ED=98=84?= <102128060+wlgusqkr@users.noreply.github.com> Date: Tue, 28 Oct 2025 20:09:07 +0900 Subject: [PATCH 11/13] fix:lint --- today-s-sound/Core/Auth/UserSession.swift | 2 -- .../Core/Network/APITargetType.swift | 2 -- today-s-sound/Core/Network/Config.swift | 4 +-- .../Network/Provider/AuthInterceptor.swift | 28 +++++++++---------- .../Core/Network/Provider/NetworkKit.swift | 7 ++--- .../Core/Network/Service/APIService.swift | 8 ++---- .../Core/Network/Targets/AnonymousAPI.swift | 9 ++---- .../Core/Network/Targets/AuthAPITarget.swift | 9 ++---- today-s-sound/Data/Models/AnonymousUser.swift | 2 -- .../PostsDemo/AnonymousTestView.swift | 12 ++++---- 10 files changed, 32 insertions(+), 51 deletions(-) diff --git a/today-s-sound/Core/Auth/UserSession.swift b/today-s-sound/Core/Auth/UserSession.swift index 3b1fd44..f00458c 100644 --- a/today-s-sound/Core/Auth/UserSession.swift +++ b/today-s-sound/Core/Auth/UserSession.swift @@ -10,5 +10,3 @@ final class UserSession: ObservableObject { refreshToken = "" } } - - diff --git a/today-s-sound/Core/Network/APITargetType.swift b/today-s-sound/Core/Network/APITargetType.swift index e80a60f..f5f1f64 100644 --- a/today-s-sound/Core/Network/APITargetType.swift +++ b/today-s-sound/Core/Network/APITargetType.swift @@ -11,5 +11,3 @@ extension APITargetType { return url } } - - diff --git a/today-s-sound/Core/Network/Config.swift b/today-s-sound/Core/Network/Config.swift index 492e6c4..7170346 100644 --- a/today-s-sound/Core/Network/Config.swift +++ b/today-s-sound/Core/Network/Config.swift @@ -3,8 +3,6 @@ import Foundation enum Config { static var baseURL: String { // TODO: 환경에 맞게 교체 (예: Debug/Release 분기) - return "https://your-api-url.com" + "https://your-api-url.com" } } - - diff --git a/today-s-sound/Core/Network/Provider/AuthInterceptor.swift b/today-s-sound/Core/Network/Provider/AuthInterceptor.swift index 87e7f2d..4048a34 100644 --- a/today-s-sound/Core/Network/Provider/AuthInterceptor.swift +++ b/today-s-sound/Core/Network/Provider/AuthInterceptor.swift @@ -1,5 +1,5 @@ -import Foundation import Alamofire +import Foundation import Moya final class AuthInterceptor: RequestInterceptor { @@ -18,7 +18,8 @@ final class AuthInterceptor: RequestInterceptor { func adapt(_ urlRequest: URLRequest, for session: Session, - completion: @escaping (Result) -> Void) { + completion: @escaping (Result) -> Void) + { var req = urlRequest let path = req.url?.path ?? "" @@ -43,8 +44,8 @@ final class AuthInterceptor: RequestInterceptor { func retry(_ request: Request, for session: Session, dueTo error: Error, - completion: @escaping (RetryResult) -> Void) { - + completion: @escaping (RetryResult) -> Void) + { let path = request.request?.url?.path ?? "nil" let status = request.response?.statusCode ?? -1 @@ -77,10 +78,11 @@ final class AuthInterceptor: RequestInterceptor { var queuedResult: RetryResult = .doNotRetry switch result { - case .success(let res): - if (200..<300).contains(res.statusCode), + case let .success(res): + if (200 ..< 300).contains(res.statusCode), let dto = try? JSONDecoder().decode(RefreshResponseDTO.self, from: res.data), - dto.isSuccess, let data = dto.data { + dto.isSuccess, let data = dto.data + { DispatchQueue.main.async { self.userSession.accessToken = data.accessToken self.userSession.refreshToken = data.refreshToken @@ -94,15 +96,13 @@ final class AuthInterceptor: RequestInterceptor { DispatchQueue.main.async { self.userSession.clear() } } - self.lock.lock() - let queued = self.waiting - self.waiting.removeAll() - self.isRefreshing = false - self.lock.unlock() + lock.lock() + let queued = waiting + waiting.removeAll() + isRefreshing = false + lock.unlock() queued.forEach { $0(queuedResult) } } } } - - diff --git a/today-s-sound/Core/Network/Provider/NetworkKit.swift b/today-s-sound/Core/Network/Provider/NetworkKit.swift index 68d70dc..d1fbe67 100644 --- a/today-s-sound/Core/Network/Provider/NetworkKit.swift +++ b/today-s-sound/Core/Network/Provider/NetworkKit.swift @@ -1,14 +1,13 @@ +import Alamofire import Foundation import Moya -import Alamofire enum NetworkKit { static func provider(userSession: UserSession, - plugins: [PluginType] = []) -> MoyaProvider { + plugins: [PluginType] = []) -> MoyaProvider + { let interceptor = AuthInterceptor(userSession: userSession) let session = Session(interceptor: interceptor) return MoyaProvider(session: session, plugins: plugins) } } - - diff --git a/today-s-sound/Core/Network/Service/APIService.swift b/today-s-sound/Core/Network/Service/APIService.swift index 756c299..40ae6c7 100644 --- a/today-s-sound/Core/Network/Service/APIService.swift +++ b/today-s-sound/Core/Network/Service/APIService.swift @@ -4,7 +4,7 @@ import Foundation import Moya protocol APIServiceType { - func request(_ target: Target) -> AnyPublisher + func request(_ target: some TargetType) -> AnyPublisher func createAnonymous(deviceSecret: String) -> AnyPublisher } @@ -12,10 +12,10 @@ class APIService: APIServiceType { private let anonymousProvider: MoyaProvider init(userSession: UserSession = UserSession()) { - self.anonymousProvider = NetworkKit.provider(userSession: userSession) + anonymousProvider = NetworkKit.provider(userSession: userSession) } - func request(_ target: Target) -> AnyPublisher { + func request(_ target: some TargetType) -> AnyPublisher { Fail(error: .requestFailed(NSError(domain: "NotImplemented", code: -1))).eraseToAnyPublisher() } @@ -40,5 +40,3 @@ class APIService: APIServiceType { .eraseToAnyPublisher() } } - - diff --git a/today-s-sound/Core/Network/Targets/AnonymousAPI.swift b/today-s-sound/Core/Network/Targets/AnonymousAPI.swift index 1f53c64..89ffc07 100644 --- a/today-s-sound/Core/Network/Targets/AnonymousAPI.swift +++ b/today-s-sound/Core/Network/Targets/AnonymousAPI.swift @@ -6,11 +6,10 @@ enum AnonymousAPI { } extension AnonymousAPI: APITargetType { - var path: String { switch self { case .createAnonymous: - return "/api/users/anonymous" + "/api/users/anonymous" } } @@ -19,11 +18,9 @@ extension AnonymousAPI: APITargetType { var task: Task { switch self { case let .createAnonymous(deviceSecret): - return .requestParameters(parameters: ["deviceSecret": deviceSecret], encoding: JSONEncoding.default) + .requestParameters(parameters: ["deviceSecret": deviceSecret], encoding: JSONEncoding.default) } } - var headers: [String : String]? { ["Content-Type": "application/json"] } + var headers: [String: String]? { ["Content-Type": "application/json"] } } - - diff --git a/today-s-sound/Core/Network/Targets/AuthAPITarget.swift b/today-s-sound/Core/Network/Targets/AuthAPITarget.swift index 8630db0..638b480 100644 --- a/today-s-sound/Core/Network/Targets/AuthAPITarget.swift +++ b/today-s-sound/Core/Network/Targets/AuthAPITarget.swift @@ -6,11 +6,10 @@ enum AuthAPITarget { } extension AuthAPITarget: APITargetType { - var path: String { switch self { case .refresh: - return "/api/auth/refresh" + "/api/auth/refresh" } } @@ -19,11 +18,11 @@ extension AuthAPITarget: APITargetType { var task: Task { switch self { case let .refresh(rt): - return .requestParameters(parameters: ["refreshToken": rt], encoding: JSONEncoding.default) + .requestParameters(parameters: ["refreshToken": rt], encoding: JSONEncoding.default) } } - var headers: [String : String]? { ["Content-Type": "application/json"] } + var headers: [String: String]? { ["Content-Type": "application/json"] } } struct RefreshResponseDTO: Codable { @@ -35,5 +34,3 @@ struct RefreshTokensDTO: Codable { let accessToken: String let refreshToken: String } - - diff --git a/today-s-sound/Data/Models/AnonymousUser.swift b/today-s-sound/Data/Models/AnonymousUser.swift index 8cd60e4..a55ed57 100644 --- a/today-s-sound/Data/Models/AnonymousUser.swift +++ b/today-s-sound/Data/Models/AnonymousUser.swift @@ -13,5 +13,3 @@ struct AnonymousUserResult: Codable { case userId = "user_id" } } - - diff --git a/today-s-sound/Presentation/Features/PostsDemo/AnonymousTestView.swift b/today-s-sound/Presentation/Features/PostsDemo/AnonymousTestView.swift index 5aa5828..be4f4b4 100644 --- a/today-s-sound/Presentation/Features/PostsDemo/AnonymousTestView.swift +++ b/today-s-sound/Presentation/Features/PostsDemo/AnonymousTestView.swift @@ -1,5 +1,5 @@ -import SwiftUI import Combine +import SwiftUI final class AnonymousTestViewModel: ObservableObject { @Published var deviceSecret: String = UUID().uuidString @@ -60,11 +60,9 @@ struct AnonymousTestView: View { } #if DEBUG -struct AnonymousTestView_Previews: PreviewProvider { - static var previews: some View { - NavigationView { AnonymousTestView() } + struct AnonymousTestView_Previews: PreviewProvider { + static var previews: some View { + NavigationView { AnonymousTestView() } + } } -} #endif - - From c0aa149ca15481c43c5583ab41a1032838d5a219 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=A7=80=ED=98=84?= <102128060+wlgusqkr@users.noreply.github.com> Date: Tue, 28 Oct 2025 20:44:08 +0900 Subject: [PATCH 12/13] fix:lint --- .../Features/Main/Home/HomeView.swift | 51 +++++++++++-------- .../PostsDemo/AnonymousTestView.swift | 12 ++--- 2 files changed, 36 insertions(+), 27 deletions(-) diff --git a/today-s-sound/Presentation/Features/Main/Home/HomeView.swift b/today-s-sound/Presentation/Features/Main/Home/HomeView.swift index dd265fc..01954a3 100644 --- a/today-s-sound/Presentation/Features/Main/Home/HomeView.swift +++ b/today-s-sound/Presentation/Features/Main/Home/HomeView.swift @@ -27,27 +27,33 @@ struct HomeView: View { .shadow(color: .black25, radius: 2, x: 0, y: 4) .padding(.bottom, 60) - Button(action: { - if let first = viewModel.recentAlerts.first { - viewModel.playAlert(first) + Button( + action: { + if let first = viewModel.recentAlerts.first { + viewModel.playAlert(first) + } + }, + label: { + Image(systemName: "play.fill") + .resizable() + .scaledToFit() + .frame(width: 120, height: 120) + .foregroundColor(Color.primaryGreen90) + .padding(40) } - }) { - Image(systemName: "play.fill") - .resizable() - .scaledToFit() - .frame(width: 120, height: 120) - .foregroundColor(Color.primaryGreen90) - .padding(40) - } + ) .padding(.bottom, 60) // 속도 조절 HStack(spacing: 48) { - Button(action: { viewModel.decreaseRate() }) { - Image(systemName: "minus") - .font(.system(size: 35, weight: .medium)) - .foregroundColor(colorScheme == .dark ? .white : Color.primaryGreen90) - } + Button( + action: { viewModel.decreaseRate() }, + label: { + Image(systemName: "minus") + .font(.system(size: 35, weight: .medium)) + .foregroundColor(colorScheme == .dark ? .white : Color.primaryGreen90) + } + ) Text(String(format: "%.1f x", viewModel.playbackRate)) .font(.system(size: 48, weight: .bold)) @@ -55,11 +61,14 @@ struct HomeView: View { .monospacedDigit() .frame(minWidth: 100) - Button(action: { viewModel.increaseRate() }) { - Image(systemName: "plus") - .font(.system(size: 35, weight: .medium)) - .foregroundColor(colorScheme == .dark ? .white : Color.primaryGreen90) - } + Button( + action: { viewModel.increaseRate() }, + label: { + Image(systemName: "plus") + .font(.system(size: 35, weight: .medium)) + .foregroundColor(colorScheme == .dark ? .white : Color.primaryGreen90) + } + ) } Spacer() diff --git a/today-s-sound/Presentation/Features/PostsDemo/AnonymousTestView.swift b/today-s-sound/Presentation/Features/PostsDemo/AnonymousTestView.swift index be4f4b4..2ab3db1 100644 --- a/today-s-sound/Presentation/Features/PostsDemo/AnonymousTestView.swift +++ b/today-s-sound/Presentation/Features/PostsDemo/AnonymousTestView.swift @@ -29,28 +29,28 @@ final class AnonymousTestViewModel: ObservableObject { } struct AnonymousTestView: View { - @StateObject private var vm = AnonymousTestViewModel() + @StateObject private var viewModel = AnonymousTestViewModel() var body: some View { Form { Section(header: Text("디바이스 시크릿")) { - TextField("deviceSecret", text: $vm.deviceSecret) + TextField("deviceSecret", text: $viewModel.deviceSecret) .textInputAutocapitalization(.never) .autocorrectionDisabled() } Section(header: Text("동작")) { Button("익명 사용자 생성") { - vm.createAnonymous() + viewModel.createAnonymous() } } - if !vm.userId.isEmpty { + if !viewModel.userId.isEmpty { Section(header: Text("결과 user_id")) { - Text(vm.userId) + Text(viewModel.userId) .font(.system(.body, design: .monospaced)) } } Section(header: Text("로그")) { - Text(vm.log) + Text(viewModel.log) .font(.footnote) .foregroundColor(.gray) } From 9b2e3259fc634ed3bbf68e8643625bee670723b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=A7=80=ED=98=84?= <102128060+wlgusqkr@users.noreply.github.com> Date: Tue, 28 Oct 2025 20:50:26 +0900 Subject: [PATCH 13/13] fix:lint; --- today-s-sound/Core/Network/Config.swift | 7 ++++-- .../Core/Network/Targets/AuthAPITarget.swift | 4 ++-- .../AddSubscription/AddSubscriptionView.swift | 4 ++-- .../NotificationList/AlertCardView.swift | 4 ++-- .../NotificationListViewModel.swift | 24 ++++++++++++++++--- .../Component/SubscriptionCardView.swift | 4 ++-- 6 files changed, 34 insertions(+), 13 deletions(-) diff --git a/today-s-sound/Core/Network/Config.swift b/today-s-sound/Core/Network/Config.swift index 7170346..0ef89da 100644 --- a/today-s-sound/Core/Network/Config.swift +++ b/today-s-sound/Core/Network/Config.swift @@ -2,7 +2,10 @@ import Foundation enum Config { static var baseURL: String { - // TODO: 환경에 맞게 교체 (예: Debug/Release 분기) - "https://your-api-url.com" + #if DEBUG + return "https://dev-your-api-url.com" + #else + return "https://your-api-url.com" + #endif } } diff --git a/today-s-sound/Core/Network/Targets/AuthAPITarget.swift b/today-s-sound/Core/Network/Targets/AuthAPITarget.swift index 638b480..9140e7c 100644 --- a/today-s-sound/Core/Network/Targets/AuthAPITarget.swift +++ b/today-s-sound/Core/Network/Targets/AuthAPITarget.swift @@ -17,8 +17,8 @@ extension AuthAPITarget: APITargetType { var task: Task { switch self { - case let .refresh(rt): - .requestParameters(parameters: ["refreshToken": rt], encoding: JSONEncoding.default) + case let .refresh(refreshToken: refreshToken): + .requestParameters(parameters: ["refreshToken": refreshToken], encoding: JSONEncoding.default) } } diff --git a/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionView.swift b/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionView.swift index 14af7a6..3afee2d 100644 --- a/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionView.swift +++ b/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionView.swift @@ -54,7 +54,7 @@ struct AddSubscriptionView: View { // 하단 버튼 Button(action: { dismiss() - }) { + }, label: { Text("등록 승인 요청") .font(.system(size: 16, weight: .semibold)) .foregroundColor(.white) @@ -64,7 +64,7 @@ struct AddSubscriptionView: View { RoundedRectangle(cornerRadius: 12) .fill(Color.primaryGreen90) ) - } + }) } .padding(.horizontal, 16) .padding(.top, 8) diff --git a/today-s-sound/Presentation/Features/NotificationList/AlertCardView.swift b/today-s-sound/Presentation/Features/NotificationList/AlertCardView.swift index f859322..3831d06 100644 --- a/today-s-sound/Presentation/Features/NotificationList/AlertCardView.swift +++ b/today-s-sound/Presentation/Features/NotificationList/AlertCardView.swift @@ -44,7 +44,7 @@ struct AlertCardView: View { // 하단: 음성으로 듣기 버튼 Button(action: { SpeechService.shared.speak(text: alert.title) - }) { + }, label: { HStack(spacing: 8) { Image(systemName: "speaker.wave.2.fill") .font(.system(size: 18)) @@ -60,7 +60,7 @@ struct AlertCardView: View { RoundedRectangle(cornerRadius: 12) .fill(buttonBackgroundColor) ) - } + }) } .padding(24) .background( diff --git a/today-s-sound/Presentation/Features/NotificationList/NotificationListViewModel.swift b/today-s-sound/Presentation/Features/NotificationList/NotificationListViewModel.swift index e6f9faf..19c4a46 100644 --- a/today-s-sound/Presentation/Features/NotificationList/NotificationListViewModel.swift +++ b/today-s-sound/Presentation/Features/NotificationList/NotificationListViewModel.swift @@ -10,9 +10,27 @@ class NotificationListViewModel: ObservableObject { private func loadMock() { alerts = [ - Alert(id: UUID(), title: "일이삼사오육칠팔", content: "본문 예시", date: Date().addingTimeInterval(-7200), isUrgent: true), - Alert(id: UUID(), title: "잡코리아 채용 공고", content: "본문 예시 2", date: Date().addingTimeInterval(-10800), isUrgent: false), - Alert(id: UUID(), title: "동국대 도서관 휴관 안내", content: "본문 예시 3", date: Date().addingTimeInterval(-14400), isUrgent: true) + Alert( + id: UUID(), + title: "일이삼사오육칠팔", + content: "본문 예시", + date: Date().addingTimeInterval(-7200), + isUrgent: true + ), + Alert( + id: UUID(), + title: "잡코리아 채용 공고", + content: "본문 예시 2", + date: Date().addingTimeInterval(-10800), + isUrgent: false + ), + Alert( + id: UUID(), + title: "동국대 도서관 휴관 안내", + content: "본문 예시 3", + date: Date().addingTimeInterval(-14400), + isUrgent: true + ) ] } } diff --git a/today-s-sound/Presentation/Features/SubscriptionList/Component/SubscriptionCardView.swift b/today-s-sound/Presentation/Features/SubscriptionList/Component/SubscriptionCardView.swift index d0c957f..8dc1de5 100644 --- a/today-s-sound/Presentation/Features/SubscriptionList/Component/SubscriptionCardView.swift +++ b/today-s-sound/Presentation/Features/SubscriptionList/Component/SubscriptionCardView.swift @@ -31,11 +31,11 @@ struct SubscriptionCardView: View { Spacer() - Button(action: {}) { + Button(action: {}, label: { Image(systemName: "bell") .font(.system(size: 40)) .foregroundColor(.green) - } + }) } .padding(16) .background(