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:
@@ -2,79 +2,39 @@
|
||||
// ContentView.swift
|
||||
// Bible-Week
|
||||
//
|
||||
// Created by Matheus A Silveira on 04/09/26.
|
||||
// Raiz do app: abas Bíblia (leitura livre) e Plano (Bíblia em 180 Dias).
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import SwiftData
|
||||
|
||||
struct ContentView: View {
|
||||
@Environment(AppRouter.self) private var router
|
||||
@Environment(\.modelContext) private var modelContext
|
||||
@Query private var items: [Item]
|
||||
|
||||
var body: some View {
|
||||
NavigationViewWrapper {
|
||||
List {
|
||||
ForEach(items) { item in
|
||||
NavigationLink {
|
||||
Text("Item at \(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))")
|
||||
} label: {
|
||||
Text(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))
|
||||
}
|
||||
}
|
||||
.onDelete(perform: deleteItems)
|
||||
@Bindable var router = router
|
||||
TabView(selection: $router.selectedTab) {
|
||||
Tab("Bíblia", systemImage: "book", value: AppRouter.Tab.bible) {
|
||||
BooksView()
|
||||
}
|
||||
#if os(macOS)
|
||||
.navigationSplitViewColumnWidth(min: 180, ideal: 200)
|
||||
#endif
|
||||
.toolbar {
|
||||
#if os(iOS)
|
||||
ToolbarItem(placement: .navigationBarTrailing) {
|
||||
EditButton()
|
||||
}
|
||||
#endif
|
||||
ToolbarItem {
|
||||
Button(action: addItem) {
|
||||
Label("Add Item", systemImage: "plus")
|
||||
}
|
||||
}
|
||||
Tab("Plano", systemImage: "calendar.badge.checkmark", value: AppRouter.Tab.plan) {
|
||||
ReadingPlanView()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func addItem() {
|
||||
withAnimation {
|
||||
let newItem = Item(timestamp: Date())
|
||||
modelContext.insert(newItem)
|
||||
}
|
||||
}
|
||||
|
||||
private func deleteItems(offsets: IndexSet) {
|
||||
withAnimation {
|
||||
for index in offsets {
|
||||
modelContext.delete(items[index])
|
||||
.task {
|
||||
#if DEBUG
|
||||
// Gancho para testes de UI: relança o app com o plano zerado.
|
||||
if CommandLine.arguments.contains("--reset-plan") {
|
||||
try? modelContext.delete(model: ReadingPlanState.self)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate struct NavigationViewWrapper<Content: View>: View {
|
||||
let content: () -> Content
|
||||
|
||||
var body: some View {
|
||||
#if os(macOS)
|
||||
NavigationSplitView {
|
||||
content()
|
||||
} detail: {
|
||||
Text("Select an item")
|
||||
}
|
||||
#else
|
||||
content()
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
ContentView()
|
||||
.modelContainer(for: Item.self, inMemory: true)
|
||||
.environment(AppRouter())
|
||||
.modelContainer(for: ReadingPlanState.self, inMemory: true)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user