Nextcloud Login refactoring
This commit is contained in:
@@ -7,88 +7,86 @@
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import SwiftData
|
||||
|
||||
|
||||
/*
|
||||
struct RecipeTabView: View {
|
||||
@EnvironmentObject var appState: AppState
|
||||
@EnvironmentObject var groceryList: GroceryList
|
||||
@EnvironmentObject var viewModel: RecipeTabView.ViewModel
|
||||
//@State var cookbookState: CookbookState = CookbookState()
|
||||
@Environment(\.modelContext) var modelContext
|
||||
@Query var recipes: [Recipe]
|
||||
@State var categories: [(String, Int)] = []
|
||||
@State private var selectedRecipe: Recipe?
|
||||
@State private var selectedCategory: String? = "*"
|
||||
|
||||
var body: some View {
|
||||
NavigationSplitView {
|
||||
List(selection: $viewModel.selectedCategory) {
|
||||
// Categories
|
||||
ForEach(appState.categories) { category in
|
||||
NavigationLink(value: category) {
|
||||
HStack(alignment: .center) {
|
||||
if viewModel.selectedCategory != nil &&
|
||||
category.name == viewModel.selectedCategory!.name {
|
||||
Image(systemName: "book")
|
||||
} else {
|
||||
Image(systemName: "book.closed.fill")
|
||||
}
|
||||
|
||||
if category.name == "*" {
|
||||
Text("Other")
|
||||
.font(.system(size: 20, weight: .medium, design: .default))
|
||||
} else {
|
||||
Text(category.name)
|
||||
.font(.system(size: 20, weight: .medium, design: .default))
|
||||
}
|
||||
|
||||
Spacer()
|
||||
Text("\(category.recipe_count)")
|
||||
.font(.system(size: 15, weight: .bold, design: .default))
|
||||
.foregroundStyle(Color.background)
|
||||
.frame(width: 25, height: 25, alignment: .center)
|
||||
.minimumScaleFactor(0.5)
|
||||
.background {
|
||||
Circle()
|
||||
.foregroundStyle(Color.secondary)
|
||||
}
|
||||
}.padding(7)
|
||||
List(selection: $selectedCategory) {
|
||||
CategoryListItem(category: "All Recipes", count: recipes.count, isSelected: selectedCategory == "*")
|
||||
.tag("*") // Tag nil to select all recipes
|
||||
|
||||
Section("Categories") {
|
||||
ForEach(categories, id: \.0.self) { category in
|
||||
CategoryListItem(category: category.0, count: category.1, isSelected: selectedCategory == category.0)
|
||||
.tag(category.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationTitle("Cookbooks")
|
||||
.toolbar {
|
||||
RecipeTabViewToolBar()
|
||||
}
|
||||
.navigationDestination(isPresented: $viewModel.presentSettingsView) {
|
||||
SettingsView()
|
||||
.environmentObject(appState)
|
||||
}
|
||||
.navigationDestination(isPresented: $viewModel.presentEditView) {
|
||||
RecipeView(viewModel: RecipeView.ViewModel())
|
||||
.environmentObject(appState)
|
||||
.environmentObject(groceryList)
|
||||
}
|
||||
.navigationTitle("Categories")
|
||||
} content: {
|
||||
RecipeListView(selectedCategory: $selectedCategory, selectedRecipe: $selectedRecipe)
|
||||
} detail: {
|
||||
NavigationStack {
|
||||
if let category = viewModel.selectedCategory {
|
||||
RecipeListView(
|
||||
categoryName: category.name,
|
||||
showEditView: $viewModel.presentEditView
|
||||
)
|
||||
.id(category.id) // Workaround: This is needed to update the detail view when the selection changes
|
||||
}
|
||||
|
||||
// Use a conditional view based on selection
|
||||
if let selectedRecipe {
|
||||
//RecipeDetailView(recipe: recipe) // Create a dedicated detail view
|
||||
RecipeView(recipe: selectedRecipe, viewModel: RecipeView.ViewModel(recipe: selectedRecipe))
|
||||
} else {
|
||||
ContentUnavailableView("Select a Recipe", systemImage: "fork.knife.circle")
|
||||
}
|
||||
}
|
||||
.tint(.nextcloudBlue)
|
||||
.task {
|
||||
let connection = await appState.checkServerConnection()
|
||||
DispatchQueue.main.async {
|
||||
viewModel.serverConnection = connection
|
||||
initCategories()
|
||||
return
|
||||
do {
|
||||
try modelContext.delete(model: Recipe.self)
|
||||
} catch {
|
||||
print("Failed to delete recipes and categories.")
|
||||
}
|
||||
|
||||
guard let categories = await CookbookApiV1.getCategories(auth: UserSettings.shared.authString).0 else { return }
|
||||
for category in categories {
|
||||
guard let recipeStubs = await CookbookApiV1.getCategory(auth: UserSettings.shared.authString, named: category.name).0 else { return }
|
||||
for recipeStub in recipeStubs {
|
||||
guard let recipe = await CookbookApiV1.getRecipe(auth: UserSettings.shared.authString, id: recipeStub.id).0 else { return }
|
||||
modelContext.insert(recipe)
|
||||
}
|
||||
}
|
||||
|
||||
}/*
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .topBarLeading) {
|
||||
Button(action: {
|
||||
//cookbookState.showSettings = true
|
||||
}) {
|
||||
Label("Settings", systemImage: "gearshape")
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
func initCategories() {
|
||||
// Load Categories
|
||||
var categoryDict: [String: Int] = [:]
|
||||
for recipe in recipes {
|
||||
// Ensure "Uncategorized" is a valid category if used
|
||||
if !recipe.category.isEmpty {
|
||||
categoryDict[recipe.category, default: 0] += 1
|
||||
} else {
|
||||
categoryDict["Other", default: 0] += 1
|
||||
}
|
||||
}
|
||||
.refreshable {
|
||||
let connection = await appState.checkServerConnection()
|
||||
DispatchQueue.main.async {
|
||||
viewModel.serverConnection = connection
|
||||
}
|
||||
await appState.getCategories()
|
||||
}
|
||||
categories = categoryDict.map {
|
||||
($0.key, $0.value)
|
||||
}.sorted { $0.0 < $1.0 }
|
||||
}
|
||||
|
||||
class ViewModel: ObservableObject {
|
||||
@@ -98,13 +96,40 @@ struct RecipeTabView: View {
|
||||
@Published var presentLoadingIndicator: Bool = false
|
||||
@Published var presentConnectionPopover: Bool = false
|
||||
@Published var serverConnection: Bool = false
|
||||
|
||||
@Published var selectedCategory: Category? = nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
fileprivate struct CategoryListItem: View {
|
||||
var category: String
|
||||
var count: Int
|
||||
var isSelected: Bool
|
||||
|
||||
var body: some View {
|
||||
HStack(alignment: .center) {
|
||||
if isSelected {
|
||||
Image(systemName: "book")
|
||||
} else {
|
||||
Image(systemName: "book.closed.fill")
|
||||
}
|
||||
|
||||
Text(category)
|
||||
.font(.system(size: 20, weight: .medium, design: .default))
|
||||
|
||||
Spacer()
|
||||
Text("\(count)")
|
||||
.font(.system(size: 15, weight: .bold, design: .default))
|
||||
.foregroundStyle(Color.background)
|
||||
.frame(width: 25, height: 25, alignment: .center)
|
||||
.minimumScaleFactor(0.5)
|
||||
.background {
|
||||
Circle()
|
||||
.foregroundStyle(Color.secondary)
|
||||
}
|
||||
}.padding(7)
|
||||
}
|
||||
}
|
||||
/*
|
||||
fileprivate struct RecipeTabViewToolBar: ToolbarContent {
|
||||
@EnvironmentObject var appState: AppState
|
||||
@EnvironmentObject var viewModel: RecipeTabView.ViewModel
|
||||
|
||||
Reference in New Issue
Block a user