WIP - Complete App refactoring
This commit is contained in:
@@ -1,8 +0,0 @@
|
||||
//
|
||||
// Account.swift
|
||||
// Nextcloud Cookbook iOS Client
|
||||
//
|
||||
// Created by Vincent Meilinger on 24.01.25.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// AccountState.swift
|
||||
// CookbookState.swift
|
||||
// Nextcloud Cookbook iOS Client
|
||||
//
|
||||
// Created by Vincent Meilinger on 29.05.24.
|
||||
@@ -7,13 +7,10 @@
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
/*
|
||||
|
||||
@Observable
|
||||
class CookbookState {
|
||||
let id = UUID()
|
||||
let account: Account? = nil
|
||||
|
||||
/// Caches recipe categories.
|
||||
var categories: [Category] = []
|
||||
|
||||
@@ -33,212 +30,193 @@ class CookbookState {
|
||||
var keywords: [RecipeKeyword] = []
|
||||
|
||||
/// Read and write interfaces.
|
||||
var readLocal: ReadInterface
|
||||
var writeLocal: WriteInterface
|
||||
var readRemote: [ReadInterface]?
|
||||
var writeRemote: [WriteInterface]?
|
||||
|
||||
var localOnly: Bool = false
|
||||
|
||||
var localReadInterface: ReadInterface
|
||||
var localWriteInterface: WriteInterface
|
||||
var remoteReadInterface: ReadInterface?
|
||||
var remoteWriteInterface: WriteInterface?
|
||||
|
||||
/// UI state variables
|
||||
var selectedCategory: Category? = nil
|
||||
var selectedRecipe: RecipeStub? = nil
|
||||
var navigationPath: NavigationPath = NavigationPath()
|
||||
var selectedRecipeStub: RecipeStub? = nil
|
||||
var showSettings: Bool = false
|
||||
var showGroceries: Bool = false
|
||||
|
||||
/// Grocery List
|
||||
var groceryList = GroceryList()
|
||||
|
||||
init(
|
||||
readLocal: ReadInterface,
|
||||
writeLocal: WriteInterface,
|
||||
readRemote: [ReadInterface] = [],
|
||||
writeRemote: [WriteInterface] = []
|
||||
localReadInterface: ReadInterface,
|
||||
localWriteInterface: WriteInterface,
|
||||
remoteReadInterface: ReadInterface? = nil,
|
||||
remoteWriteInterface: WriteInterface? = nil
|
||||
|
||||
) {
|
||||
self.readLocal = readLocal
|
||||
self.writeLocal = writeLocal
|
||||
self.readRemote = readRemote
|
||||
self.writeRemote = writeRemote
|
||||
self.localReadInterface = localReadInterface
|
||||
self.localWriteInterface = localWriteInterface
|
||||
self.remoteReadInterface = remoteReadInterface
|
||||
self.remoteWriteInterface = remoteWriteInterface
|
||||
}
|
||||
|
||||
init() {
|
||||
let accountLoader = AccountLoader()
|
||||
rI, wI = accountLoader.load
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension CookbookState {
|
||||
func removeRecipe(_ id: String) {
|
||||
for key in recipeStubs.keys {
|
||||
recipeStubs[key]?.removeAll(where: { $0.id == id })
|
||||
}
|
||||
recipes.removeValue(forKey: id)
|
||||
thumbnails.removeValue(forKey: id)
|
||||
images.removeValue(forKey: id)
|
||||
}
|
||||
|
||||
func imgToCache(_ image: UIImage, id: String, size: RecipeImage.RecipeImageSize) {
|
||||
if size == .THUMB {
|
||||
thumbnails[id] = image
|
||||
} else {
|
||||
images[id] = image
|
||||
}
|
||||
}
|
||||
|
||||
func imgFromCache(id: String, size: RecipeImage.RecipeImageSize) -> UIImage? {
|
||||
if size == .THUMB {
|
||||
return thumbnails[id]
|
||||
} else {
|
||||
return images[id]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension CookbookState: ReadInterface {
|
||||
func getImage(id: String, size: RecipeImage.RecipeImageSize) async -> UIImage? {
|
||||
if let image = imgFromCache(id: id, size: size) {
|
||||
return image
|
||||
}
|
||||
|
||||
if !localOnly, let readRemote {
|
||||
if let image = await readRemote.getImage(id: id, size: size) {
|
||||
return image
|
||||
}
|
||||
}
|
||||
|
||||
if let image = await readLocal.getImage(id: id, size: size) {
|
||||
return image
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getRecipeStubs() async -> [RecipeStub]? {
|
||||
if !localOnly, let readRemote {
|
||||
if let stubs = await readRemote.getRecipeStubs() {
|
||||
return stubs
|
||||
}
|
||||
}
|
||||
|
||||
if categories.isEmpty {
|
||||
self.categories = await readLocal.getCategories() ?? []
|
||||
}
|
||||
|
||||
for category in self.categories {
|
||||
self.recipeStubs[category.name] = await readLocal.getRecipeStubsForCategory(named: category.name)
|
||||
}
|
||||
|
||||
return self.recipeStubs.flatMap({_, val in val})
|
||||
}
|
||||
|
||||
func getRecipe(id: String) async -> Recipe? {
|
||||
if let recipe = self.recipes[id] {
|
||||
return recipe
|
||||
}
|
||||
|
||||
if !localOnly, let readRemote {
|
||||
if let recipe = await readRemote.getRecipe(id: id) {
|
||||
return recipe
|
||||
}
|
||||
}
|
||||
|
||||
return await readLocal.getRecipe(id: id)
|
||||
}
|
||||
|
||||
func getCategories() async -> [Category]? {
|
||||
if !localOnly, let readRemote {
|
||||
if let categories = await readRemote.getCategories() {
|
||||
func loadCategories(remoteFirst: Bool = false) async {
|
||||
if remoteFirst {
|
||||
if let remoteReadInterface, let categories = await remoteReadInterface.getCategories() {
|
||||
self.categories = categories
|
||||
return categories
|
||||
return
|
||||
}
|
||||
|
||||
if let categories = await localReadInterface.getCategories() {
|
||||
self.categories = categories
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if let categories = await localReadInterface.getCategories() {
|
||||
self.categories = categories
|
||||
return
|
||||
}
|
||||
|
||||
guard let remoteReadInterface else { return }
|
||||
if let categories = await remoteReadInterface.getCategories() {
|
||||
self.categories = categories
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if self.categories.isEmpty, let categories = await readLocal.getCategories() {
|
||||
self.categories = categories
|
||||
return categories
|
||||
}
|
||||
|
||||
return self.categories
|
||||
}
|
||||
|
||||
func getRecipeStubsForCategory(named categoryName: String) async -> [RecipeStub]? {
|
||||
if let stubs = self.recipeStubs[categoryName] {
|
||||
return stubs
|
||||
}
|
||||
|
||||
if !localOnly, let readRemote {
|
||||
if let stubs = await readRemote.getRecipeStubsForCategory(named: categoryName) {
|
||||
self.recipeStubs[categoryName] = stubs
|
||||
func loadRecipeStubs(category: String, remoteFirst: Bool = false) async {
|
||||
if remoteFirst {
|
||||
if let remoteReadInterface, let stubs = await remoteReadInterface.getRecipeStubs() {
|
||||
self.recipeStubs[category] = stubs
|
||||
return
|
||||
}
|
||||
|
||||
if let stubs = await localReadInterface.getRecipeStubs() {
|
||||
self.recipeStubs[category] = stubs
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if let stubs = await localReadInterface.getRecipeStubs() {
|
||||
self.recipeStubs[category] = stubs
|
||||
return
|
||||
}
|
||||
|
||||
guard let remoteReadInterface else { return }
|
||||
if let stubs = await remoteReadInterface.getRecipeStubs() {
|
||||
self.recipeStubs[category] = stubs
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if let stubs = await readLocal.getRecipeStubsForCategory(named: categoryName) {
|
||||
self.recipeStubs[categoryName] = stubs
|
||||
return stubs
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getTags() async -> [RecipeKeyword]? {
|
||||
if !keywords.isEmpty {
|
||||
return keywords
|
||||
}
|
||||
|
||||
if !localOnly, let readRemote {
|
||||
if let tags = await readRemote.getTags() {
|
||||
self.keywords = tags
|
||||
func loadKeywords(remoteFirst: Bool = false) async {
|
||||
if remoteFirst {
|
||||
if let remoteReadInterface, let keywords = await remoteReadInterface.getTags() {
|
||||
self.keywords = keywords
|
||||
return
|
||||
}
|
||||
|
||||
if let keywords = await localReadInterface.getTags() {
|
||||
self.keywords = keywords
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if let keywords = await localReadInterface.getTags() {
|
||||
self.keywords = keywords
|
||||
return
|
||||
}
|
||||
|
||||
guard let remoteReadInterface else { return }
|
||||
if let keywords = await remoteReadInterface.getTags() {
|
||||
self.keywords = keywords
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return await readLocal.getTags()
|
||||
}
|
||||
|
||||
func getRecipesTagged(keyword: String) async -> [RecipeStub]? {
|
||||
if !localOnly, let readRemote {
|
||||
if let stubs = await readRemote.getRecipesTagged(keyword: keyword) {
|
||||
return stubs
|
||||
func loadRecipe(id: String, remoteFirst: Bool = false) async {
|
||||
if remoteFirst {
|
||||
if let remoteReadInterface, let recipe = await remoteReadInterface.getRecipe(id: id) {
|
||||
self.recipes[id] = recipe
|
||||
return
|
||||
}
|
||||
|
||||
if let recipe = await localReadInterface.getRecipe(id: id) {
|
||||
self.recipes[id] = recipe
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if let recipe = await localReadInterface.getRecipe(id: id) {
|
||||
self.recipes[id] = recipe
|
||||
return
|
||||
}
|
||||
|
||||
guard let remoteReadInterface else { return }
|
||||
if let recipe = await remoteReadInterface.getRecipe(id: id) {
|
||||
self.recipes[id] = recipe
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return await getRecipeStubs()?.filter({ recipe in
|
||||
recipe.keywords?.contains(keyword.lowercased()) ?? false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
extension CookbookState: WriteInterface {
|
||||
func postImage(id: String, image: UIImage, size: RecipeImage.RecipeImageSize) async -> ((any UserAlert)?) {
|
||||
let _ = await writeLocal.postImage(id: id, image: image, size: size)
|
||||
let _ = await writeRemote?.postImage(id: id, image: image, size: size)
|
||||
return nil
|
||||
}
|
||||
|
||||
func postRecipe(recipe: Recipe) async -> ((any UserAlert)?) {
|
||||
let _ = await writeLocal.postRecipe(recipe: recipe)
|
||||
let _ = await writeRemote?.postRecipe(recipe: recipe)
|
||||
return nil
|
||||
}
|
||||
|
||||
func updateRecipe(recipe: Recipe) async -> ((any UserAlert)?) {
|
||||
let _ = await writeLocal.updateRecipe(recipe: recipe)
|
||||
let _ = await writeRemote?.updateRecipe(recipe: recipe)
|
||||
return nil
|
||||
}
|
||||
|
||||
func deleteRecipe(id: String) async -> ((any UserAlert)?) {
|
||||
let _ = await writeLocal.deleteRecipe(id: id)
|
||||
let _ = await writeRemote?.deleteRecipe(id: id)
|
||||
return nil
|
||||
}
|
||||
|
||||
func renameCategory(named categoryName: String, newName: String) async -> ((any UserAlert)?) {
|
||||
let _ = await writeLocal.renameCategory(named: categoryName, newName: newName)
|
||||
let _ = await writeRemote?.renameCategory(named: categoryName, newName: newName)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension AccountState: Hashable, Identifiable {
|
||||
static func == (lhs: AccountState, rhs: AccountState) -> Bool {
|
||||
lhs.id == rhs.id
|
||||
|
||||
class AccountLoader {
|
||||
func initInterfaces() async -> [ReadInterface & WriteInterface] {
|
||||
let accounts = await self.loadAccounts("accounts.data")
|
||||
|
||||
if accounts.isEmpty && UserSettings.shared.serverAddress != "" {
|
||||
print("Creating new Account from legacy Cookbook client account.")
|
||||
let auth = Authentication(
|
||||
baseUrl: UserSettings.shared.serverAddress,
|
||||
user: UserSettings.shared.username,
|
||||
token: UserSettings.shared.authString
|
||||
)
|
||||
let authKey = "legacyNextcloud"
|
||||
let legacyAccount = Account(
|
||||
id: UUID(),
|
||||
name: "Nextcloud",
|
||||
type: .nextcloud,
|
||||
apiVersion: "1.0",
|
||||
authKey: authKey
|
||||
)
|
||||
await saveAccounts([legacyAccount], "accounts.data")
|
||||
legacyAccount.storeAuth(auth)
|
||||
|
||||
let interface = NextcloudDataInterface(auth: auth, version: legacyAccount.apiVersion)
|
||||
return [interface]
|
||||
} else {
|
||||
print("Recovering existing accounts.")
|
||||
var interfaces: [ReadInterface & WriteInterface] = []
|
||||
for account in accounts {
|
||||
if let interface: CookbookInterface = account.getInterface() {
|
||||
interfaces.append(interface)
|
||||
}
|
||||
}
|
||||
return interfaces
|
||||
}
|
||||
}
|
||||
|
||||
func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(id)
|
||||
func loadAccounts(_ path: String) async -> [Account] {
|
||||
do {
|
||||
return try await DataStore.shared.load(fromPath: path) ?? []
|
||||
} catch (let error) {
|
||||
print(error)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
func saveAccounts(_ accounts: [Account], _ path: String) async {
|
||||
await DataStore.shared.save(data: accounts, toPath: path)
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
@@ -9,7 +9,7 @@ import Foundation
|
||||
import SwiftUI
|
||||
import KeychainSwift
|
||||
|
||||
|
||||
/*
|
||||
protocol CookbookInterface {
|
||||
/// A unique id of the interface. Used to associate recipes to their respective accounts.
|
||||
var id: String { get }
|
||||
@@ -24,12 +24,12 @@ protocol ReadInterface {
|
||||
func getImage(
|
||||
id: String,
|
||||
size: RecipeImage.RecipeImageSize
|
||||
) async -> (UIImage?, UserAlert?)
|
||||
) async -> UIImage?
|
||||
|
||||
/// Get all recipe stubs.
|
||||
/// - Returns: A list of all recipes.
|
||||
func getRecipeStubs(
|
||||
) async -> ([RecipeStub]?, UserAlert?)
|
||||
) async -> [RecipeStub]?
|
||||
|
||||
/// Get the recipe with the specified id.
|
||||
/// - Parameters:
|
||||
@@ -37,12 +37,12 @@ protocol ReadInterface {
|
||||
/// - Returns: The recipe if it exists. A UserAlert if the request fails.
|
||||
func getRecipe(
|
||||
id: String
|
||||
) async -> (Recipe?, UserAlert?)
|
||||
) async -> Recipe?
|
||||
|
||||
/// Get all categories.
|
||||
/// - Returns: A list of categories. A UserAlert if the request fails.
|
||||
func getCategories(
|
||||
) async -> ([Category]?, UserAlert?)
|
||||
) async -> [Category]?
|
||||
|
||||
/// Get all recipes of a specified category.
|
||||
/// - Parameters:
|
||||
@@ -50,12 +50,12 @@ protocol ReadInterface {
|
||||
/// - Returns: A list of recipes. A UserAlert if the request fails.
|
||||
func getRecipeStubsForCategory(
|
||||
named categoryName: String
|
||||
) async -> ([RecipeStub]?, UserAlert?)
|
||||
) async -> [RecipeStub]?
|
||||
|
||||
/// Get all keywords/tags.
|
||||
/// - Returns: A list of tag strings. A UserAlert if the request fails.
|
||||
func getTags(
|
||||
) async -> ([RecipeKeyword]?, UserAlert?)
|
||||
) async -> [RecipeKeyword]?
|
||||
|
||||
/// Get all recipes tagged with the specified keyword.
|
||||
/// - Parameters:
|
||||
@@ -63,7 +63,7 @@ protocol ReadInterface {
|
||||
/// - Returns: A list of recipes tagged with the specified keyword. A UserAlert if the request fails.
|
||||
func getRecipesTagged(
|
||||
keyword: String
|
||||
) async -> ([RecipeStub]?, UserAlert?)
|
||||
) async -> [RecipeStub]?
|
||||
}
|
||||
|
||||
protocol WriteInterface {
|
||||
@@ -111,3 +111,4 @@ protocol WriteInterface {
|
||||
newName: String
|
||||
) async -> (UserAlert?)
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
/*
|
||||
|
||||
class LocalDataInterface: CookbookInterface {
|
||||
var id: String
|
||||
@@ -49,49 +49,36 @@ class LocalDataInterface: CookbookInterface {
|
||||
// MARK: - Local Read Interface
|
||||
|
||||
extension LocalDataInterface: ReadInterface {
|
||||
|
||||
func getImage(id: String, size: RecipeImage.RecipeImageSize) async -> (UIImage?, (any UserAlert)?) {
|
||||
func getImage(id: String, size: RecipeImage.RecipeImageSize) async -> UIImage? {
|
||||
guard let data: String = await load(path: .image(id: id, size: size)) else {
|
||||
return (nil, PersistenceAlert.LOAD_FAILED)
|
||||
return nil
|
||||
}
|
||||
guard let dataDecoded = Data(base64Encoded: data) else { return (nil, PersistenceAlert.DECODING_FAILED) }
|
||||
if let image = UIImage(data: dataDecoded) {
|
||||
return (image, nil)
|
||||
}
|
||||
return (nil, nil)
|
||||
guard let dataDecoded = Data(base64Encoded: data) else { return nil }
|
||||
return UIImage(data: dataDecoded)
|
||||
}
|
||||
|
||||
func getRecipeStubs() async -> ([RecipeStub]?, (any UserAlert)?) {
|
||||
return (nil, PersistenceAlert.LOAD_FAILED)
|
||||
func getRecipeStubs() async -> [RecipeStub]? {
|
||||
return nil
|
||||
}
|
||||
|
||||
func getRecipe(id: String) async -> (Recipe?, (any UserAlert)?) {
|
||||
if let recipe: Recipe? = await load(path: LocalDataPath.recipe(id: id)) {
|
||||
return (recipe, nil)
|
||||
}
|
||||
return (nil, nil)
|
||||
func getRecipe(id: String) async -> Recipe? {
|
||||
return await load(path: LocalDataPath.recipe(id: id))
|
||||
}
|
||||
|
||||
func getCategories() async -> ([Category]?, (any UserAlert)?) {
|
||||
return (await load(path: LocalDataPath.categories), nil)
|
||||
func getCategories() async -> [Category]? {
|
||||
return await load(path: LocalDataPath.categories)
|
||||
}
|
||||
|
||||
func getRecipeStubsForCategory(named categoryName: String) async -> ([RecipeStub]?, (any UserAlert)?) {
|
||||
if let stubs: [RecipeStub] = await load(path: .recipeStubs(category: categoryName)) {
|
||||
return (stubs, nil)
|
||||
}
|
||||
return (nil, PersistenceAlert.LOAD_FAILED)
|
||||
func getRecipeStubsForCategory(named categoryName: String) async -> [RecipeStub]? {
|
||||
return await load(path: .recipeStubs(category: categoryName))
|
||||
}
|
||||
|
||||
func getTags() async -> ([RecipeKeyword]?, (any UserAlert)?) {
|
||||
if let keywords: [RecipeKeyword] = await load(path: .keywords) {
|
||||
return (keywords, nil)
|
||||
}
|
||||
return (nil, PersistenceAlert.LOAD_FAILED)
|
||||
func getTags() async -> [RecipeKeyword]? {
|
||||
return await load(path: .keywords)
|
||||
}
|
||||
|
||||
func getRecipesTagged(keyword: String) async -> ([RecipeStub]?, (any UserAlert)?) {
|
||||
return (nil, PersistenceAlert.LOAD_FAILED)
|
||||
func getRecipesTagged(keyword: String) async -> [RecipeStub]? {
|
||||
return nil
|
||||
}
|
||||
|
||||
}
|
||||
@@ -109,6 +96,7 @@ extension LocalDataInterface: WriteInterface {
|
||||
path: LocalDataPath.image(id: id, size: size)
|
||||
)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func postRecipe(recipe: Recipe) async -> ((any UserAlert)?) {
|
||||
@@ -129,8 +117,9 @@ extension LocalDataInterface: WriteInterface {
|
||||
guard let stubs: [RecipeStub] = await load(path: .recipeStubs(category: categoryName)) else {
|
||||
return PersistenceAlert.LOAD_FAILED
|
||||
}
|
||||
await delete(path: .recipeStubs(category: categoryName))
|
||||
await save(stubs, path: .recipeStubs(category: newName))
|
||||
await delete(path: .recipeStubs(category: categoryName))
|
||||
return nil
|
||||
}
|
||||
|
||||
}
|
||||
@@ -159,3 +148,4 @@ extension LocalDataInterface {
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
|
||||
/*
|
||||
class NextcloudDataInterface: CookbookInterface {
|
||||
var id: String
|
||||
|
||||
@@ -31,39 +31,35 @@ class NextcloudDataInterface: CookbookInterface {
|
||||
// MARK: - Nextcloud Read Interface
|
||||
extension NextcloudDataInterface: ReadInterface {
|
||||
|
||||
func getImage(id: String, size: RecipeImage.RecipeImageSize) async -> (UIImage?, UserAlert?) {
|
||||
let (image, error) = await api.getImage(auth: auth.token, id: id, size: size)
|
||||
if let image {
|
||||
return (image, nil)
|
||||
}
|
||||
return (nil, error)
|
||||
func getImage(id: String, size: RecipeImage.RecipeImageSize) async -> UIImage? {
|
||||
return await api.getImage(auth: auth.token, id: id, size: size).0
|
||||
}
|
||||
|
||||
func getRecipeStubs() async -> ([RecipeStub]?, UserAlert?) {
|
||||
return await api.getRecipes(auth: auth.token)
|
||||
func getRecipeStubs() async -> [RecipeStub]? {
|
||||
return await api.getRecipes(auth: auth.token).0
|
||||
}
|
||||
|
||||
func getRecipe(id: String) async -> (Recipe?, UserAlert?) {
|
||||
return await api.getRecipe(auth: auth.token, id: id)
|
||||
func getRecipe(id: String) async -> Recipe?{
|
||||
return await api.getRecipe(auth: auth.token, id: id).0
|
||||
}
|
||||
|
||||
func getCategories() async -> ([Category]?, UserAlert?) {
|
||||
return await api.getCategories(auth: auth.token)
|
||||
func getCategories() async -> [Category]? {
|
||||
return await api.getCategories(auth: auth.token).0
|
||||
}
|
||||
|
||||
func getRecipeStubsForCategory(named categoryName: String) async -> ([RecipeStub]?, UserAlert?) {
|
||||
func getRecipeStubsForCategory(named categoryName: String) async -> [RecipeStub]? {
|
||||
return await api.getCategory(
|
||||
auth: UserSettings.shared.authString,
|
||||
named: categoryName
|
||||
)
|
||||
).0
|
||||
}
|
||||
|
||||
func getTags() async -> ([RecipeKeyword]?, (any UserAlert)?) {
|
||||
return await api.getTags(auth: auth.token)
|
||||
func getTags() async -> [RecipeKeyword]? {
|
||||
return await api.getTags(auth: auth.token).0
|
||||
}
|
||||
|
||||
func getRecipesTagged(keyword: String) async -> ([RecipeStub]?, UserAlert?) {
|
||||
return await api.getRecipesTagged(auth: auth.token, keyword: keyword)
|
||||
func getRecipesTagged(keyword: String) async -> [RecipeStub]? {
|
||||
return await api.getRecipesTagged(auth: auth.token, keyword: keyword).0
|
||||
}
|
||||
|
||||
}
|
||||
@@ -93,3 +89,4 @@ extension NextcloudDataInterface: WriteInterface {
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user