This commit is contained in:
VincentMeilinger
2025-05-28 06:29:37 +02:00
parent 31dd6c6926
commit 078c01808d
4 changed files with 26 additions and 10 deletions

View File

@@ -797,7 +797,7 @@
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 14.0; MACOSX_DEPLOYMENT_TARGET = 14.0;
MARKETING_VERSION = 1.10.1; MARKETING_VERSION = 1.10.2;
PRODUCT_BUNDLE_IDENTIFIER = "VincentMeilinger.Nextcloud-Cookbook-iOS-Client"; PRODUCT_BUNDLE_IDENTIFIER = "VincentMeilinger.Nextcloud-Cookbook-iOS-Client";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = auto; SDKROOT = auto;
@@ -841,7 +841,7 @@
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 14.0; MACOSX_DEPLOYMENT_TARGET = 14.0;
MARKETING_VERSION = 1.10.1; MARKETING_VERSION = 1.10.2;
PRODUCT_BUNDLE_IDENTIFIER = "VincentMeilinger.Nextcloud-Cookbook-iOS-Client"; PRODUCT_BUNDLE_IDENTIFIER = "VincentMeilinger.Nextcloud-Cookbook-iOS-Client";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = auto; SDKROOT = auto;

View File

@@ -3836,7 +3836,7 @@
"de" : { "de" : {
"stringUnit" : { "stringUnit" : {
"state" : "translated", "state" : "translated",
"value" : "Durch das Feld unten können Einkäufe manuell hinzugefügt werden. Durch Zeilenumbrüche können mehrere Artikel auf einmal hinzugefügt werden." "value" : "Über das Textfeld können Einkäufe manuell hinzugefügt werden. Durch Zeilenumbrüche können mehrere Artikel auf einmal hinzugefügt werden."
} }
}, },
"es" : { "es" : {

View File

@@ -12,6 +12,7 @@ import SwiftUI
struct GroceryListTabView: View { struct GroceryListTabView: View {
@EnvironmentObject var groceryList: GroceryList @EnvironmentObject var groceryList: GroceryList
@State var newGroceries: String = "" @State var newGroceries: String = ""
@FocusState private var isFocused: Bool
var body: some View { var body: some View {
NavigationStack { NavigationStack {
@@ -24,6 +25,7 @@ struct GroceryListTabView: View {
.padding(4) .padding(4)
.overlay(RoundedRectangle(cornerRadius: 8) .overlay(RoundedRectangle(cornerRadius: 8)
.stroke(Color.secondary).opacity(0.5)) .stroke(Color.secondary).opacity(0.5))
.focused($isFocused)
Button { Button {
if !newGroceries.isEmpty { if !newGroceries.isEmpty {
let items = newGroceries let items = newGroceries
@@ -33,9 +35,11 @@ struct GroceryListTabView: View {
groceryList.addItems(items, toRecipe: "Other", recipeName: String(localized: "Other")) groceryList.addItems(items, toRecipe: "Other", recipeName: String(localized: "Other"))
} }
newGroceries = "" newGroceries = ""
} label: { } label: {
Text("Add") Text("Add")
} }
.disabled(newGroceries.isEmpty)
.buttonStyle(.borderedProminent) .buttonStyle(.borderedProminent)
} }
@@ -44,11 +48,9 @@ struct GroceryListTabView: View {
ForEach(groceryList.groceryDict[key]!.items) { item in ForEach(groceryList.groceryDict[key]!.items) { item in
GroceryListItemView(item: item, toggleAction: { GroceryListItemView(item: item, toggleAction: {
groceryList.toggleItemChecked(item) groceryList.toggleItemChecked(item)
groceryList.objectWillChange.send()
}, deleteAction: { }, deleteAction: {
groceryList.deleteItem(item.name, fromRecipe: key)
withAnimation { withAnimation {
groceryList.objectWillChange.send() groceryList.deleteItem(item.name, fromRecipe: key)
} }
}) })
} }
@@ -78,6 +80,9 @@ struct GroceryListTabView: View {
.foregroundStyle(Color.nextcloudBlue) .foregroundStyle(Color.nextcloudBlue)
} }
} }
.onTapGesture {
isFocused = false
}
} }
} }
} }
@@ -120,6 +125,7 @@ fileprivate struct GroceryListItemView: View {
fileprivate struct EmptyGroceryListView: View { fileprivate struct EmptyGroceryListView: View {
@EnvironmentObject var groceryList: GroceryList @EnvironmentObject var groceryList: GroceryList
@Binding var newGroceries: String @Binding var newGroceries: String
@FocusState private var isFocused: Bool
var body: some View { var body: some View {
List { List {
@@ -136,6 +142,7 @@ fileprivate struct EmptyGroceryListView: View {
.padding(4) .padding(4)
.overlay(RoundedRectangle(cornerRadius: 8) .overlay(RoundedRectangle(cornerRadius: 8)
.stroke(Color.secondary).opacity(0.5)) .stroke(Color.secondary).opacity(0.5))
.focused($isFocused)
Button { Button {
if !newGroceries.isEmpty { if !newGroceries.isEmpty {
let items = newGroceries let items = newGroceries
@@ -148,11 +155,15 @@ fileprivate struct EmptyGroceryListView: View {
} label: { } label: {
Text("Add") Text("Add")
} }
.disabled(newGroceries.isEmpty)
.buttonStyle(.borderedProminent) .buttonStyle(.borderedProminent)
} }
.padding(.bottom, 4) .padding(.bottom, 4)
} }
.navigationTitle("Grocery List") .navigationTitle("Grocery List")
.onTapGesture {
isFocused = false
}
} }
} }
@@ -198,6 +209,8 @@ class GroceryRecipeItem: Identifiable, Codable {
func addItem(_ itemName: String, toRecipe recipeId: String, recipeName: String? = nil, saveGroceryDict: Bool = true) { func addItem(_ itemName: String, toRecipe recipeId: String, recipeName: String? = nil, saveGroceryDict: Bool = true) {
print("Adding item of recipe \(String(describing: recipeName))") print("Adding item of recipe \(String(describing: recipeName))")
DispatchQueue.main.async { DispatchQueue.main.async {
if self.groceryDict[recipeId] != nil { if self.groceryDict[recipeId] != nil {
self.groceryDict[recipeId]?.items.append(GroceryRecipeItem(itemName)) self.groceryDict[recipeId]?.items.append(GroceryRecipeItem(itemName))
} else { } else {
@@ -206,8 +219,9 @@ class GroceryRecipeItem: Identifiable, Codable {
} }
if saveGroceryDict { if saveGroceryDict {
self.save() self.save()
self.objectWillChange.send()
} }
self.objectWillChange.send()
} }
} }
@@ -216,7 +230,7 @@ class GroceryRecipeItem: Identifiable, Codable {
addItem(item, toRecipe: recipeId, recipeName: recipeName, saveGroceryDict: false) addItem(item, toRecipe: recipeId, recipeName: recipeName, saveGroceryDict: false)
} }
self.save() self.save()
objectWillChange.send() self.objectWillChange.send()
} }
func deleteItem(_ itemName: String, fromRecipe recipeId: String) { func deleteItem(_ itemName: String, fromRecipe recipeId: String) {
@@ -228,26 +242,28 @@ class GroceryRecipeItem: Identifiable, Codable {
groceryDict.removeValue(forKey: recipeId) groceryDict.removeValue(forKey: recipeId)
} }
save() save()
objectWillChange.send() self.objectWillChange.send()
} }
func deleteGroceryRecipe(_ recipeId: String) { func deleteGroceryRecipe(_ recipeId: String) {
print("Deleting grocery recipe with id \(recipeId)") print("Deleting grocery recipe with id \(recipeId)")
groceryDict.removeValue(forKey: recipeId) groceryDict.removeValue(forKey: recipeId)
save() save()
objectWillChange.send() self.objectWillChange.send()
} }
func deleteAll() { func deleteAll() {
print("Deleting all grocery items") print("Deleting all grocery items")
groceryDict = [:] groceryDict = [:]
save() save()
self.objectWillChange.send()
} }
func toggleItemChecked(_ groceryItem: GroceryRecipeItem) { func toggleItemChecked(_ groceryItem: GroceryRecipeItem) {
print("Item checked: \(groceryItem.name)") print("Item checked: \(groceryItem.name)")
groceryItem.isChecked.toggle() groceryItem.isChecked.toggle()
save() save()
self.objectWillChange.send()
} }
func containsItem(at recipeId: String, item: String) -> Bool { func containsItem(at recipeId: String, item: String) -> Bool {