RTSDA-iOS/Views/BulletinViews.swift

192 lines
6.3 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 BulletinDetailView: View {
let bulletin: Bulletin
@Environment(\.dismiss) private var dismiss
var body: some View {
ScrollView {
VStack(alignment: .leading, spacing: 20) {
// Header
VStack(alignment: .leading, spacing: 8) {
Text(bulletin.date.formatted(date: .long, time: .omitted))
.font(.subheadline)
.foregroundColor(.secondary)
Text(bulletin.title)
.font(.title)
.fontWeight(.bold)
}
// PDF Download Button
if let pdfUrl = bulletin.pdfUrl, let url = URL(string: pdfUrl) {
Link(destination: url) {
Label("Download PDF", systemImage: "doc.fill")
.frame(maxWidth: .infinity)
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
}
}
// Sections
ForEach(bulletin.sections, id: \.title) { section in
BulletinSectionView(section: section)
}
}
.padding()
}
.navigationBarTitleDisplayMode(.inline)
}
}
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 bulletin.pdfUrl != nil {
Label("PDF Available", systemImage: "doc.fill")
.font(.caption)
.foregroundColor(.blue)
}
}
.padding(.vertical, 8)
}
}