implemented couchbase, fs image import, zip export

This commit is contained in:
Vishnu Raghav B 2020-10-24 23:32:35 +05:30
parent 7c102fe518
commit 1d7bca959e
13 changed files with 2503 additions and 2892 deletions

View file

@ -9,10 +9,18 @@
// e.g. project.ext.googlePlayServicesVersion = "15.0.1"
// create a file named before-plugins.gradle in the current directory and place it there
// abiFilter "arm64-v8a" "armeabi-v7a" "x86" "x86_64"
android {
defaultConfig {
minSdkVersion 23
generatedDensities = []
ndk {
abiFilters.clear()
abiFilters.addAll(['arm64-v8a','x86'])
}
}
aaptOptions {
additionalParameters "--no-version-vectors"

View file

@ -71,7 +71,8 @@ Page {
color: $grayD4;
}
}
.view-imageHolder {
.view-imageHolder,
.recipeImgContainer {
color: $grayL1;
background: $grayL2;
}
@ -126,7 +127,8 @@ Page {
color: $grayL4;
}
}
.view-imageHolder {
.view-imageHolder,
.recipeImgContainer {
color: $grayD4;
background: #111;
}
@ -239,7 +241,7 @@ RadListView {
margin: 8 16;
border-radius: 6;
.recipe-info {
margin: 4 0;
margin: 4;
}
.recipe-cat {
font-size: 12;
@ -255,15 +257,31 @@ RadListView {
.recipe-time {
padding: 0;
}
.recipe-favorite {
font-size: 12;
padding: 14 8 0 0;
}
.recipe-cat,
.recipe-favorite {
.recipe-cat {
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
.group-header {
@ -372,13 +390,13 @@ RadListView {
}
// Edit Recipe
.fab-button {
color: white;
color: #fff;
height: 56;
width: 56;
background-color: #ff7043;
horizontal-align: center;
vertical-align: center;
border-radius: 100;
border-radius: 28;
padding: 16;
margin: 16;
}
@ -411,6 +429,9 @@ RadListView {
padding: 24 24 12;
font-size: 20;
}
.dialogInputField {
padding: 0 24 16;
}
.dialogDescription {
font-size: 16;
padding: 0 24 16;

View file

@ -34,6 +34,7 @@
class="sd-group-header orkm"
rows="auto"
columns="*, auto"
v-if="categories.length"
>
<Label col="0" text="Categories" />
<Label
@ -103,6 +104,7 @@
<!-- Home -->
<EnRecipes
ref="enrecipes"
:passedRecipes="recipes"
:filterFavorites="filterFavorites"
:filterMustTry="filterMustTry"
:selectedCategory="selectedCategory"
@ -132,8 +134,9 @@ import About from "./About.vue"
import PromptDialog from "./modal/PromptDialog.vue"
import { mapState, mapActions } from "vuex"
// import { Couchbase, ConcurrencyMode } from "nativescript-couchbase-plugin"
// const cb = new Couchbase("enrecipes")
import { Couchbase } from "nativescript-couchbase-plugin"
const cb = new Couchbase("enrecipes")
const cbCat = new Couchbase("categories")
let page
export default {
@ -177,10 +180,11 @@ export default {
},
],
catEditMode: false,
recipes: null,
}
},
computed: {
...mapState(["recipes", "categories", "icon", "currentComponent"]),
...mapState(["icon", "currentComponent"]),
categories() {
let arr = this.recipes.map((e) => {
return e.category
@ -214,9 +218,20 @@ export default {
if (this.categories.includes(result)) {
Toast.makeText("Category already exists!", "long").show()
} else {
this.renameCategoryAction({
current: item,
updated: result,
let categories = cbCat.getDocument("categories").categories
console.log(categories, categories.indexOf(item))
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
}
@ -293,6 +308,7 @@ export default {
backstackVisible: false,
})
this.closeDrawer()
this.catEditMode = false
} else if (!this.catEditMode) {
this.releaseGlobalBackEvent()
this.hijackGlobalBackEvent()
@ -342,40 +358,10 @@ export default {
created() {
let themeName = ApplicationSettings.getString("application-theme", "Light")
setTimeout((e) => Theme.setMode(Theme[themeName]), 50)
this.recipes = cb.query({ select: [] })
cb.addDatabaseChangeListener((e) => {
this.recipes = cb.query({ select: [] })
})
},
}
</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>

View file

@ -260,7 +260,14 @@
</template>
<script>
import { Screen, AndroidApplication } from "@nativescript/core"
import {
Screen,
AndroidApplication,
ImageSource,
path,
getFileAccess,
knownFolders,
} from "@nativescript/core"
import { Mediafilepicker } from "nativescript-mediafilepicker"
import { mapState, mapActions } from "vuex"
@ -269,8 +276,13 @@ import ActionDialog from "./modal/ActionDialog.vue"
import PromptDialog from "./modal/PromptDialog.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 {
props: ["recipeIndex", "selectedCategory"],
props: ["recipeID", "selectedCategory"],
data() {
return {
title: "New recipe",
@ -297,16 +309,67 @@ export default {
lastModified: null,
},
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,
cbCat: [],
newRecipeID: null,
}
},
computed: {
...mapState(["icon", "units", "categories", "currentComponent", "recipes"]),
...mapState(["icon", "currentComponent"]),
screenWidth() {
return Screen.mainScreen.widthDIPs
},
hasEnoughDetails() {
if (this.recipeIndex) {
if (this.recipeID) {
return (
JSON.stringify(this.recipeContent) !==
JSON.stringify(this.tempRecipeContent)
@ -317,26 +380,38 @@ export default {
},
},
methods: {
...mapActions([
"setCurrentComponentAction",
"overwriteRecipeAction",
"addRecipeAction",
"addCategoryAction",
]),
...mapActions(["setCurrentComponentAction"]),
initializePage() {
setTimeout((e) => {
this.setCurrentComponentAction("EditRecipe")
}, 500)
this.title = this.recipeIndex >= 0 ? "Edit recipe" : "New recipe"
if (this.recipeIndex >= 0) {
Object.assign(this.recipeContent, this.recipes[this.recipeIndex])
Object.assign(this.tempRecipeContent, this.recipes[this.recipeIndex])
this.title = this.recipeID ? "Edit recipe" : "New recipe"
if (this.recipeID) {
let recipe = cb.getDocument(this.recipeID)
Object.assign(this.recipeContent, recipe)
Object.assign(this.tempRecipeContent, recipe)
} else {
if (this.selectedCategory)
this.recipeContent.category = this.selectedCategory
Object.assign(this.tempRecipeContent, this.recipeContent)
this.newRecipeID = this.getRandomID()
}
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) {
if (Date.parse(time)) {
@ -375,13 +450,11 @@ export default {
saveRecipe() {
this.clearEmptyFields()
this.recipeContent.lastModified = new Date()
if (this.recipeIndex >= 0) {
this.overwriteRecipeAction({
index: this.recipeIndex,
recipe: this.recipeContent,
})
if (this.recipeID) {
cb.updateDocument(this.recipeID, this.recipeContent)
} else {
this.addRecipeAction(this.recipeContent)
this.recipeContent.id = this.newRecipeID
cb.createDocument(this.recipeContent, this.newRecipeID)
}
this.$navigateBack()
},
@ -416,7 +489,11 @@ export default {
this.hijackBackEvent()
if (result.length) {
this.recipeContent.category = result
this.addCategoryAction(result)
this.categories.push(result)
this.categories.sort()
cbCat.updateDocument("categories", {
categories: [...this.categories],
})
}
})
} else if (action) {
@ -471,7 +548,11 @@ export default {
takePicture() {
let mediafilepicker = new Mediafilepicker()
let vm = this
const options = { width: 800, height: 800, lockSquare: true }
const options = {
width: this.screenWidth,
height: this.screenWidth,
lockSquare: true,
}
const androidOptions = {
isFreeStyleCropEnabled: true,
statusBarColor: "black",
@ -505,8 +586,15 @@ export default {
},
})
mediafilepicker.on("getFiles", function(res) {
let result = res.object.get("results")
vm.recipeContent.imageSrc = result[0].file
let result = res.object.get("results")[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() {
@ -516,7 +604,10 @@ export default {
okButtonText: "Delete",
cancelButtonText: "Cancel",
}).then((e) => {
if (e) this.recipeContent.imageSrc = null
if (e) {
getFileAccess().deleteFile(this.recipeContent.imageSrc)
this.recipeContent.imageSrc = null
}
})
},

View file

@ -39,15 +39,27 @@
col="0"
/>
<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" />
<Label
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>
</ActionBar>
<AbsoluteLayout>
<RadListView
ref="listView"
itemHeight="112"
for="recipe in recipes"
for="recipe in passedRecipes"
swipeActions="true"
@itemSwipeProgressChanged="onSwiping"
@itemSwipeProgressEnded="onSwipeEnded"
@ -63,7 +75,24 @@
columns="112, *"
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">
<Label :text="recipe.category" class="orkm recipe-cat" />
<Label :text="recipe.title" class="orkm recipe-title" />
@ -86,37 +115,29 @@
</v-template>
</RadListView>
<Label
v-if="!recipes.length && !filterFavorites && !filterMustTry"
v-if="!passedRecipes.length && !filterFavorites && !filterMustTry"
class="noResults"
horizontalAlignment="center"
text='Click the "+" icon to add a new recipe.'
textAlignment="center"
textWrap="true"
/>
<Label
v-if="!filteredRecipes.length && searchQuery"
class="noResults"
horizontalAlignment="center"
:text="
`Your search &quot;${searchQuery}&quot; did not match any recipes in this category.`
"
textAlignment="center"
textWrap="true"
/>
<Label
v-if="!filteredRecipes.length && filterFavorites && !searchQuery"
class="noResults"
horizontalAlignment="center"
text="Your favorite recipes will be listed here."
textAlignment="center"
textWrap="true"
/>
<Label
v-if="!filteredRecipes.length && filterMustTry && !searchQuery"
class="noResults"
horizontalAlignment="center"
text="Your Must-Try recipes will be listed here."
textAlignment="center"
text="Your must-try recipes will be listed here."
textWrap="true"
/>
<GridLayout id="btnFabContainer" rows="*,88" columns="*,88">
@ -143,8 +164,12 @@ import ActionDialog from "./modal/ActionDialog.vue"
import ConfirmDialog from "./modal/ConfirmDialog.vue"
import { mapState, mapActions } from "vuex"
import { Couchbase } from "nativescript-couchbase-plugin"
const cb = new Couchbase("enrecipes")
export default {
props: [
"passedRecipes",
"filterFavorites",
"filterMustTry",
"selectedCategory",
@ -161,31 +186,31 @@ export default {
searchQuery: "",
viewIsScrolled: false,
showSearch: false,
// leftAction: false,
rightAction: false,
sortType: "Natural order",
deletionDialogActive: false,
}
},
computed: {
...mapState(["recipes", "icon", "currentComponent"]),
...mapState(["icon", "currentComponent"]),
filteredRecipes() {
if (this.filterFavorites) {
return this.recipes.filter(
return this.passedRecipes.filter(
(e) =>
e.isFavorite && e.title.toLowerCase().includes(this.searchQuery)
)
} else if (this.filterMustTry) {
return this.recipes.filter(
return this.passedRecipes.filter(
(e) => !e.tried && e.title.toLowerCase().includes(this.searchQuery)
)
} else if (this.selectedCategory) {
return this.recipes.filter(
return this.passedRecipes.filter(
(e) =>
e.category === this.selectedCategory &&
e.title.toLowerCase().includes(this.searchQuery)
)
} else {
return this.recipes.filter((e) =>
return this.passedRecipes.filter((e) =>
e.title.toLowerCase().includes(this.searchQuery)
)
}
@ -193,6 +218,15 @@ export default {
},
methods: {
...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() {
this.showSearch = true
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 }) {
const swipeLimits = data.swipeLimits
const swipeView = object
@ -318,21 +343,25 @@ export default {
}
},
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
},
deleteRecipe(index) {
deleteRecipe(index, recipeID) {
this.deletionDialogActive = true
this.$showModal(ConfirmDialog, {
props: {
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",
okButtonText: "DELETE",
},
}).then((action) => {
if (action) {
this.deleteRecipeAction(index)
cb.deleteDocument(recipeID)
}
this.deletionDialogActive = false
})
},
getTotalTime(prepTime, cookTime) {
@ -384,7 +413,7 @@ export default {
curve: "easeIn",
},
props: {
recipeIndex: this.recipes.indexOf(item),
recipeID: item.id,
hijackGlobalBackEvent: this.hijackGlobalBackEvent,
releaseGlobalBackEvent: this.releaseGlobalBackEvent,
},

View file

@ -58,8 +58,15 @@
</template>
<script>
import { ApplicationSettings } from "@nativescript/core"
import {
ApplicationSettings,
path,
getFileAccess,
knownFolders,
Application,
} from "@nativescript/core"
import * as permissions from "nativescript-permissions"
import { Zip } from "nativescript-zip"
import Theme from "@nativescript/theme"
import ActionDialog from "./modal/ActionDialog.vue"
@ -164,7 +171,24 @@ export default {
permissions
.requestPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
.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(() => {
console.log("Uh oh, no permissions - plan B time!")

View file

@ -95,9 +95,15 @@
</StackLayout>
</ScrollView>
</TabViewItem>
<TabViewItem title="Ingredients" v-if="recipe.ingredients.length">
<TabViewItem title="Ingredients">
<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">
<TextField
width="50%"
@ -135,9 +141,15 @@
</StackLayout>
</ScrollView>
</TabViewItem>
<TabViewItem title="Instructions" v-if="recipe.instructions.length">
<TabViewItem title="Instructions">
<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
columns="auto ,*"
v-for="(instruction, index) in recipe.instructions"
@ -165,9 +177,15 @@
</StackLayout>
</ScrollView>
</TabViewItem>
<TabViewItem title="Notes" v-if="recipe.notes.length">
<TabViewItem title="Notes">
<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
columns="auto ,*"
v-for="(note, index) in recipe.notes"
@ -191,9 +209,15 @@
</StackLayout>
</ScrollView>
</TabViewItem>
<TabViewItem title="References" v-if="recipe.references.length">
<TabViewItem title="References">
<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
columns="auto ,*"
v-for="(reference, index) in recipe.references"
@ -243,19 +267,20 @@ import { mapState, mapActions } from "vuex"
import EditRecipe from "./EditRecipe.vue"
import { Couchbase } from "nativescript-couchbase-plugin"
const cb = new Couchbase("enrecipes")
export default {
props: ["recipeIndex", "hijackGlobalBackEvent", "releaseGlobalBackEvent"],
props: ["recipeID", "hijackGlobalBackEvent", "releaseGlobalBackEvent"],
data() {
return {
busy: false,
portionScale: 1,
recipe: null,
}
},
computed: {
...mapState(["icon", "recipes"]),
recipe() {
return this.recipes[this.recipeIndex]
},
...mapState(["icon"]),
screenWidth() {
return Screen.mainScreen.widthDIPs
},
@ -266,11 +291,15 @@ export default {
},
},
methods: {
...mapActions([
"toggleFavoriteAction",
"toggleMustTryAction",
"setCurrentComponentAction",
]),
...mapActions(["toggleMustTryAction", "setCurrentComponentAction"]),
initializePage() {
this.recipe = cb.getDocument(this.recipeID)
this.releaseGlobalBackEvent()
this.busy = false
setTimeout((e) => {
this.setCurrentComponentAction("ViewRecipe")
}, 500)
},
roundedQuantity(quantity, unit) {
return Math.round(quantity * this.isPortionScalePositive * 100) / 100
},
@ -283,24 +312,27 @@ export default {
curve: "easeIn",
},
props: {
recipeIndex: this.recipeIndex,
recipeID: this.recipeID,
},
// backstackVisible: false,
})
},
toggle(key) {
this.recipe[key] = !this.recipe[key]
cb.updateDocument(this.recipeID, this.recipe)
this.recipe = cb.getDocument(this.recipeID)
},
toggleFavorite() {
this.recipe.isFavorite
? Toast.makeText("Removed from Favorites").show()
: Toast.makeText("Added to Favorites").show()
this.toggleFavoriteAction(this.recipeIndex)
this.toggle("isFavorite")
},
toggleMustTry() {
this.recipe.tried
? Toast.makeText("Added to Must-Try").show()
: Toast.makeText("Removed from Must-Try").show()
this.toggleMustTryAction(this.recipeIndex)
this.toggle("tried")
},
getTime(time) {
let t = time.split(":")
@ -311,13 +343,9 @@ export default {
openURL(args, url) {
Utils.openUrl(url)
},
initializePage() {
this.releaseGlobalBackEvent()
this.busy = false
setTimeout((e) => {
this.setCurrentComponentAction("ViewRecipe")
}, 500)
},
},
created() {
this.recipe = cb.getDocument(this.recipeID)
},
}
</script>

View file

@ -1,9 +1,7 @@
<template>
<Page>
<StackLayout
class="dialogContainer"
:class="isLightTheme ? 'light' : 'dark'"
>
<StackLayout class="dialogContainer" :class="isLightMode">
<!-- :class="isLightTheme ? 'light' : 'dark'" -->
<Label class="dialogTitle orkm" :text="title" />
<ListView
width="100%"
@ -38,21 +36,18 @@
</template>
<script>
import Theme from "@nativescript/theme"
import { Application } from "@nativescript/core"
export default {
props: ["title", "list", "height", "action"],
data() {
return {
isLightTheme: true,
}
computed: {
isLightMode() {
return Application.systemAppearance()
},
},
methods: {
tapAction({ item }) {
this.$modal.close(item)
},
},
created() {
this.isLightTheme = Theme.getMode() == "ns-light" ? true : false
},
}
</script>

View file

@ -1,9 +1,6 @@
<template>
<Page>
<StackLayout
class="dialogContainer"
:class="isLightTheme ? 'light' : 'dark'"
>
<StackLayout class="dialogContainer" :class="isLightMode">
<Label class="dialogTitle orkm" :text="title" />
<Label class="dialogDescription" :text="description" textWrap="true" />
<StackLayout
@ -27,16 +24,13 @@
</template>
<script>
import Theme from "@nativescript/theme"
import { Application } from "@nativescript/core"
export default {
props: ["title", "description", "cancelButtonText", "okButtonText"],
data() {
return {
isLightTheme: true,
}
},
created() {
this.isLightTheme = Theme.getMode() == "ns-light" ? true : false
computed: {
isLightMode() {
return Application.systemAppearance()
},
},
}
</script>

View file

@ -1,16 +1,14 @@
<template>
<Page>
<StackLayout
class="dialogContainer"
:class="isLightTheme ? 'light' : 'dark'"
>
<StackLayout class="dialogContainer" :class="isLightMode">
<Label class="dialogTitle orkm" :text="title" />
<TextField
width="100%"
:hint="hint"
v-model="category"
autocapitalizationType="words"
/>
<StackLayout class="dialogInputField">
<TextField
:hint="hint"
v-model="category"
autocapitalizationType="words"
/>
</StackLayout>
<StackLayout orientation="horizontal" horizontalAlignment="right">
<Label class="action orkm" text="CANCEL" @tap="$modal.close(false)" />
<Label
@ -24,34 +22,18 @@
</template>
<script>
import Theme from "@nativescript/theme"
import { Application } from "@nativescript/core"
export default {
props: ["title", "hint", "action"],
data() {
return {
category: null,
isLightTheme: true,
}
},
created() {
this.isLightTheme = Theme.getMode() == "ns-light" ? true : false
computed: {
isLightMode() {
return Application.systemAppearance()
},
},
}
</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>

View file

@ -5,181 +5,7 @@ Vue.use(Vuex)
export default new Vuex.Store({
state: {
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,
// recipes: [],
icon: {
home: "\ued99",
heart: "\ued94",
@ -210,123 +36,74 @@ export default new Vuex.Store({
musttry: "\uec96",
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",
},
mutations: {
addRecipe(state, recipe) {
state.recipes.push(recipe)
},
addCategory(state, category) {
let a = state.categories.filter((e) => e === category).length
if (a == 0) {
state.categories.push(category)
state.categories.sort()
}
},
overwriteRecipe(state, { index, recipe }) {
Object.assign(state.recipes[index], recipe)
},
deleteRecipe(state, index) {
state.recipes.splice(index, 1)
},
toggleFavorite(state, index) {
state.recipes[index].isFavorite = !state.recipes[index].isFavorite
},
toggleMustTry(state, index) {
state.recipes[index].tried = !state.recipes[index].tried
},
// addRecipe(state, recipe) {
// state.recipes.push(recipe)
// },
// addCategory(state, category) {
// let a = state.categories.filter((e) => e === category).length
// if (a == 0) {
// state.categories.push(category)
// state.categories.sort()
// }
// },
// overwriteRecipe(state, { index, recipe }) {
// Object.assign(state.recipes[index], recipe)
// },
// deleteRecipe(state, index) {
// state.recipes.splice(index, 1)
// },
// toggleFavorite(state, index) {
// state.recipes[index].isFavorite = !state.recipes[index].isFavorite
// },
// toggleMustTry(state, index) {
// state.recipes[index].tried = !state.recipes[index].tried
// },
setCurrentComponent(state, comp) {
state.currentComponent = comp
},
renameCategory(state, { current, updated }) {
let a = state.categories.filter((e) => e === updated).length
if (a == 0) {
// add updated category to categories
state.categories.splice(state.categories.indexOf(current), 1)
state.categories.push(updated)
state.categories.sort()
// rename all occurences
state.recipes.forEach((e, i) => {
if (e.category == current) {
state.recipes[i].category = updated
}
})
}
},
// renameCategory(state, { current, updated }) {
// let a = state.categories.filter((e) => e === updated).length
// if (a == 0) {
// // add updated category to categories
// state.categories.splice(state.categories.indexOf(current), 1)
// state.categories.push(updated)
// state.categories.sort()
// // rename all occurences
// state.recipes.forEach((e, i) => {
// if (e.category == current) {
// state.recipes[i].category = updated
// }
// })
// }
// },
},
actions: {
addRecipeAction({ commit }, recipe) {
commit("addRecipe", recipe)
},
addCategoryAction({ commit }, category) {
commit("addCategory", category)
},
overwriteRecipeAction({ commit }, updatedRecipe) {
commit("overwriteRecipe", updatedRecipe)
},
deleteRecipeAction({ commit }, index) {
commit("deleteRecipe", index)
},
toggleFavoriteAction({ commit }, index) {
commit("toggleFavorite", index)
},
toggleMustTryAction({ commit }, index) {
commit("toggleMustTry", index)
},
// addRecipeAction({ commit }, recipe) {
// commit("addRecipe", recipe)
// },
// addCategoryAction({ commit }, category) {
// commit("addCategory", category)
// },
// overwriteRecipeAction({ commit }, updatedRecipe) {
// commit("overwriteRecipe", updatedRecipe)
// },
// deleteRecipeAction({ commit }, index) {
// commit("deleteRecipe", index)
// },
// toggleFavoriteAction({ commit }, index) {
// commit("toggleFavorite", index)
// },
// toggleMustTryAction({ commit }, index) {
// commit("toggleMustTry", index)
// },
setCurrentComponentAction({ commit }, comp) {
commit("setCurrentComponent", comp)
},
renameCategoryAction({ commit }, category) {
commit("renameCategory", category)
},
// renameCategoryAction({ commit }, category) {
// commit("renameCategory", category)
// },
},
})

4499
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -11,6 +11,7 @@
"@nativescript/core": "~7.0.0",
"@nativescript/datetimepicker": "^2.0.4",
"@nativescript/theme": "^3.0.0",
"@nativescript/webpack": "3.0.0",
"@nstudio/nativescript-floatingactionbutton": "^3.0.3",
"nativescript-camera": "^4.5.0",
"nativescript-couchbase-plugin": "^0.9.6",
@ -20,6 +21,7 @@
"nativescript-ui-listview": "^9.0.4",
"nativescript-ui-sidedrawer": "^9.0.3",
"nativescript-vue": "^2.6.1",
"nativescript-zip": "^4.0.2",
"vuex": "^3.3.0"
},
"devDependencies": {
@ -28,7 +30,6 @@
"@nativescript/android": "7.0.1",
"@types/node": "^14.0.27",
"babel-loader": "^8.1.0",
"nativescript-dev-webpack": "^1.5.1",
"nativescript-vue-template-compiler": "^2.6.0",
"node-sass": "^4.13.1",
"vue-loader": "^15.9.1"