
- Comprehensive README update documenting v2.0 architectural changes - Updated git remote to ssh://rockvilleav@git.rockvilletollandsda.church:10443/RTSDA/RTSDA-iOS.git - Documented unified ChurchService and 60% code reduction - Added new features: Home Feed, responsive reading, enhanced UI - Corrected license information (GPL v3 with church content copyright) - Updated build instructions and technical stack details
236 lines
9.7 KiB
Swift
236 lines
9.7 KiB
Swift
import SwiftUI
|
|
|
|
struct FilterSheet: View {
|
|
let selectedTab: WatchView.WatchTab
|
|
@Binding var selectedSpeaker: String
|
|
@Binding var selectedDateRange: String
|
|
@Binding var selectedDuration: String
|
|
@Environment(\.dismiss) private var dismiss
|
|
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
|
|
@Environment(ChurchDataService.self) private var dataService
|
|
|
|
@State private var selectedYear: String = "All Time"
|
|
@State private var selectedMonth: String = "All Months"
|
|
|
|
private var availableSpeakers: [String] {
|
|
let currentContent = selectedTab == .sermons ? dataService.sermons : dataService.livestreamArchives
|
|
let cleanedSpeakers = currentContent.compactMap { sermon -> String? in
|
|
let speaker = sermon.speaker.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
return speaker.isEmpty ? nil : speaker
|
|
}
|
|
let uniqueSpeakers = Set(cleanedSpeakers)
|
|
return ["All Speakers"] + Array(uniqueSpeakers).sorted()
|
|
}
|
|
|
|
private var availableYears: [String] {
|
|
var years = ["All Time"]
|
|
let calendar = Calendar.current
|
|
|
|
// Use proper date formatter for your date format: "August 02, 2025"
|
|
let formatter = DateFormatter()
|
|
formatter.dateFormat = "MMMM dd, yyyy"
|
|
formatter.locale = Locale(identifier: "en_US")
|
|
|
|
let currentContent = selectedTab == .sermons ? dataService.sermons : dataService.livestreamArchives
|
|
|
|
// Extract all unique years from content
|
|
var yearSet: Set<Int> = []
|
|
|
|
for item in currentContent {
|
|
guard let dateString = item.date,
|
|
!dateString.isEmpty,
|
|
let date = formatter.date(from: dateString) else { continue }
|
|
|
|
let year = calendar.component(.year, from: date)
|
|
yearSet.insert(year)
|
|
}
|
|
|
|
// Add years in descending order
|
|
let sortedYears = yearSet.sorted(by: >)
|
|
for year in sortedYears {
|
|
years.append(String(year))
|
|
}
|
|
|
|
return years
|
|
}
|
|
|
|
private var availableMonths: [String] {
|
|
guard selectedYear != "All Time", let targetYear = Int(selectedYear) else {
|
|
return ["All Months"]
|
|
}
|
|
|
|
var months = ["All Months"]
|
|
let calendar = Calendar.current
|
|
|
|
// Use proper date formatter for your date format: "August 02, 2025"
|
|
let formatter = DateFormatter()
|
|
formatter.dateFormat = "MMMM dd, yyyy"
|
|
formatter.locale = Locale(identifier: "en_US")
|
|
|
|
let currentContent = selectedTab == .sermons ? dataService.sermons : dataService.livestreamArchives
|
|
|
|
// Extract months for the selected year
|
|
var monthSet: Set<Int> = []
|
|
|
|
for item in currentContent {
|
|
guard let dateString = item.date,
|
|
!dateString.isEmpty,
|
|
let date = formatter.date(from: dateString) else { continue }
|
|
|
|
let year = calendar.component(.year, from: date)
|
|
let month = calendar.component(.month, from: date)
|
|
|
|
if year == targetYear {
|
|
monthSet.insert(month)
|
|
}
|
|
}
|
|
|
|
// Add months in descending order (most recent first)
|
|
let monthNames = ["January", "February", "March", "April", "May", "June",
|
|
"July", "August", "September", "October", "November", "December"]
|
|
|
|
let sortedMonths = monthSet.sorted(by: >)
|
|
for month in sortedMonths {
|
|
if month >= 1 && month <= 12 {
|
|
months.append(monthNames[month-1])
|
|
}
|
|
}
|
|
|
|
print("🔍 DEBUG: availableMonths for year \(targetYear): \(months)")
|
|
return months
|
|
}
|
|
private let durations = ["Any Duration", "Under 30 min", "30-60 min", "Over 60 min"]
|
|
|
|
var body: some View {
|
|
NavigationStack {
|
|
Form {
|
|
Section {
|
|
Text("Filter \(selectedTab.rawValue)")
|
|
.font(.headline)
|
|
.foregroundColor(.primary)
|
|
} header: {
|
|
EmptyView()
|
|
}
|
|
|
|
Section("Speaker") {
|
|
Picker("Speaker", selection: $selectedSpeaker) {
|
|
ForEach(availableSpeakers, id: \.self) { speaker in
|
|
Text(speaker).tag(speaker)
|
|
}
|
|
}
|
|
.pickerStyle(.menu)
|
|
}
|
|
|
|
Section("Date Range") {
|
|
Picker("Year", selection: $selectedYear) {
|
|
ForEach(availableYears, id: \.self) { year in
|
|
Text(year).tag(year)
|
|
}
|
|
}
|
|
.pickerStyle(.menu)
|
|
.onChange(of: selectedYear) { _, newYear in
|
|
// Don't auto-reset month when year changes during initialization
|
|
// Only reset if it's a user-initiated change
|
|
if selectedMonth != "All Months" && !availableMonths.contains(selectedMonth) {
|
|
selectedMonth = "All Months"
|
|
}
|
|
}
|
|
|
|
// Only show month picker if a specific year is selected
|
|
if selectedYear != "All Time" {
|
|
Picker("Month", selection: $selectedMonth) {
|
|
ForEach(availableMonths, id: \.self) { month in
|
|
Text(month).tag(month)
|
|
}
|
|
}
|
|
.pickerStyle(.menu)
|
|
}
|
|
}
|
|
|
|
Section("Duration") {
|
|
Picker("Duration", selection: $selectedDuration) {
|
|
ForEach(durations, id: \.self) { duration in
|
|
Text(duration).tag(duration)
|
|
}
|
|
}
|
|
.pickerStyle(.menu)
|
|
}
|
|
|
|
Section {
|
|
Button("Reset Filters") {
|
|
selectedSpeaker = "All Speakers"
|
|
selectedYear = "All Time"
|
|
selectedMonth = "All Months"
|
|
selectedDuration = "Any Duration"
|
|
}
|
|
.foregroundColor(.red)
|
|
}
|
|
}
|
|
.navigationTitle("Filters")
|
|
.navigationBarTitleDisplayMode(.inline)
|
|
.toolbar {
|
|
ToolbarItem(placement: .navigationBarLeading) {
|
|
Button("Cancel") {
|
|
dismiss()
|
|
}
|
|
}
|
|
|
|
ToolbarItem(placement: .navigationBarTrailing) {
|
|
Button("Apply") {
|
|
// Convert year/month selection to selectedDateRange format
|
|
if selectedYear == "All Time" {
|
|
selectedDateRange = "All Time"
|
|
} else if selectedMonth == "All Months" {
|
|
selectedDateRange = selectedYear
|
|
} else {
|
|
selectedDateRange = "\(selectedMonth) \(selectedYear)"
|
|
}
|
|
dismiss()
|
|
}
|
|
.fontWeight(.semibold)
|
|
.foregroundColor(Color(hex: "fb8b23"))
|
|
}
|
|
}
|
|
}
|
|
.presentationDetents([.medium, .large])
|
|
.presentationDragIndicator(.visible)
|
|
.onAppear {
|
|
// Initialize year/month from current selectedDateRange
|
|
print("🔍 DEBUG: Initializing filter sheet with selectedDateRange: '\(selectedDateRange)'")
|
|
|
|
if selectedDateRange == "All Time" {
|
|
selectedYear = "All Time"
|
|
selectedMonth = "All Months"
|
|
} else {
|
|
// Check if it's a year-only filter (e.g., "2024")
|
|
if let _ = Int(selectedDateRange) {
|
|
selectedYear = selectedDateRange
|
|
selectedMonth = "All Months"
|
|
print("🔍 DEBUG: Set year-only filter - Year: \(selectedYear), Month: \(selectedMonth)")
|
|
} else {
|
|
// It's a month-year filter (e.g., "January 2024")
|
|
let components = selectedDateRange.components(separatedBy: " ")
|
|
if components.count == 2 {
|
|
selectedYear = components[1]
|
|
selectedMonth = components[0]
|
|
print("🔍 DEBUG: Set month-year filter - Year: \(selectedYear), Month: \(selectedMonth)")
|
|
|
|
// Force a small delay to ensure availableMonths is computed before validation
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
|
if !availableMonths.contains(selectedMonth) {
|
|
print("🔍 DEBUG: Month '\(selectedMonth)' not found in available months, resetting")
|
|
selectedMonth = "All Months"
|
|
} else {
|
|
print("🔍 DEBUG: Month '\(selectedMonth)' validated successfully")
|
|
}
|
|
}
|
|
} else {
|
|
selectedYear = "All Time"
|
|
selectedMonth = "All Months"
|
|
print("🔍 DEBUG: Failed to parse, defaulting to All Time")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |