Adds a Share Extension so users can share URLs from Safari (or any app) to open the main app with the ImportURLSheet pre-filled. Uses a custom URL scheme (nextcloud-cookbook://) as the bridge between the extension and the main app. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
127 lines
4.6 KiB
Swift
127 lines
4.6 KiB
Swift
//
|
|
// ContentView.swift
|
|
// Nextcloud Cookbook iOS Client
|
|
//
|
|
// Created by Vincent Meilinger on 06.09.23.
|
|
//
|
|
|
|
import SwiftUI
|
|
|
|
struct MainView: View {
|
|
@StateObject var appState = AppState()
|
|
@StateObject var groceryList = GroceryListManager()
|
|
@StateObject var mealPlan = MealPlanManager()
|
|
|
|
// Tab ViewModels
|
|
@StateObject var recipeViewModel = RecipeTabView.ViewModel()
|
|
@StateObject var searchViewModel = SearchTabView.ViewModel()
|
|
|
|
@ObservedObject private var userSettings = UserSettings.shared
|
|
|
|
@State private var selectedTab: Tab = .recipes
|
|
|
|
@Binding var pendingImportURL: String?
|
|
|
|
enum Tab {
|
|
case recipes, search, mealPlan, groceryList
|
|
}
|
|
|
|
var body: some View {
|
|
TabView(selection: $selectedTab) {
|
|
SwiftUI.Tab("Recipes", systemImage: "book.closed.fill", value: .recipes) {
|
|
RecipeTabView()
|
|
.environmentObject(recipeViewModel)
|
|
.environmentObject(appState)
|
|
.environmentObject(groceryList)
|
|
.environmentObject(mealPlan)
|
|
}
|
|
|
|
SwiftUI.Tab("Search", systemImage: "magnifyingglass", value: .search, role: .search) {
|
|
SearchTabView()
|
|
.environmentObject(searchViewModel)
|
|
.environmentObject(appState)
|
|
.environmentObject(groceryList)
|
|
.environmentObject(mealPlan)
|
|
}
|
|
|
|
SwiftUI.Tab("Meal Plan", systemImage: "calendar", value: .mealPlan) {
|
|
MealPlanTabView()
|
|
.environmentObject(mealPlan)
|
|
.environmentObject(appState)
|
|
.environmentObject(groceryList)
|
|
}
|
|
|
|
if userSettings.groceryListMode != GroceryListMode.appleReminders.rawValue {
|
|
SwiftUI.Tab("Grocery List", systemImage: "storefront", value: .groceryList) {
|
|
GroceryListTabView()
|
|
.environmentObject(groceryList)
|
|
}
|
|
}
|
|
}
|
|
.tabViewStyle(.sidebarAdaptable)
|
|
.modifier(TabBarMinimizeModifier())
|
|
.onChange(of: userSettings.groceryListMode) { _, newValue in
|
|
if newValue == GroceryListMode.appleReminders.rawValue && selectedTab == .groceryList {
|
|
selectedTab = .recipes
|
|
}
|
|
Task {
|
|
await groceryList.load()
|
|
}
|
|
}
|
|
.task {
|
|
recipeViewModel.presentLoadingIndicator = true
|
|
await appState.getCategories()
|
|
await appState.updateAllRecipeDetails()
|
|
|
|
// Preload category images
|
|
for category in appState.categories {
|
|
await appState.getCategoryImage(for: category.name)
|
|
}
|
|
|
|
// Load recently viewed recipes
|
|
await appState.loadRecentRecipes()
|
|
|
|
// Load category sorting data
|
|
await appState.loadCategoryAccessDates()
|
|
await appState.loadManualCategoryOrder()
|
|
|
|
// Open detail view for default category
|
|
if UserSettings.shared.defaultCategory != "" {
|
|
if let cat = appState.categories.first(where: { c in
|
|
if c.name == UserSettings.shared.defaultCategory {
|
|
return true
|
|
}
|
|
return false
|
|
}) {
|
|
recipeViewModel.selectedCategory = cat
|
|
}
|
|
}
|
|
await groceryList.load()
|
|
groceryList.configureSyncManager(appState: appState)
|
|
if UserSettings.shared.grocerySyncEnabled {
|
|
await groceryList.syncManager?.performInitialSync()
|
|
}
|
|
await mealPlan.load()
|
|
mealPlan.configureSyncManager(appState: appState)
|
|
if UserSettings.shared.mealPlanSyncEnabled {
|
|
await mealPlan.syncManager?.performInitialSync()
|
|
}
|
|
recipeViewModel.presentLoadingIndicator = false
|
|
}
|
|
.onChange(of: pendingImportURL) { _, newURL in
|
|
guard let url = newURL, !url.isEmpty else { return }
|
|
selectedTab = .recipes
|
|
recipeViewModel.pendingImportURL = url
|
|
// Dismiss any currently open import sheet before re-presenting
|
|
if recipeViewModel.showImportURLSheet {
|
|
recipeViewModel.showImportURLSheet = false
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
|
|
recipeViewModel.showImportURLSheet = true
|
|
}
|
|
} else {
|
|
recipeViewModel.showImportURLSheet = true
|
|
}
|
|
}
|
|
}
|
|
}
|