Skip to content

Commit

Permalink
Merge pull request #27 from jacuzzicoding/feature/towns
Browse files Browse the repository at this point in the history
Feature/towns
  • Loading branch information
jacuzzicoding authored Dec 16, 2024
2 parents 201f4b6 + 1498d67 commit 8240281
Show file tree
Hide file tree
Showing 6 changed files with 213 additions and 17 deletions.
14 changes: 12 additions & 2 deletions AnimalCrossingGCN-Tracker/App/AnimalCrossingGCN_TrackerApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//
// Created by Brock Jenkinson on 10/5/24.
//
// Last updated 11/18/24
// Last updated 12/15/24
//

import SwiftUI
Expand All @@ -17,7 +17,8 @@ struct AnimalCrossingGCN_TrackerApp: App {
Fossil.self,
Bug.self,
Fish.self,
Art.self
Art.self,
Town.self
])

let modelConfiguration = ModelConfiguration(isStoredInMemoryOnly: false)
Expand All @@ -33,10 +34,19 @@ struct AnimalCrossingGCN_TrackerApp: App {
fatalError("Could not create ModelContainer: \(error)")
}
}()

// Initialize DataManager with the shared ModelContainer's context
@StateObject private var dataManager: DataManager

init() {
let context = sharedModelContainer.mainContext
_dataManager = StateObject(wrappedValue: DataManager(modelContext: context))
}

var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(dataManager) // Inject DataManager into the environment
}
.modelContainer(sharedModelContainer)
}
Expand Down
85 changes: 85 additions & 0 deletions AnimalCrossingGCN-Tracker/Managers/DataManager.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// DataManager.swift
import Foundation
import SwiftData
import Combine
import SwiftUI

class DataManager: ObservableObject {
// Access to the Model Context
private var modelContext: ModelContext

// Published properties to notify views of changes
@Published var currentTown: Town?

// Initialize DataManager and fetch the current town
init(modelContext: ModelContext) {
self.modelContext = modelContext
fetchCurrentTown()
}

/// Fetches the current town from the persistent store.
/// If no town exists, it creates a default one.
func fetchCurrentTown() {
// Create a basic fetch descriptor for Town
let descriptor = FetchDescriptor<Town>()

do {
let towns = try modelContext.fetch(descriptor)
if let town = towns.first {
DispatchQueue.main.async {
self.currentTown = town
}
} else {
// No town exists; create a default one
let defaultTown = Town(name: "My Town")
modelContext.insert(defaultTown)
try modelContext.save()
DispatchQueue.main.async {
self.currentTown = defaultTown
}
}
} catch {
print("Error fetching or creating Town: \(error)")
}
}


/// Updates the town's name.
/// - Parameter newName: The new name for the town.
func updateTownName(_ newName: String) {
guard let town = currentTown else { return }
town.name = newName

do {
try modelContext.save()
} catch {
print("Error updating town name: \(error)")
}
}

/// Adds a new town. (Optional: If you plan to support multiple towns in the future)
/// - Parameter town: The `Town` object to add.
func addTown(_ town: Town) {
modelContext.insert(town)

do {
try modelContext.save()
currentTown = town
} catch {
print("Error adding new town: \(error)")
}
}

/// Deletes the current town. (Optional: If you plan to support multiple towns)
func deleteCurrentTown() {
guard let town = currentTown else { return }
modelContext.delete(town)

do {
try modelContext.save()
fetchCurrentTown()
} catch {
print("Error deleting town: \(error)")
}
}
}
11 changes: 11 additions & 0 deletions AnimalCrossingGCN-Tracker/Models/Town.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Town.swift
import SwiftData

@Model
class Town {
var name: String

init(name: String) {
self.name = name
}
}
57 changes: 43 additions & 14 deletions AnimalCrossingGCN-Tracker/Views/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ struct CategorySection<T: CollectibleItem>: View { //this is the new CategorySec
}
}

// Add this helper struct
//helper struct
struct LazyView<Content: View>: View {
let build: () -> Content

Expand All @@ -194,21 +194,49 @@ struct LazyView<Content: View>: View {
}
}

struct ContentView: View { //here is the new ContentView struct
// Keeping existing environment and query properties
struct ContentView: View { // Updated ContentView
// Existing environment and query properties
@Environment(\.modelContext) private var modelContext
@Query(sort: \Fossil.name) private var fossilsQuery: [Fossil]
@Query(sort: \Bug.name) private var bugsQuery: [Bug]
@Query(sort: \Fish.name) private var fishQuery: [Fish]
@Query(sort: \Art.name) private var artQuery: [Art]


// Town managing
@EnvironmentObject var dataManager: DataManager
@State private var isEditingTown = false
@State private var newTownName: String = ""

// Category manager
@Environment(\.horizontalSizeClass) var horizontalSizeClass
@StateObject private var categoryManager = CategoryManager()
@State private var searchText = ""

private var mainContent: some View {
ZStack(alignment: .bottom) { //align the floating category switcher to the bottom
VStack(spacing: 0) {
// Town Section
HStack {
Text("Town Name:")
.font(.headline)
Spacer()
Text(dataManager.currentTown?.name ?? "Loading...")
.font(.title2)
Button(action: {
// Initialize with current town name or empty if not set
newTownName = dataManager.currentTown?.name ?? ""
isEditingTown = true
}) {
Image(systemName: "pencil")
.foregroundColor(.blue)
}
.buttonStyle(BorderlessButtonStyle())
}
.padding()

Divider()

// Existing search and main list content
SearchBar(text: $searchText)
MainListView(
searchText: $searchText,
Expand All @@ -218,15 +246,14 @@ struct ContentView: View { //here is the new ContentView struct
artQuery: artQuery
)
}

// Floating category switcher overlay
FloatingCategorySwitcher()
.padding(.bottom, 20)
}
}
/* DATA LOADING SECTION */

// Keeping existing loadData function
/*Data Loading Section*/ //moving to DataManager.swift soon
// Keeping the existing loadData function unchanged
private func loadData() {
for category in Category.allCases {
let data = category.getDefaultData()
Expand All @@ -251,7 +278,6 @@ struct ContentView: View { //here is the new ContentView struct
}
try? modelContext.save()
}
//helper function for the navigationDestination modifiers we need in the body..

@ViewBuilder
func addNavigationDestinations<Content: View>(_ content: Content) -> some View {
Expand All @@ -269,18 +295,17 @@ struct ContentView: View { //here is the new ContentView struct
ArtDetailView(art: art)
}
}
//here!
var body: some View {

var body: some View {
Group {
if horizontalSizeClass == .compact {
// IPHONE SECTION
// iPhone section
NavigationStack {
addNavigationDestinations(mainContent)
.navigationTitle("Museum Tracker")
}
} else {
// MAC/IPAD SECTION
// iPad/Mac section
NavigationSplitView {
addNavigationDestinations(mainContent)
#if os(macOS)
Expand All @@ -301,5 +326,9 @@ struct ContentView: View { //here is the new ContentView struct
.onAppear {
loadData()
}
.sheet(isPresented: $isEditingTown) {
EditTownView(isPresented: $isEditingTown, townName: $newTownName)
.environmentObject(dataManager)
}
}
}
62 changes: 62 additions & 0 deletions AnimalCrossingGCN-Tracker/Views/EditTownView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import SwiftUI
import SwiftData

struct EditTownView: View {
@Binding var isPresented: Bool
@Binding var townName: String
@EnvironmentObject var dataManager: DataManager

var body: some View {
#if os(macOS)
editTownContent
.frame(width: 300, height: 150)
#else
NavigationStack {
editTownContent
.navigationTitle("Edit Town")
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button("Cancel") {
isPresented = false
}
}
ToolbarItem(placement: .confirmationAction) {
Button("Save") {
dataManager.updateTownName(townName)
isPresented = false
}
}
}
}
#endif
}

private var editTownContent: some View {
Form {
Section(header: Text("Town Details")) {
TextField("Town Name", text: $townName)
}
#if os(macOS)
HStack {
Button("Cancel") {
isPresented = false
}
Spacer()
Button("Save") {
dataManager.updateTownName(townName)
isPresented = false
}
}
.padding()
#endif
}
}
}

#Preview {
EditTownView(
isPresented: .constant(true),
townName: .constant("Test Town")
)
.environmentObject(DataManager(modelContext: try! ModelContext(ModelContainer(for: Town.self))))
}
1 change: 0 additions & 1 deletion test.md

This file was deleted.

0 comments on commit 8240281

Please sign in to comment.