users can now choose between http and https
This commit is contained in:
Binary file not shown.
@@ -37,6 +37,12 @@ class UserSettings: ObservableObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Published var serverProtocol: String {
|
||||||
|
didSet {
|
||||||
|
UserDefaults.standard.set(serverProtocol, forKey: "serverProtocol")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Published var onboarding: Bool {
|
@Published var onboarding: Bool {
|
||||||
didSet {
|
didSet {
|
||||||
UserDefaults.standard.set(onboarding, forKey: "onboarding")
|
UserDefaults.standard.set(onboarding, forKey: "onboarding")
|
||||||
@@ -102,6 +108,7 @@ class UserSettings: ObservableObject {
|
|||||||
self.token = UserDefaults.standard.object(forKey: "token") as? String ?? ""
|
self.token = UserDefaults.standard.object(forKey: "token") as? String ?? ""
|
||||||
self.authString = UserDefaults.standard.object(forKey: "authString") as? String ?? ""
|
self.authString = UserDefaults.standard.object(forKey: "authString") as? String ?? ""
|
||||||
self.serverAddress = UserDefaults.standard.object(forKey: "serverAddress") as? String ?? ""
|
self.serverAddress = UserDefaults.standard.object(forKey: "serverAddress") as? String ?? ""
|
||||||
|
self.serverProtocol = UserDefaults.standard.object(forKey: "serverProtocol") as? String ?? "https://"
|
||||||
self.onboarding = UserDefaults.standard.object(forKey: "onboarding") as? Bool ?? true
|
self.onboarding = UserDefaults.standard.object(forKey: "onboarding") as? Bool ?? true
|
||||||
self.defaultCategory = UserDefaults.standard.object(forKey: "defaultCategory") as? String ?? ""
|
self.defaultCategory = UserDefaults.standard.object(forKey: "defaultCategory") as? String ?? ""
|
||||||
self.language = UserDefaults.standard.object(forKey: "language") as? String ?? SupportedLanguage.DEVICE.rawValue
|
self.language = UserDefaults.standard.object(forKey: "language") as? String ?? SupportedLanguage.DEVICE.rawValue
|
||||||
|
|||||||
@@ -710,6 +710,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"Copy Link" : {
|
||||||
|
|
||||||
},
|
},
|
||||||
"Could not establish a connection to the server. The action will be retried upon reconnection." : {
|
"Could not establish a connection to the server. The action will be retried upon reconnection." : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@@ -952,6 +955,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"e.g.: example.com" : {
|
||||||
|
|
||||||
},
|
},
|
||||||
"Edit" : {
|
"Edit" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@@ -1152,6 +1158,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"If the login button does not open your browser, copy the following link and paste it in your browser manually:" : {
|
"If the login button does not open your browser, copy the following link and paste it in your browser manually:" : {
|
||||||
|
"extractionState" : "stale",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"de" : {
|
"de" : {
|
||||||
"stringUnit" : {
|
"stringUnit" : {
|
||||||
@@ -1172,6 +1179,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"If the login button does not open your browser, use the 'Copy Link' button and paste the link in your browser manually." : {
|
||||||
|
|
||||||
},
|
},
|
||||||
"If you are interested in contributing to this project or simply wish to review its source code, we encourage you to visit the GitHub repository for this application." : {
|
"If you are interested in contributing to this project or simply wish to review its source code, we encourage you to visit the GitHub repository for this application." : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@@ -1574,8 +1584,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"Make sure to enter the server address in the form 'example.com', or \n'<server address>:<port>'\n when a non-standard port is used." : {
|
||||||
|
|
||||||
},
|
},
|
||||||
"Make sure to enter the server address in the form 'example.com'. Currently, only servers using the 'https' protocol are supported." : {
|
"Make sure to enter the server address in the form 'example.com'. Currently, only servers using the 'https' protocol are supported." : {
|
||||||
|
"extractionState" : "stale",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"de" : {
|
"de" : {
|
||||||
"stringUnit" : {
|
"stringUnit" : {
|
||||||
@@ -2828,9 +2842,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"Use a non-standard port" : {
|
|
||||||
|
|
||||||
},
|
},
|
||||||
"Validate" : {
|
"Validate" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ import Foundation
|
|||||||
import OSLog
|
import OSLog
|
||||||
|
|
||||||
struct ApiRequest {
|
struct ApiRequest {
|
||||||
/// The server address, e.g. https://example.com
|
|
||||||
let serverAddress: String
|
|
||||||
let path: String
|
let path: String
|
||||||
let method: RequestMethod
|
let method: RequestMethod
|
||||||
let authString: String?
|
let authString: String?
|
||||||
@@ -21,14 +19,12 @@ struct ApiRequest {
|
|||||||
let cookbookPath = "/index.php/apps/cookbook"
|
let cookbookPath = "/index.php/apps/cookbook"
|
||||||
|
|
||||||
init(
|
init(
|
||||||
serverAdress: String,
|
|
||||||
path: String,
|
path: String,
|
||||||
method: RequestMethod,
|
method: RequestMethod,
|
||||||
authString: String? = nil,
|
authString: String? = nil,
|
||||||
headerFields: [HeaderField] = [],
|
headerFields: [HeaderField] = [],
|
||||||
body: Data? = nil
|
body: Data? = nil
|
||||||
) {
|
) {
|
||||||
self.serverAddress = serverAdress
|
|
||||||
self.method = method
|
self.method = method
|
||||||
self.path = path
|
self.path = path
|
||||||
self.headerFields = headerFields
|
self.headerFields = headerFields
|
||||||
@@ -40,7 +36,7 @@ struct ApiRequest {
|
|||||||
Logger.network.debug("\(method.rawValue) \(path) sending ...")
|
Logger.network.debug("\(method.rawValue) \(path) sending ...")
|
||||||
|
|
||||||
// Prepare URL
|
// Prepare URL
|
||||||
let urlString = "https://" + serverAddress + cookbookPath + path
|
let urlString = UserSettings.shared.serverProtocol + UserSettings.shared.serverAddress + cookbookPath + path
|
||||||
print("Full path: \(urlString)")
|
print("Full path: \(urlString)")
|
||||||
//Logger.network.debug("Full path: \(urlString)")
|
//Logger.network.debug("Full path: \(urlString)")
|
||||||
guard let urlStringSanitized = urlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else { return (nil, .unknownError) }
|
guard let urlStringSanitized = urlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else { return (nil, .unknownError) }
|
||||||
|
|||||||
@@ -13,20 +13,17 @@ import UIKit
|
|||||||
protocol CookbookApi {
|
protocol CookbookApi {
|
||||||
/// Not implemented yet.
|
/// Not implemented yet.
|
||||||
static func importRecipe(
|
static func importRecipe(
|
||||||
from serverAdress: String,
|
|
||||||
auth: String,
|
auth: String,
|
||||||
data: Data
|
data: Data
|
||||||
) async -> (RecipeDetail?, NetworkError?)
|
) async -> (RecipeDetail?, NetworkError?)
|
||||||
|
|
||||||
/// Get either the full image or a thumbnail sized version.
|
/// Get either the full image or a thumbnail sized version.
|
||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - serverAdress: Server address in the format https://example.com.
|
|
||||||
/// - auth: Server authentication string.
|
/// - auth: Server authentication string.
|
||||||
/// - id: The according recipe id.
|
/// - id: The according recipe id.
|
||||||
/// - size: The size of the image.
|
/// - size: The size of the image.
|
||||||
/// - Returns: The image of the recipe with the specified id. A NetworkError if the request fails, otherwise nil.
|
/// - Returns: The image of the recipe with the specified id. A NetworkError if the request fails, otherwise nil.
|
||||||
static func getImage(
|
static func getImage(
|
||||||
from serverAdress: String,
|
|
||||||
auth: String,
|
auth: String,
|
||||||
id: Int,
|
id: Int,
|
||||||
size: RecipeImage.RecipeImageSize
|
size: RecipeImage.RecipeImageSize
|
||||||
@@ -34,91 +31,75 @@ protocol CookbookApi {
|
|||||||
|
|
||||||
/// Get all recipes.
|
/// Get all recipes.
|
||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - serverAdress: Server address in the format https://example.com.
|
|
||||||
/// - auth: Server authentication string.
|
/// - auth: Server authentication string.
|
||||||
/// - Returns: A list of all recipes.
|
/// - Returns: A list of all recipes.
|
||||||
static func getRecipes(
|
static func getRecipes(
|
||||||
from serverAdress: String,
|
|
||||||
auth: String
|
auth: String
|
||||||
) async -> ([Recipe]?, NetworkError?)
|
) async -> ([Recipe]?, NetworkError?)
|
||||||
|
|
||||||
/// Create a new recipe.
|
/// Create a new recipe.
|
||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - serverAdress: Server address in the format https://example.com.
|
|
||||||
/// - auth: Server authentication string.
|
/// - auth: Server authentication string.
|
||||||
/// - Returns: A NetworkError if the request fails. Nil otherwise.
|
/// - Returns: A NetworkError if the request fails. Nil otherwise.
|
||||||
static func createRecipe(
|
static func createRecipe(
|
||||||
from serverAdress: String,
|
|
||||||
auth: String,
|
auth: String,
|
||||||
recipe: RecipeDetail
|
recipe: RecipeDetail
|
||||||
) async -> (NetworkError?)
|
) async -> (NetworkError?)
|
||||||
|
|
||||||
/// Get the recipe with the specified id.
|
/// Get the recipe with the specified id.
|
||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - serverAdress: Server address in the format https://example.com.
|
|
||||||
/// - auth: Server authentication string.
|
/// - auth: Server authentication string.
|
||||||
/// - id: The recipe id.
|
/// - id: The recipe id.
|
||||||
/// - Returns: The recipe if it exists. A NetworkError if the request fails.
|
/// - Returns: The recipe if it exists. A NetworkError if the request fails.
|
||||||
static func getRecipe(
|
static func getRecipe(
|
||||||
from serverAdress: String,
|
|
||||||
auth: String, id: Int
|
auth: String, id: Int
|
||||||
) async -> (RecipeDetail?, NetworkError?)
|
) async -> (RecipeDetail?, NetworkError?)
|
||||||
|
|
||||||
/// Update an existing recipe with new entries.
|
/// Update an existing recipe with new entries.
|
||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - serverAdress: Server address in the format https://example.com.
|
|
||||||
/// - auth: Server authentication string.
|
/// - auth: Server authentication string.
|
||||||
/// - id: The recipe id.
|
/// - id: The recipe id.
|
||||||
/// - Returns: A NetworkError if the request fails. Nil otherwise.
|
/// - Returns: A NetworkError if the request fails. Nil otherwise.
|
||||||
static func updateRecipe(
|
static func updateRecipe(
|
||||||
from serverAdress: String,
|
|
||||||
auth: String,
|
auth: String,
|
||||||
recipe: RecipeDetail
|
recipe: RecipeDetail
|
||||||
) async -> (NetworkError?)
|
) async -> (NetworkError?)
|
||||||
|
|
||||||
/// Delete the recipe with the specified id.
|
/// Delete the recipe with the specified id.
|
||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - serverAdress: Server address in the format https://example.com.
|
|
||||||
/// - auth: Server authentication string.
|
/// - auth: Server authentication string.
|
||||||
/// - id: The recipe id.
|
/// - id: The recipe id.
|
||||||
/// - Returns: A NetworkError if the request fails. Nil otherwise.
|
/// - Returns: A NetworkError if the request fails. Nil otherwise.
|
||||||
static func deleteRecipe(
|
static func deleteRecipe(
|
||||||
from serverAdress: String,
|
|
||||||
auth: String,
|
auth: String,
|
||||||
id: Int
|
id: Int
|
||||||
) async -> (NetworkError?)
|
) async -> (NetworkError?)
|
||||||
|
|
||||||
/// Get all categories.
|
/// Get all categories.
|
||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - serverAdress: Server address in the format https://example.com.
|
|
||||||
/// - auth: Server authentication string.
|
/// - auth: Server authentication string.
|
||||||
/// - Returns: A list of categories. A NetworkError if the request fails.
|
/// - Returns: A list of categories. A NetworkError if the request fails.
|
||||||
static func getCategories(
|
static func getCategories(
|
||||||
from serverAdress: String,
|
|
||||||
auth: String
|
auth: String
|
||||||
) async -> ([Category]?, NetworkError?)
|
) async -> ([Category]?, NetworkError?)
|
||||||
|
|
||||||
/// Get all recipes of a specified category.
|
/// Get all recipes of a specified category.
|
||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - serverAdress: Server address in the format https://example.com.
|
|
||||||
/// - auth: Server authentication string.
|
/// - auth: Server authentication string.
|
||||||
/// - categoryName: The category name.
|
/// - categoryName: The category name.
|
||||||
/// - Returns: A list of recipes. A NetworkError if the request fails.
|
/// - Returns: A list of recipes. A NetworkError if the request fails.
|
||||||
static func getCategory(
|
static func getCategory(
|
||||||
from serverAdress: String,
|
|
||||||
auth: String,
|
auth: String,
|
||||||
named categoryName: String
|
named categoryName: String
|
||||||
) async -> ([Recipe]?, NetworkError?)
|
) async -> ([Recipe]?, NetworkError?)
|
||||||
|
|
||||||
/// Rename an existing category.
|
/// Rename an existing category.
|
||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - serverAdress: Server address in the format https://example.com.
|
|
||||||
/// - auth: Server authentication string.
|
/// - auth: Server authentication string.
|
||||||
/// - categoryName: The name of the category to be renamed.
|
/// - categoryName: The name of the category to be renamed.
|
||||||
/// - newName: The new category name.
|
/// - newName: The new category name.
|
||||||
/// - Returns: A NetworkError if the request fails.
|
/// - Returns: A NetworkError if the request fails.
|
||||||
static func renameCategory(
|
static func renameCategory(
|
||||||
from serverAdress: String,
|
|
||||||
auth: String,
|
auth: String,
|
||||||
named categoryName: String,
|
named categoryName: String,
|
||||||
newName: String
|
newName: String
|
||||||
@@ -126,63 +107,51 @@ protocol CookbookApi {
|
|||||||
|
|
||||||
/// Get all keywords/tags.
|
/// Get all keywords/tags.
|
||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - serverAdress: Server address in the format https://example.com.
|
|
||||||
/// - auth: Server authentication string.
|
/// - auth: Server authentication string.
|
||||||
/// - Returns: A list of tag strings. A NetworkError if the request fails.
|
/// - Returns: A list of tag strings. A NetworkError if the request fails.
|
||||||
static func getTags(
|
static func getTags(
|
||||||
from serverAdress: String,
|
|
||||||
auth: String
|
auth: String
|
||||||
) async -> ([RecipeKeyword]?, NetworkError?)
|
) async -> ([RecipeKeyword]?, NetworkError?)
|
||||||
|
|
||||||
/// Get all recipes tagged with the specified keyword.
|
/// Get all recipes tagged with the specified keyword.
|
||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - serverAdress: Server address in the format https://example.com.
|
|
||||||
/// - auth: Server authentication string.
|
/// - auth: Server authentication string.
|
||||||
/// - keyword: The keyword.
|
/// - keyword: The keyword.
|
||||||
/// - Returns: A list of recipes tagged with the specified keyword. A NetworkError if the request fails.
|
/// - Returns: A list of recipes tagged with the specified keyword. A NetworkError if the request fails.
|
||||||
static func getRecipesTagged(
|
static func getRecipesTagged(
|
||||||
from serverAdress: String,
|
|
||||||
auth: String,
|
auth: String,
|
||||||
keyword: String
|
keyword: String
|
||||||
) async -> ([Recipe]?, NetworkError?)
|
) async -> ([Recipe]?, NetworkError?)
|
||||||
|
|
||||||
/// Get the servers api version.
|
/// Get the servers api version.
|
||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - serverAdress: Server address in the format https://example.com.
|
|
||||||
/// - auth: Server authentication string.
|
/// - auth: Server authentication string.
|
||||||
/// - Returns: A NetworkError if the request fails.
|
/// - Returns: A NetworkError if the request fails.
|
||||||
static func getApiVersion(
|
static func getApiVersion(
|
||||||
from serverAdress: String,
|
|
||||||
auth: String
|
auth: String
|
||||||
) async -> (NetworkError?)
|
) async -> (NetworkError?)
|
||||||
|
|
||||||
/// Trigger a reindexing action on the server.
|
/// Trigger a reindexing action on the server.
|
||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - serverAdress: Server address in the format. https://example.com
|
|
||||||
/// - auth: Server authentication string
|
/// - auth: Server authentication string
|
||||||
/// - Returns: A NetworkError if the request fails.
|
/// - Returns: A NetworkError if the request fails.
|
||||||
static func postReindex(
|
static func postReindex(
|
||||||
from serverAdress: String,
|
|
||||||
auth: String
|
auth: String
|
||||||
) async -> (NetworkError?)
|
) async -> (NetworkError?)
|
||||||
|
|
||||||
/// Get the current configuration of the Cookbook server application.
|
/// Get the current configuration of the Cookbook server application.
|
||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - serverAdress: Server address in the format. https://example.com
|
|
||||||
/// - auth: Server authentication string
|
/// - auth: Server authentication string
|
||||||
/// - Returns: A NetworkError if the request fails.
|
/// - Returns: A NetworkError if the request fails.
|
||||||
static func getConfig(
|
static func getConfig(
|
||||||
from serverAdress: String,
|
|
||||||
auth: String
|
auth: String
|
||||||
) async -> (NetworkError?)
|
) async -> (NetworkError?)
|
||||||
|
|
||||||
/// Set the current configuration of the Cookbook server application.
|
/// Set the current configuration of the Cookbook server application.
|
||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - serverAdress: Server address in the format. https://example.com
|
|
||||||
/// - auth: Server authentication string
|
/// - auth: Server authentication string
|
||||||
/// - Returns: A NetworkError if the request fails.
|
/// - Returns: A NetworkError if the request fails.
|
||||||
static func postConfig(
|
static func postConfig(
|
||||||
from serverAdress: String,
|
|
||||||
auth: String
|
auth: String
|
||||||
) async -> (NetworkError?)
|
) async -> (NetworkError?)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,9 +10,8 @@ import UIKit
|
|||||||
|
|
||||||
|
|
||||||
class CookbookApiV1: CookbookApi {
|
class CookbookApiV1: CookbookApi {
|
||||||
static func importRecipe(from serverAdress: String, auth: String, data: Data) async -> (RecipeDetail?, NetworkError?) {
|
static func importRecipe(auth: String, data: Data) async -> (RecipeDetail?, NetworkError?) {
|
||||||
let request = ApiRequest(
|
let request = ApiRequest(
|
||||||
serverAdress: serverAdress,
|
|
||||||
path: "/api/v1/import",
|
path: "/api/v1/import",
|
||||||
method: .POST,
|
method: .POST,
|
||||||
authString: auth,
|
authString: auth,
|
||||||
@@ -24,10 +23,9 @@ class CookbookApiV1: CookbookApi {
|
|||||||
return (JSONDecoder.safeDecode(data), nil)
|
return (JSONDecoder.safeDecode(data), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func getImage(from serverAdress: String, auth: String, id: Int, size: RecipeImage.RecipeImageSize) async -> (UIImage?, NetworkError?) {
|
static func getImage(auth: String, id: Int, size: RecipeImage.RecipeImageSize) async -> (UIImage?, NetworkError?) {
|
||||||
let imageSize = (size == .FULL ? "full" : "thumb")
|
let imageSize = (size == .FULL ? "full" : "thumb")
|
||||||
let request = ApiRequest(
|
let request = ApiRequest(
|
||||||
serverAdress: serverAdress,
|
|
||||||
path: "/api/v1/recipes/\(id)/image?size=\(imageSize)",
|
path: "/api/v1/recipes/\(id)/image?size=\(imageSize)",
|
||||||
method: .GET,
|
method: .GET,
|
||||||
authString: auth,
|
authString: auth,
|
||||||
@@ -39,9 +37,8 @@ class CookbookApiV1: CookbookApi {
|
|||||||
return (UIImage(data: data), error)
|
return (UIImage(data: data), error)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func getRecipes(from serverAdress: String, auth: String) async -> ([Recipe]?, NetworkError?) {
|
static func getRecipes(auth: String) async -> ([Recipe]?, NetworkError?) {
|
||||||
let request = ApiRequest(
|
let request = ApiRequest(
|
||||||
serverAdress: serverAdress,
|
|
||||||
path: "/api/v1/recipes",
|
path: "/api/v1/recipes",
|
||||||
method: .GET,
|
method: .GET,
|
||||||
authString: auth,
|
authString: auth,
|
||||||
@@ -53,13 +50,12 @@ class CookbookApiV1: CookbookApi {
|
|||||||
return (JSONDecoder.safeDecode(data), nil)
|
return (JSONDecoder.safeDecode(data), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func createRecipe(from serverAdress: String, auth: String, recipe: RecipeDetail) async -> (NetworkError?) {
|
static func createRecipe(auth: String, recipe: RecipeDetail) async -> (NetworkError?) {
|
||||||
guard let recipeData = JSONEncoder.safeEncode(recipe) else {
|
guard let recipeData = JSONEncoder.safeEncode(recipe) else {
|
||||||
return .dataError
|
return .dataError
|
||||||
}
|
}
|
||||||
|
|
||||||
let request = ApiRequest(
|
let request = ApiRequest(
|
||||||
serverAdress: serverAdress,
|
|
||||||
path: "/api/v1/recipes",
|
path: "/api/v1/recipes",
|
||||||
method: .POST,
|
method: .POST,
|
||||||
authString: auth,
|
authString: auth,
|
||||||
@@ -82,9 +78,8 @@ class CookbookApiV1: CookbookApi {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
static func getRecipe(from serverAdress: String, auth: String, id: Int) async -> (RecipeDetail?, NetworkError?) {
|
static func getRecipe(auth: String, id: Int) async -> (RecipeDetail?, NetworkError?) {
|
||||||
let request = ApiRequest(
|
let request = ApiRequest(
|
||||||
serverAdress: serverAdress,
|
|
||||||
path: "/api/v1/recipes/\(id)",
|
path: "/api/v1/recipes/\(id)",
|
||||||
method: .GET,
|
method: .GET,
|
||||||
authString: auth,
|
authString: auth,
|
||||||
@@ -96,12 +91,11 @@ class CookbookApiV1: CookbookApi {
|
|||||||
return (JSONDecoder.safeDecode(data), nil)
|
return (JSONDecoder.safeDecode(data), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func updateRecipe(from serverAdress: String, auth: String, recipe: RecipeDetail) async -> (NetworkError?) {
|
static func updateRecipe(auth: String, recipe: RecipeDetail) async -> (NetworkError?) {
|
||||||
guard let recipeData = JSONEncoder.safeEncode(recipe) else {
|
guard let recipeData = JSONEncoder.safeEncode(recipe) else {
|
||||||
return .dataError
|
return .dataError
|
||||||
}
|
}
|
||||||
let request = ApiRequest(
|
let request = ApiRequest(
|
||||||
serverAdress: serverAdress,
|
|
||||||
path: "/api/v1/recipes/\(recipe.id)",
|
path: "/api/v1/recipes/\(recipe.id)",
|
||||||
method: .PUT,
|
method: .PUT,
|
||||||
authString: auth,
|
authString: auth,
|
||||||
@@ -124,9 +118,8 @@ class CookbookApiV1: CookbookApi {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
static func deleteRecipe(from serverAdress: String, auth: String, id: Int) async -> (NetworkError?) {
|
static func deleteRecipe(auth: String, id: Int) async -> (NetworkError?) {
|
||||||
let request = ApiRequest(
|
let request = ApiRequest(
|
||||||
serverAdress: serverAdress,
|
|
||||||
path: "/api/v1/recipes/\(id)",
|
path: "/api/v1/recipes/\(id)",
|
||||||
method: .DELETE,
|
method: .DELETE,
|
||||||
authString: auth,
|
authString: auth,
|
||||||
@@ -138,9 +131,8 @@ class CookbookApiV1: CookbookApi {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
static func getCategories(from serverAdress: String, auth: String) async -> ([Category]?, NetworkError?) {
|
static func getCategories(auth: String) async -> ([Category]?, NetworkError?) {
|
||||||
let request = ApiRequest(
|
let request = ApiRequest(
|
||||||
serverAdress: serverAdress,
|
|
||||||
path: "/api/v1/categories",
|
path: "/api/v1/categories",
|
||||||
method: .GET,
|
method: .GET,
|
||||||
authString: auth,
|
authString: auth,
|
||||||
@@ -152,9 +144,8 @@ class CookbookApiV1: CookbookApi {
|
|||||||
return (JSONDecoder.safeDecode(data), nil)
|
return (JSONDecoder.safeDecode(data), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func getCategory(from serverAdress: String, auth: String, named categoryName: String) async -> ([Recipe]?, NetworkError?) {
|
static func getCategory(auth: String, named categoryName: String) async -> ([Recipe]?, NetworkError?) {
|
||||||
let request = ApiRequest(
|
let request = ApiRequest(
|
||||||
serverAdress: serverAdress,
|
|
||||||
path: "/api/v1/category/\(categoryName)",
|
path: "/api/v1/category/\(categoryName)",
|
||||||
method: .GET,
|
method: .GET,
|
||||||
authString: auth,
|
authString: auth,
|
||||||
@@ -166,9 +157,8 @@ class CookbookApiV1: CookbookApi {
|
|||||||
return (JSONDecoder.safeDecode(data), nil)
|
return (JSONDecoder.safeDecode(data), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func renameCategory(from serverAdress: String, auth: String, named categoryName: String, newName: String) async -> (NetworkError?) {
|
static func renameCategory(auth: String, named categoryName: String, newName: String) async -> (NetworkError?) {
|
||||||
let request = ApiRequest(
|
let request = ApiRequest(
|
||||||
serverAdress: serverAdress,
|
|
||||||
path: "/api/v1/category/\(categoryName)",
|
path: "/api/v1/category/\(categoryName)",
|
||||||
method: .PUT,
|
method: .PUT,
|
||||||
authString: auth,
|
authString: auth,
|
||||||
@@ -180,9 +170,8 @@ class CookbookApiV1: CookbookApi {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
static func getTags(from serverAdress: String, auth: String) async -> ([RecipeKeyword]?, NetworkError?) {
|
static func getTags(auth: String) async -> ([RecipeKeyword]?, NetworkError?) {
|
||||||
let request = ApiRequest(
|
let request = ApiRequest(
|
||||||
serverAdress: serverAdress,
|
|
||||||
path: "/api/v1/keywords",
|
path: "/api/v1/keywords",
|
||||||
method: .GET,
|
method: .GET,
|
||||||
authString: auth,
|
authString: auth,
|
||||||
@@ -194,9 +183,8 @@ class CookbookApiV1: CookbookApi {
|
|||||||
return (JSONDecoder.safeDecode(data), nil)
|
return (JSONDecoder.safeDecode(data), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func getRecipesTagged(from serverAdress: String, auth: String, keyword: String) async -> ([Recipe]?, NetworkError?) {
|
static func getRecipesTagged(auth: String, keyword: String) async -> ([Recipe]?, NetworkError?) {
|
||||||
let request = ApiRequest(
|
let request = ApiRequest(
|
||||||
serverAdress: serverAdress,
|
|
||||||
path: "/api/v1/tags/\(keyword)",
|
path: "/api/v1/tags/\(keyword)",
|
||||||
method: .GET,
|
method: .GET,
|
||||||
authString: auth,
|
authString: auth,
|
||||||
@@ -208,19 +196,19 @@ class CookbookApiV1: CookbookApi {
|
|||||||
return (JSONDecoder.safeDecode(data), nil)
|
return (JSONDecoder.safeDecode(data), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func getApiVersion(from serverAdress: String, auth: String) async -> (NetworkError?) {
|
static func getApiVersion(auth: String) async -> (NetworkError?) {
|
||||||
return .none
|
return .none
|
||||||
}
|
}
|
||||||
|
|
||||||
static func postReindex(from serverAdress: String, auth: String) async -> (NetworkError?) {
|
static func postReindex(auth: String) async -> (NetworkError?) {
|
||||||
return .none
|
return .none
|
||||||
}
|
}
|
||||||
|
|
||||||
static func getConfig(from serverAdress: String, auth: String) async -> (NetworkError?) {
|
static func getConfig(auth: String) async -> (NetworkError?) {
|
||||||
return .none
|
return .none
|
||||||
}
|
}
|
||||||
|
|
||||||
static func postConfig(from serverAdress: String, auth: String) async -> (NetworkError?) {
|
static func postConfig(auth: String) async -> (NetworkError?) {
|
||||||
return .none
|
return .none
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,7 +49,6 @@ import UIKit
|
|||||||
*/
|
*/
|
||||||
func getCategories() async {
|
func getCategories() async {
|
||||||
let (categories, _) = await api.getCategories(
|
let (categories, _) = await api.getCategories(
|
||||||
from: userSettings.serverAddress,
|
|
||||||
auth: userSettings.authString
|
auth: userSettings.authString
|
||||||
)
|
)
|
||||||
if let categories = categories {
|
if let categories = categories {
|
||||||
@@ -93,7 +92,6 @@ import UIKit
|
|||||||
|
|
||||||
func getServer(store: Bool = false) async -> Bool {
|
func getServer(store: Bool = false) async -> Bool {
|
||||||
let (recipes, _) = await api.getCategory(
|
let (recipes, _) = await api.getCategory(
|
||||||
from: userSettings.serverAddress,
|
|
||||||
auth: userSettings.authString,
|
auth: userSettings.authString,
|
||||||
named: categoryString
|
named: categoryString
|
||||||
)
|
)
|
||||||
@@ -156,7 +154,6 @@ import UIKit
|
|||||||
*/
|
*/
|
||||||
func getRecipes() async -> [Recipe] {
|
func getRecipes() async -> [Recipe] {
|
||||||
let (recipes, error) = await api.getRecipes(
|
let (recipes, error) = await api.getRecipes(
|
||||||
from: userSettings.serverAddress,
|
|
||||||
auth: userSettings.authString
|
auth: userSettings.authString
|
||||||
)
|
)
|
||||||
if let recipes = recipes {
|
if let recipes = recipes {
|
||||||
@@ -197,7 +194,6 @@ import UIKit
|
|||||||
|
|
||||||
func getServer() async -> RecipeDetail? {
|
func getServer() async -> RecipeDetail? {
|
||||||
let (recipe, error) = await api.getRecipe(
|
let (recipe, error) = await api.getRecipe(
|
||||||
from: userSettings.serverAddress,
|
|
||||||
auth: userSettings.authString,
|
auth: userSettings.authString,
|
||||||
id: id
|
id: id
|
||||||
)
|
)
|
||||||
@@ -291,7 +287,6 @@ import UIKit
|
|||||||
|
|
||||||
func getServer() async -> UIImage? {
|
func getServer() async -> UIImage? {
|
||||||
let (image, _) = await api.getImage(
|
let (image, _) = await api.getImage(
|
||||||
from: userSettings.serverAddress,
|
|
||||||
auth: userSettings.authString,
|
auth: userSettings.authString,
|
||||||
id: id,
|
id: id,
|
||||||
size: size
|
size: size
|
||||||
@@ -368,7 +363,6 @@ import UIKit
|
|||||||
|
|
||||||
func getServer() async -> [RecipeKeyword]? {
|
func getServer() async -> [RecipeKeyword]? {
|
||||||
let (tags, _) = await api.getTags(
|
let (tags, _) = await api.getTags(
|
||||||
from: userSettings.serverAddress,
|
|
||||||
auth: userSettings.authString
|
auth: userSettings.authString
|
||||||
)
|
)
|
||||||
return tags
|
return tags
|
||||||
@@ -423,7 +417,6 @@ import UIKit
|
|||||||
*/
|
*/
|
||||||
func deleteRecipe(withId id: Int, categoryName: String) async -> RequestAlert? {
|
func deleteRecipe(withId id: Int, categoryName: String) async -> RequestAlert? {
|
||||||
let (error) = await api.deleteRecipe(
|
let (error) = await api.deleteRecipe(
|
||||||
from: userSettings.serverAddress,
|
|
||||||
auth: userSettings.authString,
|
auth: userSettings.authString,
|
||||||
id: id
|
id: id
|
||||||
)
|
)
|
||||||
@@ -455,7 +448,6 @@ import UIKit
|
|||||||
*/
|
*/
|
||||||
func checkServerConnection() async -> Bool {
|
func checkServerConnection() async -> Bool {
|
||||||
let (categories, _) = await api.getCategories(
|
let (categories, _) = await api.getCategories(
|
||||||
from: userSettings.serverAddress,
|
|
||||||
auth: userSettings.authString
|
auth: userSettings.authString
|
||||||
)
|
)
|
||||||
if let categories = categories {
|
if let categories = categories {
|
||||||
@@ -485,13 +477,11 @@ import UIKit
|
|||||||
var error: NetworkError? = nil
|
var error: NetworkError? = nil
|
||||||
if createNew {
|
if createNew {
|
||||||
error = await api.createRecipe(
|
error = await api.createRecipe(
|
||||||
from: userSettings.serverAddress,
|
|
||||||
auth: userSettings.authString,
|
auth: userSettings.authString,
|
||||||
recipe: recipeDetail
|
recipe: recipeDetail
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
error = await api.updateRecipe(
|
error = await api.updateRecipe(
|
||||||
from: userSettings.serverAddress,
|
|
||||||
auth: userSettings.authString,
|
auth: userSettings.authString,
|
||||||
recipe: recipeDetail
|
recipe: recipeDetail
|
||||||
)
|
)
|
||||||
@@ -505,7 +495,6 @@ import UIKit
|
|||||||
func importRecipe(url: String) async -> (RecipeDetail?, RequestAlert?) {
|
func importRecipe(url: String) async -> (RecipeDetail?, RequestAlert?) {
|
||||||
guard let data = JSONEncoder.safeEncode(RecipeImportRequest(url: url)) else { return (nil, .REQUEST_DROPPED) }
|
guard let data = JSONEncoder.safeEncode(RecipeImportRequest(url: url)) else { return (nil, .REQUEST_DROPPED) }
|
||||||
let (recipeDetail, error) = await api.importRecipe(
|
let (recipeDetail, error) = await api.importRecipe(
|
||||||
from: userSettings.serverAddress,
|
|
||||||
auth: userSettings.authString,
|
auth: userSettings.authString,
|
||||||
data: data
|
data: data
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -181,11 +181,8 @@ struct LoginTextField: View {
|
|||||||
|
|
||||||
|
|
||||||
struct ServerAddressField: View {
|
struct ServerAddressField: View {
|
||||||
@Binding var addressString: String
|
@ObservedObject var userSettings = UserSettings.shared
|
||||||
@State var serverAddress: String = ""
|
|
||||||
@State var serverProtocol: ServerProtocol = .https
|
@State var serverProtocol: ServerProtocol = .https
|
||||||
@State var serverPort: String = ""
|
|
||||||
@State var useNonStandardPort: Bool = false
|
|
||||||
|
|
||||||
enum ServerProtocol: String {
|
enum ServerProtocol: String {
|
||||||
case https="https://", http="http://"
|
case https="https://", http="http://"
|
||||||
@@ -205,22 +202,26 @@ struct ServerAddressField: View {
|
|||||||
}.pickerStyle(.menu)
|
}.pickerStyle(.menu)
|
||||||
.tint(.white)
|
.tint(.white)
|
||||||
.font(.headline)
|
.font(.headline)
|
||||||
|
.onChange(of: serverProtocol) { color in
|
||||||
LoginTextField(example: "e.g.: example.com", text: $serverAddress)
|
userSettings.serverProtocol = color.rawValue
|
||||||
}
|
}
|
||||||
|
|
||||||
Toggle("Use a non-standard port", isOn: $useNonStandardPort)
|
TextField("e.g.: example.com", text: $userSettings.serverAddress)
|
||||||
.tint(.white.opacity(0.2))
|
.textFieldStyle(.plain)
|
||||||
|
.autocorrectionDisabled()
|
||||||
|
.textInputAutocapitalization(.never)
|
||||||
.foregroundStyle(.white)
|
.foregroundStyle(.white)
|
||||||
.font(.headline)
|
.padding()
|
||||||
.padding(.top)
|
.background(
|
||||||
if useNonStandardPort {
|
RoundedRectangle(cornerRadius: 10)
|
||||||
LoginTextField(example: "e.g.: 80", text: $serverPort)
|
.foregroundColor(Color.white.opacity(0.2))
|
||||||
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LoginLabel(text: "Full server address")
|
LoginLabel(text: "Full server address")
|
||||||
.padding(.top)
|
.padding(.top)
|
||||||
Text(createServerAddressString())
|
Text(userSettings.serverProtocol + userSettings.serverAddress)
|
||||||
.foregroundColor(.white)
|
.foregroundColor(.white)
|
||||||
.padding(.vertical, 5)
|
.padding(.vertical, 5)
|
||||||
}
|
}
|
||||||
@@ -230,26 +231,13 @@ struct ServerAddressField: View {
|
|||||||
.stroke(.white, lineWidth: 2)
|
.stroke(.white, lineWidth: 2)
|
||||||
.foregroundColor(.clear)
|
.foregroundColor(.clear)
|
||||||
)
|
)
|
||||||
}.animation(.easeInOut, value: useNonStandardPort)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func createServerAddressString() -> String {
|
|
||||||
if useNonStandardPort && serverPort != "" {
|
|
||||||
addressString = serverProtocol.rawValue + serverAddress + ":" + serverPort
|
|
||||||
} else {
|
|
||||||
addressString = serverProtocol.rawValue + serverAddress
|
|
||||||
}
|
|
||||||
return addressString
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ServerAddressField_Preview: PreviewProvider {
|
struct ServerAddressField_Preview: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
ServerAddressField(addressString: .constant(""),
|
ServerAddressField()
|
||||||
serverAddress: "example.com",
|
|
||||||
serverProtocol: .https,
|
|
||||||
serverPort: "80",
|
|
||||||
useNonStandardPort: true)
|
|
||||||
.previewLayout(.sizeThatFits)
|
.previewLayout(.sizeThatFits)
|
||||||
.padding()
|
.padding()
|
||||||
.background(Color.nextcloudBlue)
|
.background(Color.nextcloudBlue)
|
||||||
|
|||||||
@@ -26,14 +26,9 @@ struct TokenLoginView: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
/*LoginLabel(text: "Server address")
|
ServerAddressField()
|
||||||
LoginTextField(example: "e.g.: example.com", text: $userSettings.serverAddress)
|
|
||||||
.focused($focusedField, equals: .server)
|
|
||||||
.textContentType(.URL)
|
|
||||||
.submitLabel(.next)
|
|
||||||
.padding(.bottom)
|
.padding(.bottom)
|
||||||
*/
|
|
||||||
ServerAddressField(addressString: $userSettings.serverAddress)
|
|
||||||
LoginLabel(text: "User name")
|
LoginLabel(text: "User name")
|
||||||
BorderedLoginTextField(example: "username", text: $userSettings.username)
|
BorderedLoginTextField(example: "username", text: $userSettings.username)
|
||||||
.focused($focusedField, equals: .username)
|
.focused($focusedField, equals: .username)
|
||||||
|
|||||||
@@ -9,11 +9,10 @@ import Foundation
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
enum V2LoginStage: LoginStage {
|
enum V2LoginStage: LoginStage {
|
||||||
case serverAddress, login, validate
|
case login, validate
|
||||||
|
|
||||||
func next() -> V2LoginStage {
|
func next() -> V2LoginStage {
|
||||||
switch self {
|
switch self {
|
||||||
case .serverAddress: return .login
|
|
||||||
case .login: return .validate
|
case .login: return .validate
|
||||||
case .validate: return .validate
|
case .validate: return .validate
|
||||||
}
|
}
|
||||||
@@ -21,8 +20,7 @@ enum V2LoginStage: LoginStage {
|
|||||||
|
|
||||||
func previous() -> V2LoginStage {
|
func previous() -> V2LoginStage {
|
||||||
switch self {
|
switch self {
|
||||||
case .serverAddress: return .serverAddress
|
case .login: return .login
|
||||||
case .login: return .serverAddress
|
|
||||||
case .validate: return .login
|
case .validate: return .login
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -34,9 +32,8 @@ struct V2LoginView: View {
|
|||||||
@Binding var showAlert: Bool
|
@Binding var showAlert: Bool
|
||||||
@Binding var alertMessage: String
|
@Binding var alertMessage: String
|
||||||
|
|
||||||
@State var loginStage: V2LoginStage = .serverAddress
|
@State var loginStage: V2LoginStage = .login
|
||||||
@State var loginRequest: LoginV2Request? = nil
|
@State var loginRequest: LoginV2Request? = nil
|
||||||
@FocusState private var focusedField: Field?
|
|
||||||
|
|
||||||
@State var userSettings = UserSettings.shared
|
@State var userSettings = UserSettings.shared
|
||||||
|
|
||||||
@@ -50,27 +47,14 @@ struct V2LoginView: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
/*LoginLabel(text: "Server address")
|
ServerAddressField()
|
||||||
.padding()
|
|
||||||
LoginTextField(example: "e.g.: example.com", text: $userSettings.serverAddress, color: loginStage == .serverAddress ? .white : .secondary)
|
|
||||||
.focused($focusedField, equals: .server)
|
|
||||||
.textContentType(.URL)
|
|
||||||
.submitLabel(.done)
|
|
||||||
.padding([.bottom, .horizontal])
|
|
||||||
.onSubmit {
|
|
||||||
withAnimation(.easeInOut) {
|
|
||||||
loginStage = loginStage.next()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
ServerAddressField(addressString: $userSettings.serverAddress)
|
|
||||||
CollapsibleView {
|
CollapsibleView {
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
Text("Make sure to enter the server address in the form 'example.com'. Currently, only servers using the 'https' protocol are supported.")
|
Text("Make sure to enter the server address in the form 'example.com', or \n'<server address>:<port>'\n when a non-standard port is used.")
|
||||||
if let loginRequest = loginRequest {
|
.padding(.bottom)
|
||||||
Text("If the login button does not open your browser, copy the following link and paste it in your browser manually:")
|
Text("The 'Login' button will open a web browser. Please follow the login instructions provided there.\nAfter a successful login, return to this application and press 'Validate'.")
|
||||||
Text(loginRequest.login)
|
.padding(.bottom)
|
||||||
}
|
Text("If the login button does not open your browser, use the 'Copy Link' button and paste the link in your browser manually.")
|
||||||
}
|
}
|
||||||
} title: {
|
} title: {
|
||||||
Text("Show help")
|
Text("Show help")
|
||||||
@@ -78,14 +62,16 @@ struct V2LoginView: View {
|
|||||||
.font(.headline)
|
.font(.headline)
|
||||||
}.padding()
|
}.padding()
|
||||||
|
|
||||||
if loginStage == .login || loginStage == .validate {
|
if loginRequest != nil {
|
||||||
Text("The 'Login' button will open a web browser. Please follow the login instructions provided there.\nAfter a successful login, return to this application and press 'Validate'.")
|
Button("Copy Link") {
|
||||||
.font(.subheadline)
|
UIPasteboard.general.string = loginRequest!.login
|
||||||
|
}
|
||||||
|
.font(.headline)
|
||||||
.foregroundStyle(.white)
|
.foregroundStyle(.white)
|
||||||
.padding()
|
.padding()
|
||||||
}
|
}
|
||||||
|
|
||||||
HStack {
|
HStack {
|
||||||
if loginStage == .login || loginStage == .validate {
|
|
||||||
Button {
|
Button {
|
||||||
if userSettings.serverAddress == "" {
|
if userSettings.serverAddress == "" {
|
||||||
alertMessage = "Please enter a valid server address."
|
alertMessage = "Please enter a valid server address."
|
||||||
@@ -114,7 +100,7 @@ struct V2LoginView: View {
|
|||||||
.foregroundColor(.clear)
|
.foregroundColor(.clear)
|
||||||
)
|
)
|
||||||
}.padding()
|
}.padding()
|
||||||
}
|
|
||||||
if loginStage == .validate {
|
if loginStage == .validate {
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user