Adiciona Plano Bíblia em 180 Dias com lembrete diário e ícone do app
- Leitor bíblico consumindo a API NBV (bible.falehandix.com.br): lista de livros por testamento e leitura de capítulos - Plano de 180 dias com três trilhas diárias (História, Sabedoria e Profetas, Novo Testamento) geradas deterministicamente sobre o cânon embutido (1.189 capítulos, cobertura testada) - Lembrete diário via notificação local recorrente (UNCalendarNotificationTrigger, identificador fixo, sem duplicatas), com pedido de autorização em contexto, configurações de horário/som, e deep link da notificação para a Leitura de Hoje - Estado do plano em SwiftData: progresso, pausa/retomada, reinício e conclusão preservando preferências do lembrete - 15 testes unitários (Testing) e 2 testes de UI (XCUIAutomation) - Ícone do app a partir do logo biblia.png Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
93
Bible-Week/BooksView.swift
Normal file
93
Bible-Week/BooksView.swift
Normal file
@@ -0,0 +1,93 @@
|
||||
//
|
||||
// BooksView.swift
|
||||
// Bible-Week
|
||||
//
|
||||
// Aba Bíblia: lista os livros agrupados por testamento.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct BooksView: View {
|
||||
@State private var books: [Book] = []
|
||||
@State private var isLoading = false
|
||||
@State private var errorMessage: String?
|
||||
|
||||
/// Livros do Antigo Testamento, em ordem canônica.
|
||||
private var oldTestament: [Book] {
|
||||
books.filter { $0.testament == "OT" }.sorted { $0.bookOrder < $1.bookOrder }
|
||||
}
|
||||
|
||||
/// Livros do Novo Testamento, em ordem canônica.
|
||||
private var newTestament: [Book] {
|
||||
books.filter { $0.testament == "NT" }.sorted { $0.bookOrder < $1.bookOrder }
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
Group {
|
||||
if isLoading {
|
||||
ProgressView("Carregando livros...")
|
||||
} else if let errorMessage {
|
||||
ContentUnavailableView {
|
||||
Label("Não foi possível carregar", systemImage: "wifi.slash")
|
||||
} description: {
|
||||
Text(errorMessage)
|
||||
} actions: {
|
||||
Button("Tentar novamente") { Task { await loadBooks() } }
|
||||
}
|
||||
} else {
|
||||
bookList
|
||||
}
|
||||
}
|
||||
.navigationTitle("Bíblia")
|
||||
}
|
||||
.task {
|
||||
if books.isEmpty { await loadBooks() }
|
||||
}
|
||||
}
|
||||
|
||||
private var bookList: some View {
|
||||
List {
|
||||
Section("Antigo Testamento") {
|
||||
ForEach(oldTestament) { book in
|
||||
bookRow(book)
|
||||
}
|
||||
}
|
||||
Section("Novo Testamento") {
|
||||
ForEach(newTestament) { book in
|
||||
bookRow(book)
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationDestination(for: Book.self) { book in
|
||||
ChapterReaderView(book: book)
|
||||
}
|
||||
}
|
||||
|
||||
private func bookRow(_ book: Book) -> some View {
|
||||
NavigationLink(value: book) {
|
||||
HStack {
|
||||
Text(book.name)
|
||||
Spacer()
|
||||
Text("\(book.chapterCount) cap.")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func loadBooks() async {
|
||||
isLoading = true
|
||||
errorMessage = nil
|
||||
defer { isLoading = false }
|
||||
do {
|
||||
books = try await BibleAPI.books()
|
||||
} catch {
|
||||
errorMessage = "Verifique sua conexão e tente novamente."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
BooksView()
|
||||
}
|
||||
Reference in New Issue
Block a user