implemented couchbase, fs image import, zip export
This commit is contained in:
parent
7c102fe518
commit
1d7bca959e
13 changed files with 2503 additions and 2892 deletions
|
@ -9,10 +9,18 @@
|
||||||
// e.g. project.ext.googlePlayServicesVersion = "15.0.1"
|
// e.g. project.ext.googlePlayServicesVersion = "15.0.1"
|
||||||
// create a file named before-plugins.gradle in the current directory and place it there
|
// create a file named before-plugins.gradle in the current directory and place it there
|
||||||
|
|
||||||
|
|
||||||
|
// abiFilter "arm64-v8a" "armeabi-v7a" "x86" "x86_64"
|
||||||
|
|
||||||
|
|
||||||
android {
|
android {
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 23
|
minSdkVersion 23
|
||||||
generatedDensities = []
|
generatedDensities = []
|
||||||
|
ndk {
|
||||||
|
abiFilters.clear()
|
||||||
|
abiFilters.addAll(['arm64-v8a','x86'])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
aaptOptions {
|
aaptOptions {
|
||||||
additionalParameters "--no-version-vectors"
|
additionalParameters "--no-version-vectors"
|
||||||
|
|
43
app/app.scss
43
app/app.scss
|
@ -71,7 +71,8 @@ Page {
|
||||||
color: $grayD4;
|
color: $grayD4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.view-imageHolder {
|
.view-imageHolder,
|
||||||
|
.recipeImgContainer {
|
||||||
color: $grayL1;
|
color: $grayL1;
|
||||||
background: $grayL2;
|
background: $grayL2;
|
||||||
}
|
}
|
||||||
|
@ -126,7 +127,8 @@ Page {
|
||||||
color: $grayL4;
|
color: $grayL4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.view-imageHolder {
|
.view-imageHolder,
|
||||||
|
.recipeImgContainer {
|
||||||
color: $grayD4;
|
color: $grayD4;
|
||||||
background: #111;
|
background: #111;
|
||||||
}
|
}
|
||||||
|
@ -239,7 +241,7 @@ RadListView {
|
||||||
margin: 8 16;
|
margin: 8 16;
|
||||||
border-radius: 6;
|
border-radius: 6;
|
||||||
.recipe-info {
|
.recipe-info {
|
||||||
margin: 4 0;
|
margin: 4;
|
||||||
}
|
}
|
||||||
.recipe-cat {
|
.recipe-cat {
|
||||||
font-size: 12;
|
font-size: 12;
|
||||||
|
@ -255,15 +257,31 @@ RadListView {
|
||||||
.recipe-time {
|
.recipe-time {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
.recipe-favorite {
|
.recipe-cat {
|
||||||
font-size: 12;
|
|
||||||
padding: 14 8 0 0;
|
|
||||||
}
|
|
||||||
.recipe-cat,
|
|
||||||
.recipe-favorite {
|
|
||||||
color: $orange;
|
color: $orange;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.noResults {
|
||||||
|
width: 100%;
|
||||||
|
font-size: 16;
|
||||||
|
line-height: 8;
|
||||||
|
padding: 32 16;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.swipe-item {
|
||||||
|
margin: 0 8;
|
||||||
|
background: #c62828;
|
||||||
|
color: #fff;
|
||||||
|
height: 128;
|
||||||
|
border-radius: 6;
|
||||||
|
}
|
||||||
|
.recipeImgContainer {
|
||||||
|
vertical-alignment: center;
|
||||||
|
// prettier-ignore
|
||||||
|
Image {
|
||||||
|
border-radius: 6 0 0 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Settings
|
// Settings
|
||||||
.group-header {
|
.group-header {
|
||||||
|
@ -372,13 +390,13 @@ RadListView {
|
||||||
}
|
}
|
||||||
// Edit Recipe
|
// Edit Recipe
|
||||||
.fab-button {
|
.fab-button {
|
||||||
color: white;
|
color: #fff;
|
||||||
height: 56;
|
height: 56;
|
||||||
width: 56;
|
width: 56;
|
||||||
background-color: #ff7043;
|
background-color: #ff7043;
|
||||||
horizontal-align: center;
|
horizontal-align: center;
|
||||||
vertical-align: center;
|
vertical-align: center;
|
||||||
border-radius: 100;
|
border-radius: 28;
|
||||||
padding: 16;
|
padding: 16;
|
||||||
margin: 16;
|
margin: 16;
|
||||||
}
|
}
|
||||||
|
@ -411,6 +429,9 @@ RadListView {
|
||||||
padding: 24 24 12;
|
padding: 24 24 12;
|
||||||
font-size: 20;
|
font-size: 20;
|
||||||
}
|
}
|
||||||
|
.dialogInputField {
|
||||||
|
padding: 0 24 16;
|
||||||
|
}
|
||||||
.dialogDescription {
|
.dialogDescription {
|
||||||
font-size: 16;
|
font-size: 16;
|
||||||
padding: 0 24 16;
|
padding: 0 24 16;
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
class="sd-group-header orkm"
|
class="sd-group-header orkm"
|
||||||
rows="auto"
|
rows="auto"
|
||||||
columns="*, auto"
|
columns="*, auto"
|
||||||
|
v-if="categories.length"
|
||||||
>
|
>
|
||||||
<Label col="0" text="Categories" />
|
<Label col="0" text="Categories" />
|
||||||
<Label
|
<Label
|
||||||
|
@ -103,6 +104,7 @@
|
||||||
<!-- Home -->
|
<!-- Home -->
|
||||||
<EnRecipes
|
<EnRecipes
|
||||||
ref="enrecipes"
|
ref="enrecipes"
|
||||||
|
:passedRecipes="recipes"
|
||||||
:filterFavorites="filterFavorites"
|
:filterFavorites="filterFavorites"
|
||||||
:filterMustTry="filterMustTry"
|
:filterMustTry="filterMustTry"
|
||||||
:selectedCategory="selectedCategory"
|
:selectedCategory="selectedCategory"
|
||||||
|
@ -132,8 +134,9 @@ import About from "./About.vue"
|
||||||
import PromptDialog from "./modal/PromptDialog.vue"
|
import PromptDialog from "./modal/PromptDialog.vue"
|
||||||
import { mapState, mapActions } from "vuex"
|
import { mapState, mapActions } from "vuex"
|
||||||
|
|
||||||
// import { Couchbase, ConcurrencyMode } from "nativescript-couchbase-plugin"
|
import { Couchbase } from "nativescript-couchbase-plugin"
|
||||||
// const cb = new Couchbase("enrecipes")
|
const cb = new Couchbase("enrecipes")
|
||||||
|
const cbCat = new Couchbase("categories")
|
||||||
|
|
||||||
let page
|
let page
|
||||||
export default {
|
export default {
|
||||||
|
@ -177,10 +180,11 @@ export default {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
catEditMode: false,
|
catEditMode: false,
|
||||||
|
recipes: null,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(["recipes", "categories", "icon", "currentComponent"]),
|
...mapState(["icon", "currentComponent"]),
|
||||||
categories() {
|
categories() {
|
||||||
let arr = this.recipes.map((e) => {
|
let arr = this.recipes.map((e) => {
|
||||||
return e.category
|
return e.category
|
||||||
|
@ -214,9 +218,20 @@ export default {
|
||||||
if (this.categories.includes(result)) {
|
if (this.categories.includes(result)) {
|
||||||
Toast.makeText("Category already exists!", "long").show()
|
Toast.makeText("Category already exists!", "long").show()
|
||||||
} else {
|
} else {
|
||||||
this.renameCategoryAction({
|
let categories = cbCat.getDocument("categories").categories
|
||||||
current: item,
|
console.log(categories, categories.indexOf(item))
|
||||||
updated: result,
|
categories.splice(categories.indexOf(item), 1)
|
||||||
|
categories.push(result)
|
||||||
|
categories.sort()
|
||||||
|
categories = [...new Set(categories)]
|
||||||
|
cbCat.updateDocument("categories", {
|
||||||
|
categories: [...categories],
|
||||||
|
})
|
||||||
|
this.recipes.forEach((e, i) => {
|
||||||
|
if (e.category == item) {
|
||||||
|
e.category = result
|
||||||
|
cb.updateDocument(e.id, e)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
this.catEditMode = false
|
this.catEditMode = false
|
||||||
}
|
}
|
||||||
|
@ -293,6 +308,7 @@ export default {
|
||||||
backstackVisible: false,
|
backstackVisible: false,
|
||||||
})
|
})
|
||||||
this.closeDrawer()
|
this.closeDrawer()
|
||||||
|
this.catEditMode = false
|
||||||
} else if (!this.catEditMode) {
|
} else if (!this.catEditMode) {
|
||||||
this.releaseGlobalBackEvent()
|
this.releaseGlobalBackEvent()
|
||||||
this.hijackGlobalBackEvent()
|
this.hijackGlobalBackEvent()
|
||||||
|
@ -342,40 +358,10 @@ export default {
|
||||||
created() {
|
created() {
|
||||||
let themeName = ApplicationSettings.getString("application-theme", "Light")
|
let themeName = ApplicationSettings.getString("application-theme", "Light")
|
||||||
setTimeout((e) => Theme.setMode(Theme[themeName]), 50)
|
setTimeout((e) => Theme.setMode(Theme[themeName]), 50)
|
||||||
|
this.recipes = cb.query({ select: [] })
|
||||||
|
cb.addDatabaseChangeListener((e) => {
|
||||||
|
this.recipes = cb.query({ select: [] })
|
||||||
|
})
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
.noResults {
|
|
||||||
width: 100%;
|
|
||||||
padding: 16;
|
|
||||||
font-size: 16;
|
|
||||||
line-height: 8;
|
|
||||||
}
|
|
||||||
.swipe-item {
|
|
||||||
margin: 0 8;
|
|
||||||
background: #ff7043;
|
|
||||||
color: #fff;
|
|
||||||
height: 128;
|
|
||||||
border-radius: 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
#btnFabContainer {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
.btnFab {
|
|
||||||
width: 56;
|
|
||||||
height: 56;
|
|
||||||
padding: 16;
|
|
||||||
background-color: #ff7043;
|
|
||||||
color: #fff;
|
|
||||||
border-radius: 28;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
// prettier-ignore
|
|
||||||
Button {
|
|
||||||
color: #ff7043;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -260,7 +260,14 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { Screen, AndroidApplication } from "@nativescript/core"
|
import {
|
||||||
|
Screen,
|
||||||
|
AndroidApplication,
|
||||||
|
ImageSource,
|
||||||
|
path,
|
||||||
|
getFileAccess,
|
||||||
|
knownFolders,
|
||||||
|
} from "@nativescript/core"
|
||||||
import { Mediafilepicker } from "nativescript-mediafilepicker"
|
import { Mediafilepicker } from "nativescript-mediafilepicker"
|
||||||
|
|
||||||
import { mapState, mapActions } from "vuex"
|
import { mapState, mapActions } from "vuex"
|
||||||
|
@ -269,8 +276,13 @@ import ActionDialog from "./modal/ActionDialog.vue"
|
||||||
import PromptDialog from "./modal/PromptDialog.vue"
|
import PromptDialog from "./modal/PromptDialog.vue"
|
||||||
import ConfirmDialog from "./modal/ConfirmDialog.vue"
|
import ConfirmDialog from "./modal/ConfirmDialog.vue"
|
||||||
|
|
||||||
|
import { Couchbase } from "nativescript-couchbase-plugin"
|
||||||
|
import { load } from "@nativescript/core/ui/builder"
|
||||||
|
const cb = new Couchbase("enrecipes")
|
||||||
|
const cbCat = new Couchbase("categories")
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ["recipeIndex", "selectedCategory"],
|
props: ["recipeID", "selectedCategory"],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
title: "New recipe",
|
title: "New recipe",
|
||||||
|
@ -297,16 +309,67 @@ export default {
|
||||||
lastModified: null,
|
lastModified: null,
|
||||||
},
|
},
|
||||||
tempRecipeContent: {},
|
tempRecipeContent: {},
|
||||||
|
units: [
|
||||||
|
"unit",
|
||||||
|
"tsp",
|
||||||
|
"Tbsp",
|
||||||
|
"oz",
|
||||||
|
"cup",
|
||||||
|
"pt",
|
||||||
|
"qt",
|
||||||
|
"lb",
|
||||||
|
"gal",
|
||||||
|
"ml",
|
||||||
|
"L",
|
||||||
|
"mg",
|
||||||
|
"g",
|
||||||
|
"kg",
|
||||||
|
"mm",
|
||||||
|
"cm",
|
||||||
|
"m",
|
||||||
|
"in",
|
||||||
|
"°C",
|
||||||
|
"°F",
|
||||||
|
],
|
||||||
|
categories: [
|
||||||
|
"Appetizers",
|
||||||
|
"BBQ",
|
||||||
|
"Beverages",
|
||||||
|
"Breads",
|
||||||
|
"Breakfast",
|
||||||
|
"Desserts",
|
||||||
|
"Dinner",
|
||||||
|
"Drinks",
|
||||||
|
"Healthy",
|
||||||
|
"Lunch",
|
||||||
|
"Main dishes",
|
||||||
|
"Meat",
|
||||||
|
"Noodles",
|
||||||
|
"Pasta",
|
||||||
|
"Poultry",
|
||||||
|
"Rice",
|
||||||
|
"Salads",
|
||||||
|
"Sauces",
|
||||||
|
"Seafood",
|
||||||
|
"Side dishes",
|
||||||
|
"Snacks",
|
||||||
|
"Soups",
|
||||||
|
"Undefined",
|
||||||
|
"Vegan",
|
||||||
|
"Vegetarian",
|
||||||
|
],
|
||||||
blockModal: false,
|
blockModal: false,
|
||||||
|
cbCat: [],
|
||||||
|
newRecipeID: null,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(["icon", "units", "categories", "currentComponent", "recipes"]),
|
...mapState(["icon", "currentComponent"]),
|
||||||
screenWidth() {
|
screenWidth() {
|
||||||
return Screen.mainScreen.widthDIPs
|
return Screen.mainScreen.widthDIPs
|
||||||
},
|
},
|
||||||
hasEnoughDetails() {
|
hasEnoughDetails() {
|
||||||
if (this.recipeIndex) {
|
if (this.recipeID) {
|
||||||
return (
|
return (
|
||||||
JSON.stringify(this.recipeContent) !==
|
JSON.stringify(this.recipeContent) !==
|
||||||
JSON.stringify(this.tempRecipeContent)
|
JSON.stringify(this.tempRecipeContent)
|
||||||
|
@ -317,26 +380,38 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions([
|
...mapActions(["setCurrentComponentAction"]),
|
||||||
"setCurrentComponentAction",
|
|
||||||
"overwriteRecipeAction",
|
|
||||||
"addRecipeAction",
|
|
||||||
"addCategoryAction",
|
|
||||||
]),
|
|
||||||
initializePage() {
|
initializePage() {
|
||||||
setTimeout((e) => {
|
setTimeout((e) => {
|
||||||
this.setCurrentComponentAction("EditRecipe")
|
this.setCurrentComponentAction("EditRecipe")
|
||||||
}, 500)
|
}, 500)
|
||||||
this.title = this.recipeIndex >= 0 ? "Edit recipe" : "New recipe"
|
this.title = this.recipeID ? "Edit recipe" : "New recipe"
|
||||||
if (this.recipeIndex >= 0) {
|
if (this.recipeID) {
|
||||||
Object.assign(this.recipeContent, this.recipes[this.recipeIndex])
|
let recipe = cb.getDocument(this.recipeID)
|
||||||
Object.assign(this.tempRecipeContent, this.recipes[this.recipeIndex])
|
Object.assign(this.recipeContent, recipe)
|
||||||
|
Object.assign(this.tempRecipeContent, recipe)
|
||||||
} else {
|
} else {
|
||||||
if (this.selectedCategory)
|
if (this.selectedCategory)
|
||||||
this.recipeContent.category = this.selectedCategory
|
this.recipeContent.category = this.selectedCategory
|
||||||
Object.assign(this.tempRecipeContent, this.recipeContent)
|
Object.assign(this.tempRecipeContent, this.recipeContent)
|
||||||
|
this.newRecipeID = this.getRandomID()
|
||||||
}
|
}
|
||||||
this.hijackBackEvent()
|
this.hijackBackEvent()
|
||||||
|
|
||||||
|
let isCategoriesStored = cbCat.query({ select: [] }).length
|
||||||
|
if (isCategoriesStored) {
|
||||||
|
this.categories = cbCat.getDocument("categories").categories
|
||||||
|
} else {
|
||||||
|
cbCat.createDocument({ categories: [...this.categories] }, "categories")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getRandomID() {
|
||||||
|
let res = ""
|
||||||
|
let chars = "abcdefghijklmnopqrstuvwxyz0123456789"
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
res += chars.charAt(Math.floor(Math.random() * chars.length))
|
||||||
|
}
|
||||||
|
return res
|
||||||
},
|
},
|
||||||
setTime(key, time) {
|
setTime(key, time) {
|
||||||
if (Date.parse(time)) {
|
if (Date.parse(time)) {
|
||||||
|
@ -375,13 +450,11 @@ export default {
|
||||||
saveRecipe() {
|
saveRecipe() {
|
||||||
this.clearEmptyFields()
|
this.clearEmptyFields()
|
||||||
this.recipeContent.lastModified = new Date()
|
this.recipeContent.lastModified = new Date()
|
||||||
if (this.recipeIndex >= 0) {
|
if (this.recipeID) {
|
||||||
this.overwriteRecipeAction({
|
cb.updateDocument(this.recipeID, this.recipeContent)
|
||||||
index: this.recipeIndex,
|
|
||||||
recipe: this.recipeContent,
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
this.addRecipeAction(this.recipeContent)
|
this.recipeContent.id = this.newRecipeID
|
||||||
|
cb.createDocument(this.recipeContent, this.newRecipeID)
|
||||||
}
|
}
|
||||||
this.$navigateBack()
|
this.$navigateBack()
|
||||||
},
|
},
|
||||||
|
@ -416,7 +489,11 @@ export default {
|
||||||
this.hijackBackEvent()
|
this.hijackBackEvent()
|
||||||
if (result.length) {
|
if (result.length) {
|
||||||
this.recipeContent.category = result
|
this.recipeContent.category = result
|
||||||
this.addCategoryAction(result)
|
this.categories.push(result)
|
||||||
|
this.categories.sort()
|
||||||
|
cbCat.updateDocument("categories", {
|
||||||
|
categories: [...this.categories],
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else if (action) {
|
} else if (action) {
|
||||||
|
@ -471,7 +548,11 @@ export default {
|
||||||
takePicture() {
|
takePicture() {
|
||||||
let mediafilepicker = new Mediafilepicker()
|
let mediafilepicker = new Mediafilepicker()
|
||||||
let vm = this
|
let vm = this
|
||||||
const options = { width: 800, height: 800, lockSquare: true }
|
const options = {
|
||||||
|
width: this.screenWidth,
|
||||||
|
height: this.screenWidth,
|
||||||
|
lockSquare: true,
|
||||||
|
}
|
||||||
const androidOptions = {
|
const androidOptions = {
|
||||||
isFreeStyleCropEnabled: true,
|
isFreeStyleCropEnabled: true,
|
||||||
statusBarColor: "black",
|
statusBarColor: "black",
|
||||||
|
@ -505,8 +586,15 @@ export default {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
mediafilepicker.on("getFiles", function(res) {
|
mediafilepicker.on("getFiles", function(res) {
|
||||||
let result = res.object.get("results")
|
let result = res.object.get("results")[0].file
|
||||||
vm.recipeContent.imageSrc = result[0].file
|
ImageSource.fromFile(result).then((savedImg) => {
|
||||||
|
let savedImgPath = path.join(
|
||||||
|
knownFolders.documents().getFolder("enrecipes").path,
|
||||||
|
`${vm.getRandomID()}.jpg`
|
||||||
|
)
|
||||||
|
savedImg.saveToFile(savedImgPath, "jpg")
|
||||||
|
vm.recipeContent.imageSrc = savedImgPath
|
||||||
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
removePicture() {
|
removePicture() {
|
||||||
|
@ -516,7 +604,10 @@ export default {
|
||||||
okButtonText: "Delete",
|
okButtonText: "Delete",
|
||||||
cancelButtonText: "Cancel",
|
cancelButtonText: "Cancel",
|
||||||
}).then((e) => {
|
}).then((e) => {
|
||||||
if (e) this.recipeContent.imageSrc = null
|
if (e) {
|
||||||
|
getFileAccess().deleteFile(this.recipeContent.imageSrc)
|
||||||
|
this.recipeContent.imageSrc = null
|
||||||
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -39,15 +39,27 @@
|
||||||
col="0"
|
col="0"
|
||||||
/>
|
/>
|
||||||
<Label class="title orkm" :text="currentComponent" col="1" />
|
<Label class="title orkm" :text="currentComponent" col="1" />
|
||||||
<Label class="bx" :text="icon.search" col="2" @tap="openSearch" />
|
<Label
|
||||||
<Label class="bx" :text="icon.sort" col="3" @tap="sortDialog" />
|
v-if="passedRecipes.length"
|
||||||
|
class="bx"
|
||||||
|
:text="icon.search"
|
||||||
|
col="2"
|
||||||
|
@tap="openSearch"
|
||||||
|
/>
|
||||||
|
<Label
|
||||||
|
v-if="passedRecipes.length"
|
||||||
|
class="bx"
|
||||||
|
:text="icon.sort"
|
||||||
|
col="3"
|
||||||
|
@tap="sortDialog"
|
||||||
|
/>
|
||||||
</GridLayout>
|
</GridLayout>
|
||||||
</ActionBar>
|
</ActionBar>
|
||||||
<AbsoluteLayout>
|
<AbsoluteLayout>
|
||||||
<RadListView
|
<RadListView
|
||||||
ref="listView"
|
ref="listView"
|
||||||
itemHeight="112"
|
itemHeight="112"
|
||||||
for="recipe in recipes"
|
for="recipe in passedRecipes"
|
||||||
swipeActions="true"
|
swipeActions="true"
|
||||||
@itemSwipeProgressChanged="onSwiping"
|
@itemSwipeProgressChanged="onSwiping"
|
||||||
@itemSwipeProgressEnded="onSwipeEnded"
|
@itemSwipeProgressEnded="onSwipeEnded"
|
||||||
|
@ -63,7 +75,24 @@
|
||||||
columns="112, *"
|
columns="112, *"
|
||||||
androidElevation="1"
|
androidElevation="1"
|
||||||
>
|
>
|
||||||
<Image col="0" src="res://icon" stretch="fill" />
|
<GridLayout class="recipeImgContainer" rows="112" columns="112">
|
||||||
|
<Image
|
||||||
|
row="0"
|
||||||
|
col="0"
|
||||||
|
v-if="recipe.imageSrc"
|
||||||
|
:src="recipe.imageSrc"
|
||||||
|
stretch="aspectFill"
|
||||||
|
/>
|
||||||
|
<Label
|
||||||
|
row="0"
|
||||||
|
col="0"
|
||||||
|
v-else
|
||||||
|
horizontalAlignment="center"
|
||||||
|
class="bx"
|
||||||
|
fontSize="56"
|
||||||
|
:text="icon.image"
|
||||||
|
/>
|
||||||
|
</GridLayout>
|
||||||
<StackLayout class="recipe-info" col="1">
|
<StackLayout class="recipe-info" col="1">
|
||||||
<Label :text="recipe.category" class="orkm recipe-cat" />
|
<Label :text="recipe.category" class="orkm recipe-cat" />
|
||||||
<Label :text="recipe.title" class="orkm recipe-title" />
|
<Label :text="recipe.title" class="orkm recipe-title" />
|
||||||
|
@ -86,37 +115,29 @@
|
||||||
</v-template>
|
</v-template>
|
||||||
</RadListView>
|
</RadListView>
|
||||||
<Label
|
<Label
|
||||||
v-if="!recipes.length && !filterFavorites && !filterMustTry"
|
v-if="!passedRecipes.length && !filterFavorites && !filterMustTry"
|
||||||
class="noResults"
|
class="noResults"
|
||||||
horizontalAlignment="center"
|
|
||||||
text='Click the "+" icon to add a new recipe.'
|
text='Click the "+" icon to add a new recipe.'
|
||||||
textAlignment="center"
|
|
||||||
textWrap="true"
|
textWrap="true"
|
||||||
/>
|
/>
|
||||||
<Label
|
<Label
|
||||||
v-if="!filteredRecipes.length && searchQuery"
|
v-if="!filteredRecipes.length && searchQuery"
|
||||||
class="noResults"
|
class="noResults"
|
||||||
horizontalAlignment="center"
|
|
||||||
:text="
|
:text="
|
||||||
`Your search "${searchQuery}" did not match any recipes in this category.`
|
`Your search "${searchQuery}" did not match any recipes in this category.`
|
||||||
"
|
"
|
||||||
textAlignment="center"
|
|
||||||
textWrap="true"
|
textWrap="true"
|
||||||
/>
|
/>
|
||||||
<Label
|
<Label
|
||||||
v-if="!filteredRecipes.length && filterFavorites && !searchQuery"
|
v-if="!filteredRecipes.length && filterFavorites && !searchQuery"
|
||||||
class="noResults"
|
class="noResults"
|
||||||
horizontalAlignment="center"
|
|
||||||
text="Your favorite recipes will be listed here."
|
text="Your favorite recipes will be listed here."
|
||||||
textAlignment="center"
|
|
||||||
textWrap="true"
|
textWrap="true"
|
||||||
/>
|
/>
|
||||||
<Label
|
<Label
|
||||||
v-if="!filteredRecipes.length && filterMustTry && !searchQuery"
|
v-if="!filteredRecipes.length && filterMustTry && !searchQuery"
|
||||||
class="noResults"
|
class="noResults"
|
||||||
horizontalAlignment="center"
|
text="Your must-try recipes will be listed here."
|
||||||
text="Your Must-Try recipes will be listed here."
|
|
||||||
textAlignment="center"
|
|
||||||
textWrap="true"
|
textWrap="true"
|
||||||
/>
|
/>
|
||||||
<GridLayout id="btnFabContainer" rows="*,88" columns="*,88">
|
<GridLayout id="btnFabContainer" rows="*,88" columns="*,88">
|
||||||
|
@ -143,8 +164,12 @@ import ActionDialog from "./modal/ActionDialog.vue"
|
||||||
import ConfirmDialog from "./modal/ConfirmDialog.vue"
|
import ConfirmDialog from "./modal/ConfirmDialog.vue"
|
||||||
import { mapState, mapActions } from "vuex"
|
import { mapState, mapActions } from "vuex"
|
||||||
|
|
||||||
|
import { Couchbase } from "nativescript-couchbase-plugin"
|
||||||
|
const cb = new Couchbase("enrecipes")
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: [
|
props: [
|
||||||
|
"passedRecipes",
|
||||||
"filterFavorites",
|
"filterFavorites",
|
||||||
"filterMustTry",
|
"filterMustTry",
|
||||||
"selectedCategory",
|
"selectedCategory",
|
||||||
|
@ -161,31 +186,31 @@ export default {
|
||||||
searchQuery: "",
|
searchQuery: "",
|
||||||
viewIsScrolled: false,
|
viewIsScrolled: false,
|
||||||
showSearch: false,
|
showSearch: false,
|
||||||
// leftAction: false,
|
|
||||||
rightAction: false,
|
rightAction: false,
|
||||||
sortType: "Natural order",
|
sortType: "Natural order",
|
||||||
|
deletionDialogActive: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(["recipes", "icon", "currentComponent"]),
|
...mapState(["icon", "currentComponent"]),
|
||||||
filteredRecipes() {
|
filteredRecipes() {
|
||||||
if (this.filterFavorites) {
|
if (this.filterFavorites) {
|
||||||
return this.recipes.filter(
|
return this.passedRecipes.filter(
|
||||||
(e) =>
|
(e) =>
|
||||||
e.isFavorite && e.title.toLowerCase().includes(this.searchQuery)
|
e.isFavorite && e.title.toLowerCase().includes(this.searchQuery)
|
||||||
)
|
)
|
||||||
} else if (this.filterMustTry) {
|
} else if (this.filterMustTry) {
|
||||||
return this.recipes.filter(
|
return this.passedRecipes.filter(
|
||||||
(e) => !e.tried && e.title.toLowerCase().includes(this.searchQuery)
|
(e) => !e.tried && e.title.toLowerCase().includes(this.searchQuery)
|
||||||
)
|
)
|
||||||
} else if (this.selectedCategory) {
|
} else if (this.selectedCategory) {
|
||||||
return this.recipes.filter(
|
return this.passedRecipes.filter(
|
||||||
(e) =>
|
(e) =>
|
||||||
e.category === this.selectedCategory &&
|
e.category === this.selectedCategory &&
|
||||||
e.title.toLowerCase().includes(this.searchQuery)
|
e.title.toLowerCase().includes(this.searchQuery)
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
return this.recipes.filter((e) =>
|
return this.passedRecipes.filter((e) =>
|
||||||
e.title.toLowerCase().includes(this.searchQuery)
|
e.title.toLowerCase().includes(this.searchQuery)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -193,6 +218,15 @@ export default {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions(["setCurrentComponentAction", "deleteRecipeAction"]),
|
...mapActions(["setCurrentComponentAction", "deleteRecipeAction"]),
|
||||||
|
initializePage() {
|
||||||
|
this.filterFavorites
|
||||||
|
? this.setComponent("Favorites")
|
||||||
|
: this.filterMustTry
|
||||||
|
? this.setComponent("Must-Try")
|
||||||
|
: this.selectedCategory
|
||||||
|
? this.setComponent(this.selectedCategory)
|
||||||
|
: this.setComponent("EnRecipes")
|
||||||
|
},
|
||||||
openSearch() {
|
openSearch() {
|
||||||
this.showSearch = true
|
this.showSearch = true
|
||||||
this.hijackLocalBackEvent()
|
this.hijackLocalBackEvent()
|
||||||
|
@ -297,15 +331,6 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
initializePage() {
|
|
||||||
this.filterFavorites
|
|
||||||
? this.setComponent("Favorites")
|
|
||||||
: this.filterMustTry
|
|
||||||
? this.setComponent("Must-Try")
|
|
||||||
: this.selectedCategory
|
|
||||||
? this.setComponent(this.selectedCategory)
|
|
||||||
: this.setComponent("EnRecipes")
|
|
||||||
},
|
|
||||||
onSwiping({ data, object }) {
|
onSwiping({ data, object }) {
|
||||||
const swipeLimits = data.swipeLimits
|
const swipeLimits = data.swipeLimits
|
||||||
const swipeView = object
|
const swipeView = object
|
||||||
|
@ -318,21 +343,25 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onSwipeEnded({ index }) {
|
onSwipeEnded({ index }) {
|
||||||
if (this.rightAction) this.deleteRecipe(index)
|
let recipeID = this.passedRecipes[index].id
|
||||||
|
if (this.rightAction && !this.deletionDialogActive)
|
||||||
|
this.deleteRecipe(index, recipeID)
|
||||||
this.rightAction = false
|
this.rightAction = false
|
||||||
},
|
},
|
||||||
deleteRecipe(index) {
|
deleteRecipe(index, recipeID) {
|
||||||
|
this.deletionDialogActive = true
|
||||||
this.$showModal(ConfirmDialog, {
|
this.$showModal(ConfirmDialog, {
|
||||||
props: {
|
props: {
|
||||||
title: "Delete recipe",
|
title: "Delete recipe",
|
||||||
description: `Are you sure you want to delete the recipe "${this.recipes[index].title}"?`,
|
description: `Are you sure you want to delete the recipe "${this.passedRecipes[index].title}"?`,
|
||||||
cancelButtonText: "CANCEL",
|
cancelButtonText: "CANCEL",
|
||||||
okButtonText: "DELETE",
|
okButtonText: "DELETE",
|
||||||
},
|
},
|
||||||
}).then((action) => {
|
}).then((action) => {
|
||||||
if (action) {
|
if (action) {
|
||||||
this.deleteRecipeAction(index)
|
cb.deleteDocument(recipeID)
|
||||||
}
|
}
|
||||||
|
this.deletionDialogActive = false
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
getTotalTime(prepTime, cookTime) {
|
getTotalTime(prepTime, cookTime) {
|
||||||
|
@ -384,7 +413,7 @@ export default {
|
||||||
curve: "easeIn",
|
curve: "easeIn",
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
recipeIndex: this.recipes.indexOf(item),
|
recipeID: item.id,
|
||||||
hijackGlobalBackEvent: this.hijackGlobalBackEvent,
|
hijackGlobalBackEvent: this.hijackGlobalBackEvent,
|
||||||
releaseGlobalBackEvent: this.releaseGlobalBackEvent,
|
releaseGlobalBackEvent: this.releaseGlobalBackEvent,
|
||||||
},
|
},
|
||||||
|
|
|
@ -58,8 +58,15 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { ApplicationSettings } from "@nativescript/core"
|
import {
|
||||||
|
ApplicationSettings,
|
||||||
|
path,
|
||||||
|
getFileAccess,
|
||||||
|
knownFolders,
|
||||||
|
Application,
|
||||||
|
} from "@nativescript/core"
|
||||||
import * as permissions from "nativescript-permissions"
|
import * as permissions from "nativescript-permissions"
|
||||||
|
import { Zip } from "nativescript-zip"
|
||||||
|
|
||||||
import Theme from "@nativescript/theme"
|
import Theme from "@nativescript/theme"
|
||||||
import ActionDialog from "./modal/ActionDialog.vue"
|
import ActionDialog from "./modal/ActionDialog.vue"
|
||||||
|
@ -164,7 +171,24 @@ export default {
|
||||||
permissions
|
permissions
|
||||||
.requestPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
.requestPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
alert("Backup successful!")
|
const sdDownloadPath = android.os.Environment.getExternalStoragePublicDirectory(
|
||||||
|
android.os.Environment.DIRECTORY_DOWNLOADS
|
||||||
|
).toString()
|
||||||
|
let fromPath = path.join(knownFolders.documents().path, "enrecipes")
|
||||||
|
let destPath = path.join(sdDownloadPath, "enrecipes.zip")
|
||||||
|
console.log(fromPath, destPath, sdDownloadPath)
|
||||||
|
Zip.zip({
|
||||||
|
directory: fromPath,
|
||||||
|
archive: destPath,
|
||||||
|
})
|
||||||
|
.then((success) => {
|
||||||
|
console.log("success:" + success)
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
|
// console.log(fromPath, destPath, sdDownloadPath)
|
||||||
|
// alert("Backup successful!")
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
console.log("Uh oh, no permissions - plan B time!")
|
console.log("Uh oh, no permissions - plan B time!")
|
||||||
|
|
|
@ -95,9 +95,15 @@
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</TabViewItem>
|
</TabViewItem>
|
||||||
<TabViewItem title="Ingredients" v-if="recipe.ingredients.length">
|
<TabViewItem title="Ingredients">
|
||||||
<ScrollView scrollBarIndicatorVisible="false">
|
<ScrollView scrollBarIndicatorVisible="false">
|
||||||
<StackLayout padding="16 16 124">
|
<Label
|
||||||
|
v-if="!recipe.ingredients.length"
|
||||||
|
class="noResults"
|
||||||
|
text="Click the edit button to add ingredients to this recipe"
|
||||||
|
textWrap="true"
|
||||||
|
/>
|
||||||
|
<StackLayout v-else padding="16 16 124">
|
||||||
<AbsoluteLayout class="inputField">
|
<AbsoluteLayout class="inputField">
|
||||||
<TextField
|
<TextField
|
||||||
width="50%"
|
width="50%"
|
||||||
|
@ -135,9 +141,15 @@
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</TabViewItem>
|
</TabViewItem>
|
||||||
<TabViewItem title="Instructions" v-if="recipe.instructions.length">
|
<TabViewItem title="Instructions">
|
||||||
<ScrollView scrollBarIndicatorVisible="false">
|
<ScrollView scrollBarIndicatorVisible="false">
|
||||||
<StackLayout padding="32 16 132">
|
<Label
|
||||||
|
v-if="!recipe.instructions.length"
|
||||||
|
class="noResults"
|
||||||
|
text="Click the edit button to add instructions to this recipe"
|
||||||
|
textWrap="true"
|
||||||
|
/>
|
||||||
|
<StackLayout v-else padding="32 16 132">
|
||||||
<GridLayout
|
<GridLayout
|
||||||
columns="auto ,*"
|
columns="auto ,*"
|
||||||
v-for="(instruction, index) in recipe.instructions"
|
v-for="(instruction, index) in recipe.instructions"
|
||||||
|
@ -165,9 +177,15 @@
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</TabViewItem>
|
</TabViewItem>
|
||||||
<TabViewItem title="Notes" v-if="recipe.notes.length">
|
<TabViewItem title="Notes">
|
||||||
<ScrollView scrollBarIndicatorVisible="false">
|
<ScrollView scrollBarIndicatorVisible="false">
|
||||||
<StackLayout padding="32 16 132">
|
<Label
|
||||||
|
v-if="!recipe.notes.length"
|
||||||
|
class="noResults"
|
||||||
|
text="Click the edit button to add notes to this recipe"
|
||||||
|
textWrap="true"
|
||||||
|
/>
|
||||||
|
<StackLayout v-else padding="32 16 132">
|
||||||
<GridLayout
|
<GridLayout
|
||||||
columns="auto ,*"
|
columns="auto ,*"
|
||||||
v-for="(note, index) in recipe.notes"
|
v-for="(note, index) in recipe.notes"
|
||||||
|
@ -191,9 +209,15 @@
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</TabViewItem>
|
</TabViewItem>
|
||||||
<TabViewItem title="References" v-if="recipe.references.length">
|
<TabViewItem title="References">
|
||||||
<ScrollView scrollBarIndicatorVisible="false">
|
<ScrollView scrollBarIndicatorVisible="false">
|
||||||
<StackLayout padding="32 16 132">
|
<Label
|
||||||
|
v-if="!recipe.references.length"
|
||||||
|
class="noResults"
|
||||||
|
text="Click the edit button to add references to this recipe"
|
||||||
|
textWrap="true"
|
||||||
|
/>
|
||||||
|
<StackLayout v-else padding="32 16 132">
|
||||||
<GridLayout
|
<GridLayout
|
||||||
columns="auto ,*"
|
columns="auto ,*"
|
||||||
v-for="(reference, index) in recipe.references"
|
v-for="(reference, index) in recipe.references"
|
||||||
|
@ -243,19 +267,20 @@ import { mapState, mapActions } from "vuex"
|
||||||
|
|
||||||
import EditRecipe from "./EditRecipe.vue"
|
import EditRecipe from "./EditRecipe.vue"
|
||||||
|
|
||||||
|
import { Couchbase } from "nativescript-couchbase-plugin"
|
||||||
|
const cb = new Couchbase("enrecipes")
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ["recipeIndex", "hijackGlobalBackEvent", "releaseGlobalBackEvent"],
|
props: ["recipeID", "hijackGlobalBackEvent", "releaseGlobalBackEvent"],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
busy: false,
|
busy: false,
|
||||||
portionScale: 1,
|
portionScale: 1,
|
||||||
|
recipe: null,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(["icon", "recipes"]),
|
...mapState(["icon"]),
|
||||||
recipe() {
|
|
||||||
return this.recipes[this.recipeIndex]
|
|
||||||
},
|
|
||||||
screenWidth() {
|
screenWidth() {
|
||||||
return Screen.mainScreen.widthDIPs
|
return Screen.mainScreen.widthDIPs
|
||||||
},
|
},
|
||||||
|
@ -266,11 +291,15 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions([
|
...mapActions(["toggleMustTryAction", "setCurrentComponentAction"]),
|
||||||
"toggleFavoriteAction",
|
initializePage() {
|
||||||
"toggleMustTryAction",
|
this.recipe = cb.getDocument(this.recipeID)
|
||||||
"setCurrentComponentAction",
|
this.releaseGlobalBackEvent()
|
||||||
]),
|
this.busy = false
|
||||||
|
setTimeout((e) => {
|
||||||
|
this.setCurrentComponentAction("ViewRecipe")
|
||||||
|
}, 500)
|
||||||
|
},
|
||||||
roundedQuantity(quantity, unit) {
|
roundedQuantity(quantity, unit) {
|
||||||
return Math.round(quantity * this.isPortionScalePositive * 100) / 100
|
return Math.round(quantity * this.isPortionScalePositive * 100) / 100
|
||||||
},
|
},
|
||||||
|
@ -283,24 +312,27 @@ export default {
|
||||||
curve: "easeIn",
|
curve: "easeIn",
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
recipeIndex: this.recipeIndex,
|
recipeID: this.recipeID,
|
||||||
},
|
},
|
||||||
// backstackVisible: false,
|
// backstackVisible: false,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
toggle(key) {
|
||||||
|
this.recipe[key] = !this.recipe[key]
|
||||||
|
cb.updateDocument(this.recipeID, this.recipe)
|
||||||
|
this.recipe = cb.getDocument(this.recipeID)
|
||||||
|
},
|
||||||
toggleFavorite() {
|
toggleFavorite() {
|
||||||
this.recipe.isFavorite
|
this.recipe.isFavorite
|
||||||
? Toast.makeText("Removed from Favorites").show()
|
? Toast.makeText("Removed from Favorites").show()
|
||||||
: Toast.makeText("Added to Favorites").show()
|
: Toast.makeText("Added to Favorites").show()
|
||||||
|
this.toggle("isFavorite")
|
||||||
this.toggleFavoriteAction(this.recipeIndex)
|
|
||||||
},
|
},
|
||||||
toggleMustTry() {
|
toggleMustTry() {
|
||||||
this.recipe.tried
|
this.recipe.tried
|
||||||
? Toast.makeText("Added to Must-Try").show()
|
? Toast.makeText("Added to Must-Try").show()
|
||||||
: Toast.makeText("Removed from Must-Try").show()
|
: Toast.makeText("Removed from Must-Try").show()
|
||||||
|
this.toggle("tried")
|
||||||
this.toggleMustTryAction(this.recipeIndex)
|
|
||||||
},
|
},
|
||||||
getTime(time) {
|
getTime(time) {
|
||||||
let t = time.split(":")
|
let t = time.split(":")
|
||||||
|
@ -311,13 +343,9 @@ export default {
|
||||||
openURL(args, url) {
|
openURL(args, url) {
|
||||||
Utils.openUrl(url)
|
Utils.openUrl(url)
|
||||||
},
|
},
|
||||||
initializePage() {
|
},
|
||||||
this.releaseGlobalBackEvent()
|
created() {
|
||||||
this.busy = false
|
this.recipe = cb.getDocument(this.recipeID)
|
||||||
setTimeout((e) => {
|
|
||||||
this.setCurrentComponentAction("ViewRecipe")
|
|
||||||
}, 500)
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<Page>
|
<Page>
|
||||||
<StackLayout
|
<StackLayout class="dialogContainer" :class="isLightMode">
|
||||||
class="dialogContainer"
|
<!-- :class="isLightTheme ? 'light' : 'dark'" -->
|
||||||
:class="isLightTheme ? 'light' : 'dark'"
|
|
||||||
>
|
|
||||||
<Label class="dialogTitle orkm" :text="title" />
|
<Label class="dialogTitle orkm" :text="title" />
|
||||||
<ListView
|
<ListView
|
||||||
width="100%"
|
width="100%"
|
||||||
|
@ -38,21 +36,18 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Theme from "@nativescript/theme"
|
import { Application } from "@nativescript/core"
|
||||||
export default {
|
export default {
|
||||||
props: ["title", "list", "height", "action"],
|
props: ["title", "list", "height", "action"],
|
||||||
data() {
|
computed: {
|
||||||
return {
|
isLightMode() {
|
||||||
isLightTheme: true,
|
return Application.systemAppearance()
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
tapAction({ item }) {
|
tapAction({ item }) {
|
||||||
this.$modal.close(item)
|
this.$modal.close(item)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
created() {
|
|
||||||
this.isLightTheme = Theme.getMode() == "ns-light" ? true : false
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<Page>
|
<Page>
|
||||||
<StackLayout
|
<StackLayout class="dialogContainer" :class="isLightMode">
|
||||||
class="dialogContainer"
|
|
||||||
:class="isLightTheme ? 'light' : 'dark'"
|
|
||||||
>
|
|
||||||
<Label class="dialogTitle orkm" :text="title" />
|
<Label class="dialogTitle orkm" :text="title" />
|
||||||
<Label class="dialogDescription" :text="description" textWrap="true" />
|
<Label class="dialogDescription" :text="description" textWrap="true" />
|
||||||
<StackLayout
|
<StackLayout
|
||||||
|
@ -27,16 +24,13 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Theme from "@nativescript/theme"
|
import { Application } from "@nativescript/core"
|
||||||
export default {
|
export default {
|
||||||
props: ["title", "description", "cancelButtonText", "okButtonText"],
|
props: ["title", "description", "cancelButtonText", "okButtonText"],
|
||||||
data() {
|
computed: {
|
||||||
return {
|
isLightMode() {
|
||||||
isLightTheme: true,
|
return Application.systemAppearance()
|
||||||
}
|
},
|
||||||
},
|
|
||||||
created() {
|
|
||||||
this.isLightTheme = Theme.getMode() == "ns-light" ? true : false
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,16 +1,14 @@
|
||||||
<template>
|
<template>
|
||||||
<Page>
|
<Page>
|
||||||
<StackLayout
|
<StackLayout class="dialogContainer" :class="isLightMode">
|
||||||
class="dialogContainer"
|
|
||||||
:class="isLightTheme ? 'light' : 'dark'"
|
|
||||||
>
|
|
||||||
<Label class="dialogTitle orkm" :text="title" />
|
<Label class="dialogTitle orkm" :text="title" />
|
||||||
<TextField
|
<StackLayout class="dialogInputField">
|
||||||
width="100%"
|
<TextField
|
||||||
:hint="hint"
|
:hint="hint"
|
||||||
v-model="category"
|
v-model="category"
|
||||||
autocapitalizationType="words"
|
autocapitalizationType="words"
|
||||||
/>
|
/>
|
||||||
|
</StackLayout>
|
||||||
<StackLayout orientation="horizontal" horizontalAlignment="right">
|
<StackLayout orientation="horizontal" horizontalAlignment="right">
|
||||||
<Label class="action orkm" text="CANCEL" @tap="$modal.close(false)" />
|
<Label class="action orkm" text="CANCEL" @tap="$modal.close(false)" />
|
||||||
<Label
|
<Label
|
||||||
|
@ -24,34 +22,18 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Theme from "@nativescript/theme"
|
import { Application } from "@nativescript/core"
|
||||||
export default {
|
export default {
|
||||||
props: ["title", "hint", "action"],
|
props: ["title", "hint", "action"],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
category: null,
|
category: null,
|
||||||
isLightTheme: true,
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
computed: {
|
||||||
this.isLightTheme = Theme.getMode() == "ns-light" ? true : false
|
isLightMode() {
|
||||||
|
return Application.systemAppearance()
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
|
||||||
TextField {
|
|
||||||
margin: 0 24 16;
|
|
||||||
}
|
|
||||||
.dialogContainer {
|
|
||||||
padding: 0 24;
|
|
||||||
}
|
|
||||||
.dialogTitle {
|
|
||||||
padding: 24 0 12;
|
|
||||||
font-size: 20;
|
|
||||||
}
|
|
||||||
.action {
|
|
||||||
padding: 24 0 24 32;
|
|
||||||
font-size: 12;
|
|
||||||
color: #ff7043;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
341
app/store.js
341
app/store.js
|
@ -5,181 +5,7 @@ Vue.use(Vuex)
|
||||||
|
|
||||||
export default new Vuex.Store({
|
export default new Vuex.Store({
|
||||||
state: {
|
state: {
|
||||||
recipes: [
|
// recipes: [],
|
||||||
{
|
|
||||||
imageSrc: null,
|
|
||||||
title: "Mediterranean Salad",
|
|
||||||
category: "Salads",
|
|
||||||
prepTime: "12:25",
|
|
||||||
cookTime: "00:30",
|
|
||||||
portionSize: 1,
|
|
||||||
ingredients: [
|
|
||||||
{
|
|
||||||
item: "Cucumbers, Seeded And Sliced",
|
|
||||||
quantity: 3,
|
|
||||||
unit: "unit",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
item: "Crumbled Feta Cheese",
|
|
||||||
quantity: 1.5,
|
|
||||||
unit: "cup",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
item: "Black Olives, Pitted And Sliced",
|
|
||||||
quantity: 1,
|
|
||||||
unit: "cup",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
item: "Diced Roma Tomatoes",
|
|
||||||
quantity: 3,
|
|
||||||
unit: "cup",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
item: "Diced Oil Packed Sun Dried Tomatoes, Drained, Oil Reserved",
|
|
||||||
quantity: 0.3,
|
|
||||||
unit: "cup",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
item: "Onion, Sliced",
|
|
||||||
quantity: 1.5,
|
|
||||||
unit: "unit",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
item: "Cucumbers, Seeded And Sliced",
|
|
||||||
quantity: 3,
|
|
||||||
unit: "unit",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
item: "Crumbled Feta Cheese",
|
|
||||||
quantity: 1.5,
|
|
||||||
unit: "cup",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
item: "Black Olives, Pitted And Sliced",
|
|
||||||
quantity: 1,
|
|
||||||
unit: "cup",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
item: "Diced Roma Tomatoes",
|
|
||||||
quantity: 3,
|
|
||||||
unit: "cup",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
item: "Diced Oil Packed Sun Dried Tomatoes, Drained, Oil Reserved",
|
|
||||||
quantity: 0.3,
|
|
||||||
unit: "cup",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
item: "Onion, Sliced",
|
|
||||||
quantity: 1.5,
|
|
||||||
unit: "unit",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
item: "Cucumbers, Seeded And Sliced",
|
|
||||||
quantity: 3,
|
|
||||||
unit: "unit",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
item: "Crumbled Feta Cheese",
|
|
||||||
quantity: 1.5,
|
|
||||||
unit: "cup",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
item: "Black Olives, Pitted And Sliced",
|
|
||||||
quantity: 1,
|
|
||||||
unit: "cup",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
item: "Diced Roma Tomatoes",
|
|
||||||
quantity: 3,
|
|
||||||
unit: "cup",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
item: "Diced Oil Packed Sun Dried Tomatoes, Drained, Oil Reserved",
|
|
||||||
quantity: 0.3,
|
|
||||||
unit: "cup",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
item: "Onion, Sliced",
|
|
||||||
quantity: 1.5,
|
|
||||||
unit: "unit",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
instructions: [
|
|
||||||
"In a large salad bowl, toss together the cucumbers, feta cheese, olives, roma tomatoes, sun-dried tomatoes, 2 tablespoons reserved sun-dried tomato oil, and red onion.",
|
|
||||||
"Chill until serving.",
|
|
||||||
"In a large salad bowl, toss together the cucumbers, feta cheese, olives, roma tomatoes, sun-dried tomatoes, 2 tablespoons reserved sun-dried tomato oil, and red onion. In a large salad bowl, toss together the cucumbers, feta cheese, olives, roma tomatoes, sun-dried tomatoes, 2 tablespoons reserved sun-dried tomato oil, and red onion.",
|
|
||||||
"Chill until serving.",
|
|
||||||
"Chill until serving.",
|
|
||||||
"In a large salad bowl, toss together the cucumbers, feta cheese, olives, roma tomatoes, sun-dried tomatoes, 2 tablespoons reserved sun-dried tomato oil, and red onion.",
|
|
||||||
"Chill until serving.",
|
|
||||||
"Chill until serving.",
|
|
||||||
"Chill until serving.",
|
|
||||||
"Chill until serving.",
|
|
||||||
"Chill until serving.",
|
|
||||||
],
|
|
||||||
notes: [
|
|
||||||
"Per Serving: 130.6 calories; protein 5.5g 11% DV; carbohydrates 9.3g 3% DV; fat 8.8g 14% DV; cholesterol 25mg 8% DV; sodium 486.4mg 20% DV.",
|
|
||||||
"Per Serving: 130.6 calories; protein 5.5g 11% DV; carbohydrates 9.3g 3% DV; fat 8.8g 14% DV; cholesterol 25mg 8% DV; sodium 486.4mg 20% DV.",
|
|
||||||
"Per Serving: 130.6 calories; protein 5.5g 11% DV; carbohydrates 9.3g 3% DV; fat 8.8g 14% DV; cholesterol 25mg 8% DV; sodium 486.4mg 20% DV.",
|
|
||||||
],
|
|
||||||
references: [
|
|
||||||
"https://www.allrecipes.com/recipe/14403/mediterranean-greek-salad/",
|
|
||||||
"https://www.allrecipes.com/recipe/14403/mediterranean-greek-salad/",
|
|
||||||
"https://www.allrecipes.com/recipe/14403/mediterranean-greek-salad/",
|
|
||||||
"https://www.allrecipes.com/recipe/14403/mediterranean-greek-salad/",
|
|
||||||
],
|
|
||||||
isFavorite: true,
|
|
||||||
tried: false,
|
|
||||||
lastModified: "2020-10-18T17:37:51.798Z",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
imageSrc: null,
|
|
||||||
title: "Fresh Tomato Sauce",
|
|
||||||
category: "Sauces",
|
|
||||||
prepTime: "00:45",
|
|
||||||
cookTime: "00:35",
|
|
||||||
portionSize: 1,
|
|
||||||
ingredients: [],
|
|
||||||
instructions: [],
|
|
||||||
notes: [],
|
|
||||||
references: [],
|
|
||||||
isFavorite: true,
|
|
||||||
tried: true,
|
|
||||||
lastModified: "2020-10-15T17:37:51.798Z",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
imageSrc: null,
|
|
||||||
title: "Creamy Mushroom Herb Pasta",
|
|
||||||
category: "Lunch",
|
|
||||||
prepTime: "00:10",
|
|
||||||
cookTime: "00:15",
|
|
||||||
portionSize: 1,
|
|
||||||
ingredients: [],
|
|
||||||
instructions: [],
|
|
||||||
notes: [],
|
|
||||||
references: [],
|
|
||||||
isFavorite: false,
|
|
||||||
tried: false,
|
|
||||||
lastModified: "2020-10-12T17:37:51.798Z",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
imageSrc: null,
|
|
||||||
title: "Grilled Cheese Sandwich",
|
|
||||||
category: "Lunch",
|
|
||||||
prepTime: "00:50",
|
|
||||||
cookTime: "00:12",
|
|
||||||
portionSize: 1,
|
|
||||||
ingredients: [],
|
|
||||||
instructions: [],
|
|
||||||
notes: [],
|
|
||||||
references: [],
|
|
||||||
isFavorite: false,
|
|
||||||
tried: true,
|
|
||||||
lastModified: "2020-10-03T17:37:51.798Z",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
viewIsScrolled: false,
|
|
||||||
icon: {
|
icon: {
|
||||||
home: "\ued99",
|
home: "\ued99",
|
||||||
heart: "\ued94",
|
heart: "\ued94",
|
||||||
|
@ -210,123 +36,74 @@ export default new Vuex.Store({
|
||||||
musttry: "\uec96",
|
musttry: "\uec96",
|
||||||
musttryOutline: "\ue9bb",
|
musttryOutline: "\ue9bb",
|
||||||
},
|
},
|
||||||
units: [
|
|
||||||
"unit",
|
|
||||||
"tsp",
|
|
||||||
"Tbsp",
|
|
||||||
"oz",
|
|
||||||
"cup",
|
|
||||||
"pt",
|
|
||||||
"qt",
|
|
||||||
"lb",
|
|
||||||
"gal",
|
|
||||||
"ml",
|
|
||||||
"L",
|
|
||||||
"mg",
|
|
||||||
"g",
|
|
||||||
"kg",
|
|
||||||
"mm",
|
|
||||||
"cm",
|
|
||||||
"m",
|
|
||||||
"in",
|
|
||||||
"°C",
|
|
||||||
"°F",
|
|
||||||
],
|
|
||||||
categories: [
|
|
||||||
"Appetizers",
|
|
||||||
"BBQ",
|
|
||||||
"Beverages",
|
|
||||||
"Breads",
|
|
||||||
"Breakfast",
|
|
||||||
"Desserts",
|
|
||||||
"Dinner",
|
|
||||||
"Drinks",
|
|
||||||
"Healthy",
|
|
||||||
"Lunch",
|
|
||||||
"Main dishes",
|
|
||||||
"Meat",
|
|
||||||
"Noodles",
|
|
||||||
"Pasta",
|
|
||||||
"Poultry",
|
|
||||||
"Rice",
|
|
||||||
"Salads",
|
|
||||||
"Sauces",
|
|
||||||
"Seafood",
|
|
||||||
"Side dishes",
|
|
||||||
"Snacks",
|
|
||||||
"Soups",
|
|
||||||
"Undefined",
|
|
||||||
"Vegan",
|
|
||||||
"Vegetarian",
|
|
||||||
],
|
|
||||||
currentComponent: "EnRecipes",
|
currentComponent: "EnRecipes",
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
addRecipe(state, recipe) {
|
// addRecipe(state, recipe) {
|
||||||
state.recipes.push(recipe)
|
// state.recipes.push(recipe)
|
||||||
},
|
// },
|
||||||
addCategory(state, category) {
|
// addCategory(state, category) {
|
||||||
let a = state.categories.filter((e) => e === category).length
|
// let a = state.categories.filter((e) => e === category).length
|
||||||
if (a == 0) {
|
// if (a == 0) {
|
||||||
state.categories.push(category)
|
// state.categories.push(category)
|
||||||
state.categories.sort()
|
// state.categories.sort()
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
overwriteRecipe(state, { index, recipe }) {
|
// overwriteRecipe(state, { index, recipe }) {
|
||||||
Object.assign(state.recipes[index], recipe)
|
// Object.assign(state.recipes[index], recipe)
|
||||||
},
|
// },
|
||||||
deleteRecipe(state, index) {
|
// deleteRecipe(state, index) {
|
||||||
state.recipes.splice(index, 1)
|
// state.recipes.splice(index, 1)
|
||||||
},
|
// },
|
||||||
toggleFavorite(state, index) {
|
// toggleFavorite(state, index) {
|
||||||
state.recipes[index].isFavorite = !state.recipes[index].isFavorite
|
// state.recipes[index].isFavorite = !state.recipes[index].isFavorite
|
||||||
},
|
// },
|
||||||
toggleMustTry(state, index) {
|
// toggleMustTry(state, index) {
|
||||||
state.recipes[index].tried = !state.recipes[index].tried
|
// state.recipes[index].tried = !state.recipes[index].tried
|
||||||
},
|
// },
|
||||||
setCurrentComponent(state, comp) {
|
setCurrentComponent(state, comp) {
|
||||||
state.currentComponent = comp
|
state.currentComponent = comp
|
||||||
},
|
},
|
||||||
renameCategory(state, { current, updated }) {
|
// renameCategory(state, { current, updated }) {
|
||||||
let a = state.categories.filter((e) => e === updated).length
|
// let a = state.categories.filter((e) => e === updated).length
|
||||||
if (a == 0) {
|
// if (a == 0) {
|
||||||
// add updated category to categories
|
// // add updated category to categories
|
||||||
state.categories.splice(state.categories.indexOf(current), 1)
|
// state.categories.splice(state.categories.indexOf(current), 1)
|
||||||
state.categories.push(updated)
|
// state.categories.push(updated)
|
||||||
state.categories.sort()
|
// state.categories.sort()
|
||||||
// rename all occurences
|
// // rename all occurences
|
||||||
state.recipes.forEach((e, i) => {
|
// state.recipes.forEach((e, i) => {
|
||||||
if (e.category == current) {
|
// if (e.category == current) {
|
||||||
state.recipes[i].category = updated
|
// state.recipes[i].category = updated
|
||||||
}
|
// }
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
addRecipeAction({ commit }, recipe) {
|
// addRecipeAction({ commit }, recipe) {
|
||||||
commit("addRecipe", recipe)
|
// commit("addRecipe", recipe)
|
||||||
},
|
// },
|
||||||
addCategoryAction({ commit }, category) {
|
// addCategoryAction({ commit }, category) {
|
||||||
commit("addCategory", category)
|
// commit("addCategory", category)
|
||||||
},
|
// },
|
||||||
overwriteRecipeAction({ commit }, updatedRecipe) {
|
// overwriteRecipeAction({ commit }, updatedRecipe) {
|
||||||
commit("overwriteRecipe", updatedRecipe)
|
// commit("overwriteRecipe", updatedRecipe)
|
||||||
},
|
// },
|
||||||
deleteRecipeAction({ commit }, index) {
|
// deleteRecipeAction({ commit }, index) {
|
||||||
commit("deleteRecipe", index)
|
// commit("deleteRecipe", index)
|
||||||
},
|
// },
|
||||||
toggleFavoriteAction({ commit }, index) {
|
// toggleFavoriteAction({ commit }, index) {
|
||||||
commit("toggleFavorite", index)
|
// commit("toggleFavorite", index)
|
||||||
},
|
// },
|
||||||
toggleMustTryAction({ commit }, index) {
|
// toggleMustTryAction({ commit }, index) {
|
||||||
commit("toggleMustTry", index)
|
// commit("toggleMustTry", index)
|
||||||
},
|
// },
|
||||||
setCurrentComponentAction({ commit }, comp) {
|
setCurrentComponentAction({ commit }, comp) {
|
||||||
commit("setCurrentComponent", comp)
|
commit("setCurrentComponent", comp)
|
||||||
},
|
},
|
||||||
renameCategoryAction({ commit }, category) {
|
// renameCategoryAction({ commit }, category) {
|
||||||
commit("renameCategory", category)
|
// commit("renameCategory", category)
|
||||||
},
|
// },
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
4499
package-lock.json
generated
4499
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -11,6 +11,7 @@
|
||||||
"@nativescript/core": "~7.0.0",
|
"@nativescript/core": "~7.0.0",
|
||||||
"@nativescript/datetimepicker": "^2.0.4",
|
"@nativescript/datetimepicker": "^2.0.4",
|
||||||
"@nativescript/theme": "^3.0.0",
|
"@nativescript/theme": "^3.0.0",
|
||||||
|
"@nativescript/webpack": "3.0.0",
|
||||||
"@nstudio/nativescript-floatingactionbutton": "^3.0.3",
|
"@nstudio/nativescript-floatingactionbutton": "^3.0.3",
|
||||||
"nativescript-camera": "^4.5.0",
|
"nativescript-camera": "^4.5.0",
|
||||||
"nativescript-couchbase-plugin": "^0.9.6",
|
"nativescript-couchbase-plugin": "^0.9.6",
|
||||||
|
@ -20,6 +21,7 @@
|
||||||
"nativescript-ui-listview": "^9.0.4",
|
"nativescript-ui-listview": "^9.0.4",
|
||||||
"nativescript-ui-sidedrawer": "^9.0.3",
|
"nativescript-ui-sidedrawer": "^9.0.3",
|
||||||
"nativescript-vue": "^2.6.1",
|
"nativescript-vue": "^2.6.1",
|
||||||
|
"nativescript-zip": "^4.0.2",
|
||||||
"vuex": "^3.3.0"
|
"vuex": "^3.3.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -28,7 +30,6 @@
|
||||||
"@nativescript/android": "7.0.1",
|
"@nativescript/android": "7.0.1",
|
||||||
"@types/node": "^14.0.27",
|
"@types/node": "^14.0.27",
|
||||||
"babel-loader": "^8.1.0",
|
"babel-loader": "^8.1.0",
|
||||||
"nativescript-dev-webpack": "^1.5.1",
|
|
||||||
"nativescript-vue-template-compiler": "^2.6.0",
|
"nativescript-vue-template-compiler": "^2.6.0",
|
||||||
"node-sass": "^4.13.1",
|
"node-sass": "^4.13.1",
|
||||||
"vue-loader": "^15.9.1"
|
"vue-loader": "^15.9.1"
|
||||||
|
|
Loading…
Reference in a new issue