Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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