enrecipes/app/components/EnRecipes.vue

396 lines
12 KiB
Vue
Raw Normal View History

2020-09-15 11:10:16 +00:00
<template>
2020-10-22 18:36:50 +00:00
<Page @loaded="initializePage">
2020-10-14 19:32:32 +00:00
<ActionBar :flat="viewIsScrolled ? false : true">
<!-- Search Actionbar -->
<GridLayout
v-if="showSearch"
columns="auto, *"
class="actionBarContainer"
2020-10-21 17:54:45 +00:00
verticalAlignment="center"
2020-10-14 19:32:32 +00:00
>
<Label
class="bx leftAction"
:text="icon.back"
automationText="Back"
col="0"
@tap="closeSearch"
/>
2020-10-21 17:54:45 +00:00
<!-- @loaded="searchBarLoaded" -->
2020-10-14 19:32:32 +00:00
<SearchBar
col="1"
hint="Search"
textFieldHintColor="#bdbdbd"
v-model="searchQuery"
2020-10-21 17:54:45 +00:00
@textChange="updateFilter"
@clear="updateFilter"
2020-10-14 19:32:32 +00:00
/>
</GridLayout>
<!-- Home Actionbar -->
<GridLayout
v-else
2020-10-21 17:54:45 +00:00
columns="auto, *, auto, auto"
2020-10-14 19:32:32 +00:00
class="actionBarContainer"
>
<Label
class="bx leftAction"
:text="icon.menu"
automationText="Menu"
@tap="showDrawer"
col="0"
/>
2020-10-21 17:54:45 +00:00
<Label class="title orkm" :text="currentComponent" col="1" />
<Label class="bx" :text="icon.search" col="2" @tap="openSearch" />
<Label class="bx" :text="icon.sort" col="3" @tap="sortDialog" />
2020-10-14 19:32:32 +00:00
</GridLayout>
</ActionBar>
<AbsoluteLayout>
<RadListView
ref="listView"
2020-10-21 17:54:45 +00:00
itemHeight="112"
for="recipe in recipes"
2020-10-14 19:32:32 +00:00
swipeActions="true"
@itemSwipeProgressChanged="onSwiping"
@itemSwipeProgressEnded="onSwipeEnded"
@scrolled="onScroll($event)"
@itemTap="viewRecipe"
2020-10-21 17:54:45 +00:00
:filteringFunction="filterFunction"
:sortingFunction="sortFunction"
2020-10-14 19:32:32 +00:00
>
<v-template>
<GridLayout
class="recipe-li"
2020-10-21 17:54:45 +00:00
rows="112"
columns="112, *"
androidElevation="1"
2020-09-15 11:10:16 +00:00
>
2020-10-21 17:54:45 +00:00
<Image col="0" src="res://icon" stretch="fill" />
<StackLayout class="recipe-info" col="1">
<Label :text="recipe.category" class="orkm recipe-cat" />
2020-10-14 19:32:32 +00:00
<Label :text="recipe.title" class="orkm recipe-title" />
<Label
:text="recipeTotalTime(recipe.prepTime, recipe.cookTime)"
class="h4 recipe-time"
/>
</StackLayout>
</GridLayout>
</v-template>
<v-template name="itemswipe">
2020-10-21 17:54:45 +00:00
<GridLayout columns="*, auto">
<StackLayout id="delete-action" col="1" class="swipe-item right">
2020-10-14 19:32:32 +00:00
<Label class="bx" padding="8 0 0 6" :text="icon.trash" />
</StackLayout>
</GridLayout>
</v-template>
2020-10-21 17:54:45 +00:00
<v-template name="footer">
<StackLayout height="128"></StackLayout>
</v-template>
2020-10-14 19:32:32 +00:00
</RadListView>
2020-10-21 17:54:45 +00:00
<Label
v-if="!recipes.length && !filterFavorites && !filterMustTry"
class="noResults"
horizontalAlignment="center"
text='Click the "+" icon to add a new recipe.'
textAlignment="center"
textWrap="true"
/>
2020-09-15 18:04:33 +00:00
<Label
2020-10-14 19:32:32 +00:00
v-if="!filteredRecipes.length && searchQuery"
class="noResults"
2020-09-15 18:04:33 +00:00
horizontalAlignment="center"
:text="
2020-10-14 19:32:32 +00:00
`Your search &quot;${searchQuery}&quot; did not match any recipes in this category.`
2020-09-15 18:04:33 +00:00
"
textAlignment="center"
textWrap="true"
/>
2020-09-15 11:10:16 +00:00
<Label
2020-10-14 19:32:32 +00:00
v-if="!filteredRecipes.length && filterFavorites && !searchQuery"
class="noResults"
horizontalAlignment="center"
text="Your favorite recipes will be listed here."
textAlignment="center"
textWrap="true"
2020-09-15 11:10:16 +00:00
/>
2020-10-21 17:54:45 +00:00
<Label
v-if="!filteredRecipes.length && filterMustTry && !searchQuery"
class="noResults"
horizontalAlignment="center"
text="Your Must-Try recipes will be listed here."
textAlignment="center"
textWrap="true"
/>
<GridLayout id="btnFabContainer" rows="*,88" columns="*,88">
2020-10-14 19:32:32 +00:00
<Label
row="1"
col="1"
2020-10-22 18:36:50 +00:00
class="bx fab-button"
2020-10-14 19:32:32 +00:00
:text="icon.plus"
androidElevation="8"
@tap="addRecipe"
/>
</GridLayout>
</AbsoluteLayout>
</Page>
2020-09-15 11:10:16 +00:00
</template>
<script>
2020-10-22 18:36:50 +00:00
import { Utils, AndroidApplication } from "@nativescript/core"
2020-10-21 17:54:45 +00:00
import * as Toast from "nativescript-toast"
2020-10-14 19:32:32 +00:00
import EditRecipe from "./EditRecipe.vue"
import ViewRecipe from "./ViewRecipe.vue"
2020-10-21 17:54:45 +00:00
import ActionDialog from "./modal/ActionDialog.vue"
import ConfirmDialog from "./modal/ConfirmDialog.vue"
2020-10-14 19:32:32 +00:00
import { mapState, mapActions } from "vuex"
export default {
2020-10-21 17:54:45 +00:00
props: [
"filterFavorites",
"filterMustTry",
"selectedCategory",
"showDrawer",
"hijackGlobalBackEvent",
"releaseGlobalBackEvent",
],
2020-10-14 19:32:32 +00:00
components: {
EditRecipe,
ViewRecipe,
},
2020-09-15 11:10:16 +00:00
data() {
return {
2020-10-14 19:32:32 +00:00
searchQuery: "",
viewIsScrolled: false,
2020-10-21 17:54:45 +00:00
showSearch: false,
// leftAction: false,
2020-10-14 19:32:32 +00:00
rightAction: false,
2020-10-21 17:54:45 +00:00
sortType: "Natural order",
2020-09-15 11:10:16 +00:00
}
},
computed: {
2020-10-21 17:54:45 +00:00
...mapState(["recipes", "icon", "currentComponent"]),
2020-09-15 11:10:16 +00:00
filteredRecipes() {
2020-10-21 17:54:45 +00:00
if (this.filterFavorites) {
return this.recipes.filter(
(e) =>
e.isFavorite && e.title.toLowerCase().includes(this.searchQuery)
)
} else if (this.filterMustTry) {
return this.recipes.filter(
(e) => !e.tried && e.title.toLowerCase().includes(this.searchQuery)
)
} else if (this.selectedCategory) {
return this.recipes.filter(
(e) =>
e.category === this.selectedCategory &&
e.title.toLowerCase().includes(this.searchQuery)
)
2020-09-15 18:04:33 +00:00
} else {
2020-10-21 17:54:45 +00:00
return this.recipes.filter((e) =>
e.title.toLowerCase().includes(this.searchQuery)
)
2020-09-15 11:10:16 +00:00
}
},
},
methods: {
2020-10-22 18:36:50 +00:00
...mapActions(["setCurrentComponentAction", "deleteRecipeAction"]),
2020-10-21 17:54:45 +00:00
openSearch() {
this.showSearch = true
this.hijackLocalBackEvent()
},
hijackLocalBackEvent() {
this.releaseGlobalBackEvent()
2020-10-22 18:36:50 +00:00
AndroidApplication.on(
AndroidApplication.activityBackPressedEvent,
2020-10-21 17:54:45 +00:00
this.searchBackEvent
)
},
releaseLocalBackEvent() {
2020-10-22 18:36:50 +00:00
AndroidApplication.off(
AndroidApplication.activityBackPressedEvent,
2020-10-21 17:54:45 +00:00
this.searchBackEvent
)
this.hijackGlobalBackEvent()
},
searchBackEvent(args) {
args.cancel = true
this.closeSearch()
},
closeSearch() {
this.searchQuery = ""
2020-10-22 18:36:50 +00:00
Utils.ad.dismissSoftInput()
2020-10-21 17:54:45 +00:00
this.showSearch = false
this.updateFilter()
this.releaseLocalBackEvent()
},
sortDialog() {
this.releaseGlobalBackEvent()
this.$showModal(ActionDialog, {
props: {
title: "Sort by",
list: ["Natural order", "Title", "Duration", "Last modified"],
2020-10-22 18:36:50 +00:00
height: "195", // 48*4 + 3 1dip separators
2020-10-21 17:54:45 +00:00
},
}).then((action) => {
if (action && action !== "Cancel" && this.sortType !== action) {
this.sortType = action
this.updateSort()
}
this.hijackGlobalBackEvent()
})
},
updateSort() {
let listView = this.$refs.listView.nativeView
listView.sortingFunction = undefined
listView.sortingFunction = this.sortFunction
},
sortFunction(item, otherItem) {
const titleOrder = item.title
.toLowerCase()
.localeCompare(otherItem.title.toLowerCase(), "en", {
ignorePunctuation: true,
})
let d1 = this.recipeDuration(item.prepTime, item.cookTime)
let d2 = this.recipeDuration(otherItem.prepTime, otherItem.cookTime)
let ld1 = new Date(item.lastModified)
let ld2 = new Date(otherItem.lastModified)
switch (this.sortType) {
case "Title":
return titleOrder > 0 ? -1 : titleOrder < 0 ? 1 : 0
break
case "Duration":
return d1 > d2 ? -1 : d1 < d2 ? 1 : 0
break
case "Last modified":
return ld1 < ld2 ? -1 : ld1 > ld2 ? 1 : 0
break
default:
return 0
break
}
},
setComponent(comp) {
2020-10-22 18:36:50 +00:00
this.setCurrentComponentAction(comp)
2020-10-21 17:54:45 +00:00
this.hijackGlobalBackEvent()
},
updateFilter() {
let listView = this.$refs.listView.nativeView
setTimeout((e) => {
listView.filteringFunction = undefined
listView.filteringFunction = this.filterFunction
}, 1)
},
filterFunction(item) {
if (this.filterFavorites) {
return item.isFavorite
? item.title.toLowerCase().includes(this.searchQuery)
: false
} else if (this.filterMustTry) {
return item.tried
? false
: item.title.toLowerCase().includes(this.searchQuery)
} else if (this.selectedCategory) {
return item.category === this.selectedCategory
? item.title.toLowerCase().includes(this.searchQuery)
: false
} else {
return item.title.toLowerCase().includes(this.searchQuery)
}
},
2020-10-22 18:36:50 +00:00
initializePage() {
2020-10-21 17:54:45 +00:00
this.filterFavorites
? this.setComponent("Favorites")
: this.filterMustTry
? this.setComponent("Must-Try")
: this.selectedCategory
? this.setComponent(this.selectedCategory)
: this.setComponent("EnRecipes")
},
2020-10-14 19:32:32 +00:00
onSwiping({ data, object }) {
const swipeLimits = data.swipeLimits
const swipeView = object
const rightItem = swipeView.getViewById("delete-action")
swipeLimits.right = rightItem.getMeasuredWidth() - 12
2020-10-21 17:54:45 +00:00
swipeLimits.threshold = swipeLimits.right - 6
if (data.x < -swipeLimits.threshold) {
2020-10-14 19:32:32 +00:00
this.rightAction = true
2020-10-21 17:54:45 +00:00
swipeView.notifySwipeToExecuteFinished()
2020-10-14 19:32:32 +00:00
}
},
onSwipeEnded({ index }) {
2020-10-21 17:54:45 +00:00
if (this.rightAction) this.deleteRecipe(index)
this.rightAction = false
2020-10-14 19:32:32 +00:00
},
2020-10-21 17:54:45 +00:00
deleteRecipe(index) {
this.$showModal(ConfirmDialog, {
props: {
title: "Delete recipe",
description: `Are you sure you want to delete the recipe "${this.recipes[index].title}"?`,
cancelButtonText: "CANCEL",
okButtonText: "DELETE",
},
}).then((action) => {
if (action) {
2020-10-22 18:36:50 +00:00
this.deleteRecipeAction(index)
2020-10-21 17:54:45 +00:00
}
})
2020-10-14 19:32:32 +00:00
},
2020-10-21 17:54:45 +00:00
getTotalTime(prepTime, cookTime) {
2020-10-14 19:32:32 +00:00
let pT = prepTime.split(":")
let cT = cookTime.split(":")
let hrs = parseInt(pT[0]) + parseInt(cT[0])
let mins = parseInt(pT[1]) + parseInt(cT[1])
if (mins > 60) {
hrs += Math.floor(mins / 60)
mins -= 60
}
2020-10-21 17:54:45 +00:00
return {
hrs,
mins,
}
},
recipeTotalTime(prepTime, cookTime) {
let { hrs, mins } = this.getTotalTime(prepTime, cookTime)
2020-10-14 19:32:32 +00:00
return hrs ? `${hrs}h ${mins}m` : `${mins}m`
},
2020-10-21 17:54:45 +00:00
recipeDuration(prepTime, cookTime) {
let { hrs, mins } = this.getTotalTime(prepTime, cookTime)
return `${hrs}${mins}`
},
2020-10-14 19:32:32 +00:00
onScroll(args) {
args.scrollOffset
? (this.viewIsScrolled = true)
: (this.viewIsScrolled = false)
},
addRecipe() {
2020-10-21 17:54:45 +00:00
this.releaseGlobalBackEvent()
2020-10-14 19:32:32 +00:00
this.$navigateTo(EditRecipe, {
transition: {
name: "slide",
duration: 250,
curve: "easeIn",
},
props: {
viewIsScrolled: this.viewIsScrolled,
2020-10-21 17:54:45 +00:00
selectedCategory: this.selectedCategory,
2020-10-14 19:32:32 +00:00
},
})
},
viewRecipe({ item }) {
this.$navigateTo(ViewRecipe, {
transition: {
name: "fade",
duration: 250,
curve: "easeIn",
},
props: {
2020-10-21 17:54:45 +00:00
recipeIndex: this.recipes.indexOf(item),
hijackGlobalBackEvent: this.hijackGlobalBackEvent,
releaseGlobalBackEvent: this.releaseGlobalBackEvent,
2020-10-14 19:32:32 +00:00
},
})
},
2020-09-15 11:10:16 +00:00
},
}
</script>