Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion today-s-sound/App/TodaySSoundApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDele

// 등록된 사용자인지 확인
guard let userId = Keychain.getString(for: KeychainKey.userId),
let deviceSecret = Keychain.getString(for: KeychainKey.deviceSecret) else {
let deviceSecret = Keychain.getString(for: KeychainKey.deviceSecret)
else {
// 미등록 사용자는 registerIfNeeded()에서 토큰과 함께 등록됨
print("ℹ️ [FCM] 미등록 사용자 - 서버 업데이트 생략 (추후 등록 시 전송)")
print("====================================\n")
Expand Down
6 changes: 3 additions & 3 deletions today-s-sound/Presentation/Features/Feed/FeedView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,11 @@ struct FeedView: View {
private var emptyState: some View {
VStack {
Spacer()
Text("표시할 피드가 없습니다")
Text("현재 표시할 피드가 없습니다\n구독한 페이지에 새로운 글이 올라오면 표시됩니다\n관리 탭에서 구독 페이지를 추가해주세요")
.font(.KoddiBold20)
.foregroundColor(Color.secondaryText(appTheme.theme))
.multilineTextAlignment(.center)
.accessibilityLabel("표시할 피드가 없습니다")
.accessibilityLabel("현재 표시할 피드가 없습니다. 구독한 페이지에 새로운 글이 올라오면 표시됩니다. 관리 탭에서 구독 페이지를 추가해주세요.")
Spacer()
}
.padding(.horizontal, 24)
Expand Down Expand Up @@ -251,7 +251,7 @@ private struct FeedCard: View {
)
}
.buttonStyle(.borderless)
.accessibilityLabel("원문 보기 버튼")
.accessibilityLabel("원문 보기")
.accessibilityHint("탭하면 Safari에서 원문 페이지를 엽니다")
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,24 +24,17 @@ struct AlertCardView: View {

var body: some View {
VStack(alignment: .leading, spacing: 16) {
// 상단: 아이콘 + 제목 + (오른쪽 상단 삭제 버튼)
HStack(alignment: .top, spacing: 12) {
// 상단: 아이콘 + 삭제 버튼 (양쪽 끝)
HStack(alignment: .top) {
Image(alarm.isKeywordMatched ? "notice" : "mail")
.resizable()
.scaledToFit()
.frame(width: 48, height: 48)
.accessibilityHidden(true)

Text(alarm.alias)
.font(.KoddiExtraBold32)
.foregroundColor(textColor)
.multilineTextAlignment(.leading)
.accessibilityLabel(alarm.isKeywordMatched ? "키워드 매칭 알림 " + alarm.alias : alarm.alias)
.accessibilityAddTraits(.isHeader)

Spacer()

// ✅ 삭제 버튼: 예전 읽음 체크 자리(오른쪽 상단), 아이콘만, 투명 배경
// ✅ 삭제 버튼: 오른쪽 상단, 아이콘만, 투명 배경
Button {
onDelete?(alarm)
} label: {
Expand All @@ -61,6 +54,14 @@ struct AlertCardView: View {
.accessibilityHint("이 알림을 삭제합니다")
}

// 제목: 아래로 넓게 펼쳐짐
Text(alarm.alias)
.font(.KoddiExtraBold32)
.foregroundColor(textColor)
.multilineTextAlignment(.leading)
.accessibilityLabel(alarm.isKeywordMatched ? "키워드 매칭 알림 " + alarm.alias : alarm.alias)
.accessibilityAddTraits(.isHeader)

// 본문
Text(alarm.summaryContent)
.font(.KoddiRegular20)
Expand Down
132 changes: 132 additions & 0 deletions today-s-sound/Presentation/Features/Settings/FAQView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
//
// FAQView.swift
// today-s-sound
//

import SwiftUI

struct FAQItem: Identifiable {
let id = UUID()
let question: String
let answer: String
}

struct FAQView: View {
let theme: AppTheme

@State private var expandedItems: Set<UUID> = []

private let faqItems: [FAQItem] = [
FAQItem(
question: "홈 탭과 피드 탭, 알림 탭에 아무것도 없어요.",
answer: "오늘의 소리는 앱 설치 후 관리 탭에서 원하는 구독 페이지를 추가하고, 구독 페이지에서 새로운 글이 발행되어야 탐색할 내용이 생성됩니다. 홈 탭과 피드 탭은 새로운 글이 올라와야 확인하실 수 있으니 해당 페이지에 새 글이 올라올 때까지 기다려주세요."
),
FAQItem(
question: "홈 탭에서 재생 버튼을 눌러도 아무 소리가 나지 않아요.",
answer: "구독한 페이지에서 새로운 글이 올라와야 재생할 내용이 생깁니다. 먼저 관리 탭에서 페이지를 구독하고, 해당 페이지에 새 글이 올라올 때까지 기다려주세요."
),
FAQItem(
question: "구독한 페이지에서 새 글이 올라왔는데 알림이 오지 않아요.",
answer: "알림은 설정한 키워드가 포함된 글이 올라오거나, 새 글 알림 설정이 켜진 페이지에서만 발송됩니다. 관리 탭에서 구독 페이지의 알림과 키워드 설정을 확인해주세요."
),
FAQItem(
question: "원하는 웹사이트랑 키워드가 없어요.",
answer: "todaysound.official@gmail.com 으로 원하는 웹사이트 또는 키워드를 요청해주시면 빠른 시일 내에 반영하도록 하겠습니다. 관리 탭의 개발자에게 문의 메뉴에서 이메일 주소를 손쉽게 복사하실 수 있습니다."
)
]

var body: some View {
ScrollView {
VStack(spacing: 0) {
ForEach(faqItems) { item in
FAQItemView(
item: item,
theme: theme,
isExpanded: expandedItems.contains(item.id),
onToggle: {
withAnimation(.easeInOut(duration: 0.2)) {
if expandedItems.contains(item.id) {
expandedItems.remove(item.id)
} else {
expandedItems.insert(item.id)
}
}
}
)

Divider()
.background(Color.border(theme))
.padding(.horizontal, 16)
.accessibilityHidden(true)
}
}
.padding(.vertical, 16)
}
.background(Color.background(theme))
}
}

struct FAQItemView: View {
let item: FAQItem
let theme: AppTheme
let isExpanded: Bool
let onToggle: () -> Void

var body: some View {
VStack(alignment: .leading, spacing: 0) {
// 질문 버튼
Button(action: onToggle) {
HStack(alignment: .top, spacing: 8) {
Text("Q.")
.font(.KoddiBold28)
.foregroundColor(.primaryGreen)

Text(item.question)
.font(.KoddiBold20)
.foregroundColor(Color.text(theme))
.multilineTextAlignment(.leading)

Spacer()

Image(systemName: isExpanded ? "chevron.up" : "chevron.down")
.font(.system(size: 16, weight: .semibold))
.foregroundColor(Color.text(theme))
}
.padding(.horizontal, 20)
.padding(.vertical, 16)
.contentShape(Rectangle())
}
.buttonStyle(PlainButtonStyle())
.accessibilityLabel("질문: \(item.question)")
.accessibilityHint(isExpanded ? "탭하면 답변을 접습니다" : "탭하면 답변을 확인할 수 있습니다")
.accessibilityValue(isExpanded ? "펼쳐짐" : "접힘")

// 답변 (펼쳐졌을 때만 표시)
if isExpanded {
HStack(alignment: .top, spacing: 8) {
Text("A.")
.font(.KoddiBold28)
.foregroundColor(.primaryGreen)

Text(item.answer)
.font(.KoddiRegular20)
.foregroundColor(Color.text(theme))
.multilineTextAlignment(.leading)

Spacer()
}
.padding(.horizontal, 20)
.padding(.bottom, 16)
.accessibilityLabel("답변: \(item.answer)")
}
}
}
}

#Preview("자주 묻는 질문 - 라이트") {
FAQView(theme: .normal)
}

#Preview("자주 묻는 질문 - 고대비") {
FAQView(theme: .highContrast)
}
Loading
Loading