RTSDA-iOS/Views/BulletinViews.swift

151 lines
4.9 KiB
Swift

import SwiftUI
struct BulletinListView: View {
@StateObject private var viewModel = BulletinViewModel()
var body: some View {
NavigationView {
Group {
if viewModel.isLoading {
ProgressView()
} else if let error = viewModel.error {
VStack {
Text("Error loading bulletins")
.font(.headline)
.foregroundColor(.red)
Text(error.localizedDescription)
.font(.subheadline)
.foregroundColor(.secondary)
Button("Retry") {
Task {
await viewModel.loadBulletins()
}
}
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(8)
}
.padding()
} else if viewModel.bulletins.isEmpty {
VStack {
Text("No Bulletins")
.font(.headline)
Text("No bulletins are available at this time.")
.font(.subheadline)
.foregroundColor(.secondary)
}
.padding()
} else {
List(viewModel.bulletins) { bulletin in
NavigationLink(destination: BulletinDetailView(bulletin: bulletin)) {
BulletinRowView(bulletin: bulletin)
}
}
}
}
.navigationTitle("Church Bulletins")
.task {
await viewModel.loadBulletins()
}
}
}
}
struct BulletinSectionView: View {
let section: BulletinSection
var body: some View {
VStack(alignment: .leading, spacing: 12) {
Text(section.title)
.font(.headline)
if section.title == "Scripture Reading" {
ScriptureReadingView(content: section.content)
} else {
BulletinContentText(content: section.content)
}
}
.padding()
.background(Color(.systemBackground))
.cornerRadius(10)
.shadow(radius: 2)
}
}
struct ScriptureReadingView: View {
let content: String
var body: some View {
VStack(spacing: 8) {
ForEach(content.components(separatedBy: .newlines), id: \.self) { line in
if !line.isEmpty {
Text(line)
.font(.body)
.foregroundColor(line.contains("Acts") ? .primary : .secondary)
}
}
}
}
}
struct BulletinContentText: View {
let content: String
var formattedContent: [(label: String?, value: String)] {
content.components(separatedBy: .newlines)
.map { line -> (String?, String) in
let parts = line.split(separator: ":", maxSplits: 1).map(String.init)
if parts.count == 2 {
return (parts[0].trimmingCharacters(in: .whitespaces),
parts[1].trimmingCharacters(in: .whitespaces))
}
return (nil, line)
}
.filter { !$0.1.isEmpty }
}
var body: some View {
VStack(spacing: 12) {
ForEach(formattedContent, id: \.1) { item in
if let label = item.label {
VStack(spacing: 4) {
Text(label)
.font(.headline)
.foregroundColor(.primary)
Text(item.value)
.font(.body)
.foregroundColor(.secondary)
}
} else {
Text(item.value)
.font(.body)
.foregroundColor(.secondary)
}
}
}
}
}
struct BulletinRowView: View {
let bulletin: Bulletin
var body: some View {
VStack(alignment: .leading, spacing: 8) {
Text(bulletin.date.formatted(date: .long, time: .omitted))
.font(.subheadline)
.foregroundColor(.secondary)
Text(bulletin.title)
.font(.headline)
.lineLimit(2)
if let pdf = bulletin.pdf, !pdf.isEmpty {
Label("PDF Available", systemImage: "doc.fill")
.font(.caption)
.foregroundColor(.blue)
}
}
.padding(.vertical, 8)
}
}