RTSDA-iOS/Views/WatchView.swift
RTSDA 00679f927c docs: Update README for v2.0 release and fix git remote URL
- 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
2025-08-16 18:41:51 -04:00

179 lines
6.9 KiB
Swift

import SwiftUI
struct WatchView: View {
@Environment(ChurchDataService.self) private var dataService
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
@State private var searchText = ""
@State private var selectedTab: WatchTab = .sermons
private let grayBackgroundColor: Color = {
#if os(iOS)
Color(.systemGray6)
#else
Color.gray.opacity(0.2)
#endif
}()
enum WatchTab: String, CaseIterable {
case sermons = "Sermons"
case liveArchives = "Live Archives"
var icon: String {
switch self {
case .sermons:
return "play.rectangle.fill"
case .liveArchives:
return "dot.radiowaves.left.and.right"
}
}
}
var currentContent: [Sermon] {
switch selectedTab {
case .sermons:
return dataService.sermons
case .liveArchives:
return dataService.livestreamArchives
}
}
var filteredContent: [Sermon] {
let content = currentContent
// Apply search text filter
return SearchUtils.searchSermons(content, searchText: searchText, contentType: selectedTab.rawValue.lowercased())
}
var body: some View {
VStack(spacing: 0) {
// Toggle buttons
HStack(spacing: 12) {
ForEach(WatchTab.allCases, id: \.self) { tab in
Button(action: {
selectedTab = tab
Task {
switch tab {
case .sermons:
await dataService.loadAllSermons()
case .liveArchives:
await dataService.loadAllLivestreamArchives()
}
}
}) {
HStack(spacing: 8) {
Image(systemName: tab.icon)
.font(horizontalSizeClass == .regular ? .body : .subheadline)
Text(tab.rawValue)
.font(.system(size: horizontalSizeClass == .regular ? 18 : 16, weight: .medium))
}
.foregroundColor(selectedTab == tab ? .white : .secondary)
.padding(.horizontal, horizontalSizeClass == .regular ? 32 : 20)
.padding(.vertical, horizontalSizeClass == .regular ? 20 : 14)
.background(
selectedTab == tab ?
Color(hex: getBrandColor()) :
Color.clear,
in: RoundedRectangle(cornerRadius: horizontalSizeClass == .regular ? 12 : 10)
)
.overlay(
RoundedRectangle(cornerRadius: horizontalSizeClass == .regular ? 12 : 10)
.strokeBorder(selectedTab == tab ? Color.clear : .secondary.opacity(0.3), lineWidth: 1)
)
.contentShape(RoundedRectangle(cornerRadius: horizontalSizeClass == .regular ? 12 : 10))
}
.buttonStyle(.plain)
}
Spacer()
}
.padding(.horizontal, 20)
.padding(.top, 16)
.padding(.bottom, 12)
// Search bar
HStack {
Image(systemName: "magnifyingglass")
.foregroundColor(.secondary)
TextField(selectedTab == .sermons ? "Search sermons..." : "Search live archives...", text: $searchText)
.textFieldStyle(PlainTextFieldStyle())
if !searchText.isEmpty {
Button(action: { searchText = "" }) {
Image(systemName: "xmark.circle.fill")
.foregroundColor(.secondary)
}
}
}
.padding(.horizontal, 16)
.padding(.vertical, 12)
.background(grayBackgroundColor)
.cornerRadius(12)
.padding(.horizontal, 20)
.padding(.bottom, 16)
// Content
if dataService.isLoading {
Spacer()
ProgressView(selectedTab == .sermons ? "Loading sermons..." : "Loading live archives...")
Spacer()
} else if filteredContent.isEmpty {
Spacer()
VStack(spacing: 16) {
Image(systemName: selectedTab == .sermons ? "play.rectangle" : "dot.radiowaves.left.and.right")
.font(.system(size: 50))
.foregroundColor(.secondary)
Text(selectedTab == .sermons ? "No sermons found" : "No live archives available")
.font(.headline)
.foregroundColor(.secondary)
if !searchText.isEmpty {
Text("Try adjusting your search terms")
.font(.subheadline)
.foregroundColor(.secondary)
.multilineTextAlignment(.center)
}
}
.padding()
Spacer()
} else {
ScrollView {
LazyVStack(spacing: 16) {
// Live stream card - only show when stream is live
if dataService.isStreamLive {
LiveStreamCard()
.padding(.horizontal, 20)
}
ForEach(filteredContent, id: \.id) { sermon in
SermonCard(sermon: sermon, style: .watch)
}
}
.padding(.horizontal, 20)
.padding(.bottom, 100)
}
.refreshable {
switch selectedTab {
case .sermons:
await dataService.loadAllSermons()
case .liveArchives:
await dataService.loadAllLivestreamArchives()
}
// Always refresh stream status when pulling to refresh
await dataService.loadStreamStatus()
}
}
}
.navigationTitle("Watch")
.task {
// Load both sermons, live archives, and stream status on initial load
await dataService.loadAllSermons()
await dataService.loadAllLivestreamArchives()
await dataService.loadStreamStatus()
}
}
}