diff --git a/today-s-sound/Core/Network/Config.swift b/today-s-sound/Core/Network/Config.swift index 2e27503..b476640 100644 --- a/today-s-sound/Core/Network/Config.swift +++ b/today-s-sound/Core/Network/Config.swift @@ -3,7 +3,7 @@ import Foundation enum Config { static var baseURL: String { #if DEBUG - return "https://www.today-sound.com" + return "https://www.today-sound.com" // return "http://localhost:8080" // 개발 서버 #else return "https://api.todays-sound.com" // 운영 서버 diff --git a/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionView.swift b/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionView.swift index 49fd964..9ef1c52 100644 --- a/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionView.swift +++ b/today-s-sound/Presentation/Features/AddSubscription/AddSubscriptionView.swift @@ -10,12 +10,20 @@ struct AddSubscriptionView: View { Color.background(colorScheme) .ignoresSafeArea() .onTapGesture { + // 배경 탭하면 키보드만 닫기 UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) } VStack(spacing: 0) { // 상단 핸들 바 (X 대신) SheetHandleBar(colorScheme: colorScheme) + .accessibilityElement() + .accessibilityLabel("새 웹페이지 추가 창 닫기") + .accessibilityHint("이 영역을 두 번 탭하거나 아래로 스와이프하면 창이 닫힙니다.") + .onTapGesture { + // 핸들 바를 두 번 탭해서도 창을 닫을 수 있게 + dismiss() + } // 화면 제목 ScreenSubTitle(text: "새 웹페이지 추가", colorScheme: colorScheme) @@ -36,6 +44,15 @@ struct AddSubscriptionView: View { text: $viewModel.urlText, colorScheme: colorScheme ) + // 시각장애인용 안내 + .accessibilityElement(children: .combine) + .accessibilityLabel("웹사이트 URL 입력 칸") + .accessibilityValue( + viewModel.urlText.isEmpty + ? "입력 예시는 https://www.example.com" + : viewModel.urlText + ) + .accessibilityHint("모니터링할 웹페이지의 정확한 주소를 입력하세요.") // 2) 웹페이지 별명 (선택) InputFieldSection( @@ -46,6 +63,14 @@ struct AddSubscriptionView: View { text: $viewModel.nameText, colorScheme: colorScheme ) + .accessibilityElement(children: .combine) + .accessibilityLabel("웹페이지 별명 입력 칸") + .accessibilityValue( + viewModel.nameText.isEmpty + ? "입력 예시는 동국대학교 공지사항" + : viewModel.nameText + ) + .accessibilityHint("해당 페이지를 구분하기 쉬운 이름을 입력하세요.") // 3) 키워드 필터 VStack(alignment: .leading, spacing: 12) { @@ -118,6 +143,7 @@ struct AddSubscriptionView: View { .padding(.top, 8) .padding(.bottom, 8) } + .scrollDismissesKeyboard(.interactively) .frame(maxWidth: .infinity, maxHeight: .infinity) // 하단 고정 "등록 승인 요청" 버튼 @@ -131,10 +157,16 @@ struct AddSubscriptionView: View { print("📤 New Subscription Request:", payload) dismiss() } + // 접근성: 활성/비활성 상태에 따라 안내 문구 변경 + .accessibilityLabel("등록 승인 요청, 버튼") + .accessibilityHint( + viewModel.isSubmitEnabled + ? "이 웹사이트 등록 승인을 요청합니다." + : "웹사이트 URL을 입력해야 활성화됩니다." + ) .padding(.horizontal, 16) .padding(.vertical, 16) } - .scrollDismissesKeyboard(.interactively) .frame(maxWidth: .infinity, maxHeight: .infinity) } } @@ -143,6 +175,22 @@ struct AddSubscriptionView: View { .sheet(isPresented: $viewModel.showKeywordSelector) { KeywordSelectorSheet(viewModel: viewModel, colorScheme: colorScheme) } + // 키보드 상단에 항상 "키보드 닫기" 버튼 제공 + .toolbar { + ToolbarItemGroup(placement: .keyboard) { + Spacer() + Button("키보드 닫기") { + UIApplication.shared.sendAction( + #selector(UIResponder.resignFirstResponder), + to: nil, + from: nil, + for: nil + ) + } + .accessibilityLabel("키보드 닫기") + .accessibilityHint("탭하여 키보드를 숨깁니다.") + } + } } } @@ -164,6 +212,12 @@ struct KeywordSelectorSheet: View { VStack(spacing: 0) { SheetHandleBar(colorScheme: colorScheme) .padding(.top, 20) + .accessibilityElement() + .accessibilityLabel("키워드 설정 창 닫기") + .accessibilityHint("이 영역을 두 번 탭하거나 아래로 스와이프하면 창이 닫힙니다.") + .onTapGesture { + dismiss() + } // 키워드 설정 화면 제목 ScreenSubTitle(text: "키워드 설정", colorScheme: colorScheme) diff --git a/today-s-sound/Presentation/Features/Feed/FeedView.swift b/today-s-sound/Presentation/Features/Feed/FeedView.swift index 32a5755..3fbb179 100644 --- a/today-s-sound/Presentation/Features/Feed/FeedView.swift +++ b/today-s-sound/Presentation/Features/Feed/FeedView.swift @@ -186,7 +186,7 @@ struct FeedView: View { ) } .buttonStyle(.plain) - .accessibilityLabel("\(option) 피드 보기") + .accessibilityLabel("필터 탭, \(option) 피드 보기") .accessibilityHint("이 버튼을 선택하면 \(option) 피드만 볼 수 있습니다") } } diff --git a/today-s-sound/Presentation/Features/Main/Home/HomeView.swift b/today-s-sound/Presentation/Features/Main/Home/HomeView.swift index 46fc5bf..3c60ba6 100644 --- a/today-s-sound/Presentation/Features/Main/Home/HomeView.swift +++ b/today-s-sound/Presentation/Features/Main/Home/HomeView.swift @@ -1,10 +1,3 @@ -// -// HomeView.swift -// today-s-sound -// -// Created by 하승연 on 9/28/25. -// - import SwiftUI struct HomeView: View { @@ -26,8 +19,9 @@ struct HomeView: View { .font(.KoddiBold56) .foregroundStyle(Color.text(colorScheme)) .padding(.bottom, 30) - .accessibilityAddTraits(.isHeader) - .accessibilityLabel("오늘의 소리") + .accessibilityElement() // 이 텍스트를 독립 요소로 + .accessibilityLabel("오늘의 소리") // 👉 "오늘의 소리"라고 읽기 + .accessibilityAddTraits(.isHeader) // 머리말(헤더)로 인식 Button( action: { @@ -65,12 +59,15 @@ struct HomeView: View { .accessibilityLabel("재생 속도 감소") .accessibilityHint("탭하여 재생 속도를 느리게 합니다") + // 현재 속도 표시 Text(String(format: "%.1f x", viewModel.playbackRate)) .font(.KoddiBold48) .foregroundColor(Color.text(colorScheme)) .monospacedDigit() .frame(minWidth: 100) - .accessibilityLabel("현재 재생 속도 \(String(format: "%.1f", viewModel.playbackRate))배속") + .accessibilityElement() // 독립 요소 + .accessibilityLabel("현재 속도 \(String(format: "%.1f", viewModel.playbackRate))배속") + // 예: "현재 속도 1.0배속" Button( action: { viewModel.increaseRate() }, @@ -86,9 +83,11 @@ struct HomeView: View { .padding(.bottom, 60) VStack(spacing: 16) { + // "현재 카테고리" 텍스트 Text("현재 카테고리") .font(.KoddiBold28) .foregroundColor(Color.text(colorScheme)) + .accessibilityElement() .accessibilityLabel("현재 카테고리") if viewModel.isLoading { @@ -103,6 +102,7 @@ struct HomeView: View { .fill(Color.primaryGreen.opacity(0.6)) ) .foregroundColor(.white) + .accessibilityElement() .accessibilityLabel("피드를 불러오는 중입니다") } else if viewModel.currentCategoryName.isEmpty { Text("재생할 피드가 없습니다") @@ -116,8 +116,10 @@ struct HomeView: View { .fill(Color.primaryGreen.opacity(0.6)) ) .foregroundColor(.white) + .accessibilityElement() .accessibilityLabel("재생할 피드가 없습니다") } else { + // 현재 카테고리 이름 카드 Text(viewModel.currentCategoryName) .font(.KoddiExtraBold32) .foregroundColor(colorScheme == .dark ? .black : .white) @@ -129,7 +131,9 @@ struct HomeView: View { .fill(Color.primaryGreen) ) .foregroundColor(.white) - .accessibilityLabel("현재 재생 중인 카테고리: \(viewModel.currentCategoryName)") + .accessibilityElement() + .accessibilityLabel(viewModel.currentCategoryName) // 👉 카테고리명만 또렷하게 + .accessibilityHint("현재 재생 중인 카테고리입니다") } } .padding(.bottom, 16) diff --git a/today-s-sound/Presentation/Features/Main/Home/HomeViewModel.swift b/today-s-sound/Presentation/Features/Main/Home/HomeViewModel.swift index 40f71e7..5544486 100644 --- a/today-s-sound/Presentation/Features/Main/Home/HomeViewModel.swift +++ b/today-s-sound/Presentation/Features/Main/Home/HomeViewModel.swift @@ -95,5 +95,4 @@ class HomeViewModel: ObservableObject { ) .store(in: &cancellables) } - } diff --git a/today-s-sound/Presentation/Features/Main/MainView.swift b/today-s-sound/Presentation/Features/Main/MainView.swift index a9969f6..18383f3 100644 --- a/today-s-sound/Presentation/Features/Main/MainView.swift +++ b/today-s-sound/Presentation/Features/Main/MainView.swift @@ -15,40 +15,55 @@ struct MainView: View { TabView(selection: $selectedTab) { HomeView() .tabItem { - Image(systemName: "play.house.fill") - Text("홈") + VStack { + Image(systemName: "play.house.fill") + .accessibilityHidden(true) // 아이콘은 읽지 않도록 + Text("홈") + } } .tag(Tab.home) .accessibilityLabel("홈 탭") FeedView() .tabItem { - Image(systemName: "text.bubble.fill") - Text("피드") + VStack { + Image(systemName: "text.bubble.fill") + .accessibilityHidden(true) + Text("피드") + } } .tag(Tab.feed) .accessibilityLabel("피드 탭") NotificationListView() .tabItem { - Image(systemName: "bell.fill") - Text("알림") + VStack { + Image(systemName: "bell.fill") + .accessibilityHidden(true) + Text("알림") + } } .tag(Tab.notifications) .accessibilityLabel("알림 탭") SubscriptionListView() .tabItem { - Image(systemName: "books.vertical.fill") - Text("구독") + VStack { + Image(systemName: "books.vertical.fill") + .accessibilityHidden(true) + Text("구독") + } } .tag(Tab.subscriptions) .accessibilityLabel("구독 탭") SettingsView() .tabItem { - Image(systemName: "gearshape.fill") - Text("설정") + VStack { + Image(systemName: "gearshape.fill") + .accessibilityHidden(true) + Text("설정") + } } .tag(Tab.settings) .accessibilityLabel("설정 탭") diff --git a/today-s-sound/Presentation/Features/Main/MainViewModel.swift b/today-s-sound/Presentation/Features/Main/MainViewModel.swift index 0efa0cc..1d19ebd 100644 --- a/today-s-sound/Presentation/Features/Main/MainViewModel.swift +++ b/today-s-sound/Presentation/Features/Main/MainViewModel.swift @@ -204,5 +204,4 @@ class MainViewModel: ObservableObject { currentItemIndex += 1 } - } diff --git a/today-s-sound/Presentation/Features/NotificationList/AlertCardView.swift b/today-s-sound/Presentation/Features/NotificationList/AlertCardView.swift index cb113e1..1d77263 100644 --- a/today-s-sound/Presentation/Features/NotificationList/AlertCardView.swift +++ b/today-s-sound/Presentation/Features/NotificationList/AlertCardView.swift @@ -55,7 +55,7 @@ struct AlertCardView: View { .fill(cardColor) ) .accessibilityElement(children: .combine) - .accessibilityLabel("\(alarm.isUrgent ? "긴급 " : "")알림, \(alarm.alias), \(alarm.summaryContent), \(alarm.timeAgo)") + .accessibilityLabel("\(alarm.isUrgent ? "긴급 " : "일반 ")알림, \(alarm.alias), \(alarm.summaryContent), \(alarm.timeAgo)") } } diff --git a/today-s-sound/Presentation/Features/Settings/SettingsView.swift b/today-s-sound/Presentation/Features/Settings/SettingsView.swift index 5c2bf8e..ce92564 100644 --- a/today-s-sound/Presentation/Features/Settings/SettingsView.swift +++ b/today-s-sound/Presentation/Features/Settings/SettingsView.swift @@ -54,4 +54,3 @@ struct SettingsView_Previews: PreviewProvider { .environmentObject(SessionStore.preview) } } - diff --git a/today-s-sound/Presentation/Features/SubscriptionList/Component/SubscriptionCardView.swift b/today-s-sound/Presentation/Features/SubscriptionList/Component/SubscriptionCardView.swift index f07a6a1..74bf4ee 100644 --- a/today-s-sound/Presentation/Features/SubscriptionList/Component/SubscriptionCardView.swift +++ b/today-s-sound/Presentation/Features/SubscriptionList/Component/SubscriptionCardView.swift @@ -56,9 +56,9 @@ struct SubscriptionCardView: View { }, label: { Image(subscription.isUrgent ? "Bell" : "Bell off") .frame(width: 40, height: 40) - .accessibilityLabel(subscription.isUrgent ? "긴급 알림 설정됨" : "긴급 알림 해제됨") + .accessibilityLabel(subscription.isUrgent ? "페이지 알림 설정됨" : "페이지 알림 해제됨") }) - .accessibilityHint("탭하여 긴급 알림 설정을 변경합니다") + .accessibilityHint("탭하여 이 페이지의 구독 알림 설정을 변경합니다") } .padding(16) .background(