Bug fixes and UI polish
This commit is contained in:
Binary file not shown.
@@ -1194,6 +1194,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"Deletion successful." : {
|
||||||
|
|
||||||
},
|
},
|
||||||
"Description" : {
|
"Description" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@@ -2720,6 +2723,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"Recipe upload successful." : {
|
||||||
|
|
||||||
},
|
},
|
||||||
"Recipes" : {
|
"Recipes" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@@ -3253,6 +3259,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"Success!" : {
|
||||||
|
|
||||||
},
|
},
|
||||||
"Sugar content" : {
|
"Sugar content" : {
|
||||||
"comment" : "Sugar content",
|
"comment" : "Sugar content",
|
||||||
|
|||||||
@@ -30,7 +30,9 @@ enum RecipeAlert: UserAlert {
|
|||||||
case NO_TITLE,
|
case NO_TITLE,
|
||||||
DUPLICATE,
|
DUPLICATE,
|
||||||
UPLOAD_ERROR,
|
UPLOAD_ERROR,
|
||||||
|
UPLOAD_SUCCESS,
|
||||||
CONFIRM_DELETE,
|
CONFIRM_DELETE,
|
||||||
|
DELETE_SUCCESS,
|
||||||
LOGIN_FAILED,
|
LOGIN_FAILED,
|
||||||
GENERIC,
|
GENERIC,
|
||||||
CUSTOM(title: LocalizedStringKey, description: LocalizedStringKey)
|
CUSTOM(title: LocalizedStringKey, description: LocalizedStringKey)
|
||||||
@@ -43,8 +45,12 @@ enum RecipeAlert: UserAlert {
|
|||||||
return "A recipe with that name already exists."
|
return "A recipe with that name already exists."
|
||||||
case .UPLOAD_ERROR:
|
case .UPLOAD_ERROR:
|
||||||
return "Unable to upload your recipe. Please check your internet connection."
|
return "Unable to upload your recipe. Please check your internet connection."
|
||||||
|
case .UPLOAD_SUCCESS:
|
||||||
|
return "Recipe upload successful."
|
||||||
case .CONFIRM_DELETE:
|
case .CONFIRM_DELETE:
|
||||||
return "This action is not reversible!"
|
return "This action is not reversible!"
|
||||||
|
case .DELETE_SUCCESS:
|
||||||
|
return "Deletion successful."
|
||||||
case .LOGIN_FAILED:
|
case .LOGIN_FAILED:
|
||||||
return "Please check your credentials and internet connection."
|
return "Please check your credentials and internet connection."
|
||||||
case .CUSTOM(title: _, description: let description):
|
case .CUSTOM(title: _, description: let description):
|
||||||
@@ -62,8 +68,12 @@ enum RecipeAlert: UserAlert {
|
|||||||
return "Duplicate recipe."
|
return "Duplicate recipe."
|
||||||
case .UPLOAD_ERROR:
|
case .UPLOAD_ERROR:
|
||||||
return "Network error."
|
return "Network error."
|
||||||
|
case .UPLOAD_SUCCESS:
|
||||||
|
return "Success!"
|
||||||
case .CONFIRM_DELETE:
|
case .CONFIRM_DELETE:
|
||||||
return "Delete recipe?"
|
return "Delete recipe?"
|
||||||
|
case .DELETE_SUCCESS:
|
||||||
|
return "Success!"
|
||||||
case .LOGIN_FAILED:
|
case .LOGIN_FAILED:
|
||||||
return "Login failed."
|
return "Login failed."
|
||||||
case .CUSTOM(title: let title, description: _):
|
case .CUSTOM(title: let title, description: _):
|
||||||
@@ -113,12 +123,14 @@ enum RecipeImportAlert: UserAlert {
|
|||||||
|
|
||||||
enum RequestAlert: UserAlert {
|
enum RequestAlert: UserAlert {
|
||||||
case REQUEST_DELAYED,
|
case REQUEST_DELAYED,
|
||||||
REQUEST_DROPPED
|
REQUEST_DROPPED,
|
||||||
|
REQUEST_SUCCESS
|
||||||
|
|
||||||
var localizedDescription: LocalizedStringKey {
|
var localizedDescription: LocalizedStringKey {
|
||||||
switch self {
|
switch self {
|
||||||
case .REQUEST_DELAYED: return "Could not establish a connection to the server. The action will be retried upon reconnection."
|
case .REQUEST_DELAYED: return "Could not establish a connection to the server. The action will be retried upon reconnection."
|
||||||
case .REQUEST_DROPPED: return "Unable to complete action."
|
case .REQUEST_DROPPED: return "Unable to complete action."
|
||||||
|
case .REQUEST_SUCCESS: return ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,6 +138,7 @@ enum RequestAlert: UserAlert {
|
|||||||
switch self {
|
switch self {
|
||||||
case .REQUEST_DELAYED: return "Action delayed"
|
case .REQUEST_DELAYED: return "Action delayed"
|
||||||
case .REQUEST_DROPPED: return "Error"
|
case .REQUEST_DROPPED: return "Error"
|
||||||
|
case .REQUEST_SUCCESS: return "Success!"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ struct RecipeListView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.navigationDestination(for: Recipe.self) { recipe in
|
.navigationDestination(for: Recipe.self) { recipe in
|
||||||
RecipeView(isPresented: .constant(true), viewModel: RecipeView.ViewModel(recipe: recipe))
|
RecipeView(viewModel: RecipeView.ViewModel(recipe: recipe))
|
||||||
.environmentObject(appState)
|
.environmentObject(appState)
|
||||||
.environmentObject(groceryList)
|
.environmentObject(groceryList)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,8 +11,10 @@ import SwiftUI
|
|||||||
|
|
||||||
struct RecipeView: View {
|
struct RecipeView: View {
|
||||||
@EnvironmentObject var appState: AppState
|
@EnvironmentObject var appState: AppState
|
||||||
@Binding var isPresented: Bool
|
@Environment(\.dismiss) private var dismiss
|
||||||
@StateObject var viewModel: ViewModel
|
@StateObject var viewModel: ViewModel
|
||||||
|
@GestureState private var dragOffset = CGSize.zero
|
||||||
|
|
||||||
var imageHeight: CGFloat {
|
var imageHeight: CGFloat {
|
||||||
if let image = viewModel.recipeImage {
|
if let image = viewModel.recipeImage {
|
||||||
return image.size.height < 350 ? image.size.height : 350
|
return image.size.height < 350 ? image.size.height : 350
|
||||||
@@ -115,8 +117,9 @@ struct RecipeView: View {
|
|||||||
.toolbar(.visible, for: .navigationBar)
|
.toolbar(.visible, for: .navigationBar)
|
||||||
//.toolbarTitleDisplayMode(.inline)
|
//.toolbarTitleDisplayMode(.inline)
|
||||||
.navigationTitle(viewModel.showTitle ? viewModel.recipe.name : "")
|
.navigationTitle(viewModel.showTitle ? viewModel.recipe.name : "")
|
||||||
|
|
||||||
.toolbar {
|
.toolbar {
|
||||||
RecipeViewToolBar(isPresented: $isPresented, viewModel: viewModel)
|
RecipeViewToolBar(viewModel: viewModel)
|
||||||
}
|
}
|
||||||
.sheet(isPresented: $viewModel.presentShareSheet) {
|
.sheet(isPresented: $viewModel.presentShareSheet) {
|
||||||
ShareView(recipeDetail: viewModel.observableRecipeDetail.toRecipeDetail(),
|
ShareView(recipeDetail: viewModel.observableRecipeDetail.toRecipeDetail(),
|
||||||
@@ -313,16 +316,18 @@ extension RecipeView {
|
|||||||
|
|
||||||
struct RecipeViewToolBar: ToolbarContent {
|
struct RecipeViewToolBar: ToolbarContent {
|
||||||
@EnvironmentObject var appState: AppState
|
@EnvironmentObject var appState: AppState
|
||||||
@Binding var isPresented: Bool
|
@Environment(\.dismiss) private var dismiss
|
||||||
@ObservedObject var viewModel: RecipeView.ViewModel
|
@ObservedObject var viewModel: RecipeView.ViewModel
|
||||||
|
|
||||||
|
|
||||||
var body: some ToolbarContent {
|
var body: some ToolbarContent {
|
||||||
if viewModel.editMode {
|
if viewModel.editMode {
|
||||||
ToolbarItemGroup(placement: .topBarLeading){
|
ToolbarItemGroup(placement: .topBarLeading) {
|
||||||
Button("Cancel") {
|
Button("Cancel") {
|
||||||
viewModel.editMode = false
|
viewModel.editMode = false
|
||||||
isPresented = false
|
if viewModel.newRecipe {
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !viewModel.newRecipe {
|
if !viewModel.newRecipe {
|
||||||
@@ -407,9 +412,10 @@ struct RecipeViewToolBar: ToolbarContent {
|
|||||||
await appState.getCategories()
|
await appState.getCategories()
|
||||||
await appState.getCategory(named: viewModel.observableRecipeDetail.recipeCategory, fetchMode: .preferServer)
|
await appState.getCategory(named: viewModel.observableRecipeDetail.recipeCategory, fetchMode: .preferServer)
|
||||||
if let id = Int(viewModel.observableRecipeDetail.id) {
|
if let id = Int(viewModel.observableRecipeDetail.id) {
|
||||||
await appState.getRecipe(id: id, fetchMode: .onlyServer, save: true)
|
let _ = await appState.getRecipe(id: id, fetchMode: .onlyServer, save: true)
|
||||||
}
|
}
|
||||||
viewModel.editMode = false
|
viewModel.editMode = false
|
||||||
|
viewModel.presentAlert(RecipeAlert.UPLOAD_SUCCESS)
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleDelete() async {
|
func handleDelete() async {
|
||||||
@@ -424,7 +430,8 @@ struct RecipeViewToolBar: ToolbarContent {
|
|||||||
}
|
}
|
||||||
await appState.getCategories()
|
await appState.getCategories()
|
||||||
await appState.getCategory(named: category, fetchMode: .preferServer)
|
await appState.getCategory(named: category, fetchMode: .preferServer)
|
||||||
self.isPresented = false
|
viewModel.presentAlert(RecipeAlert.DELETE_SUCCESS)
|
||||||
|
dismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
func recipeValid() -> RecipeAlert? {
|
func recipeValid() -> RecipeAlert? {
|
||||||
|
|||||||
@@ -227,12 +227,14 @@ extension SettingsView {
|
|||||||
|
|
||||||
func getUserData() async {
|
func getUserData() async {
|
||||||
let (data, _) = await NextcloudApi.getAvatar()
|
let (data, _) = await NextcloudApi.getAvatar()
|
||||||
avatarImage = data
|
|
||||||
|
|
||||||
let (userData, _) = await NextcloudApi.getHoverCard()
|
let (userData, _) = await NextcloudApi.getHoverCard()
|
||||||
|
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.avatarImage = data
|
||||||
self.userData = userData
|
self.userData = userData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ struct RecipeTabView: View {
|
|||||||
.environmentObject(appState)
|
.environmentObject(appState)
|
||||||
}
|
}
|
||||||
.navigationDestination(isPresented: $viewModel.presentEditView) {
|
.navigationDestination(isPresented: $viewModel.presentEditView) {
|
||||||
RecipeView(isPresented: $viewModel.presentEditView, viewModel: RecipeView.ViewModel())
|
RecipeView(viewModel: RecipeView.ViewModel())
|
||||||
.environmentObject(appState)
|
.environmentObject(appState)
|
||||||
.environmentObject(groceryList)
|
.environmentObject(groceryList)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ struct SearchTabView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.navigationDestination(for: Recipe.self) { recipe in
|
.navigationDestination(for: Recipe.self) { recipe in
|
||||||
RecipeView(isPresented: .constant(true), viewModel: RecipeView.ViewModel(recipe: recipe))
|
RecipeView(viewModel: RecipeView.ViewModel(recipe: recipe))
|
||||||
}
|
}
|
||||||
.searchable(text: $viewModel.searchText, prompt: "Search recipes/keywords")
|
.searchable(text: $viewModel.searchText, prompt: "Search recipes/keywords")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user