couchbase and vuex integrated

This commit is contained in:
Vishnu Raghav B 2020-10-27 02:19:54 +05:30
parent 1d7bca959e
commit 52446b3cd7
13 changed files with 437 additions and 371 deletions

View file

@ -15,7 +15,7 @@
android {
defaultConfig {
minSdkVersion 23
minSdkVersion 25
generatedDensities = []
ndk {
abiFilters.clear()

View file

@ -1,40 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="__PACKAGE__"
android:versionCode="10000"
android:versionName="1.0">
<supports-screens
android:smallScreens="true"
android:normalScreens="true"
android:largeScreens="true"
android:xlargeScreens="true"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:usesCleartextTraffic="true"
android:name="com.tns.NativeScriptApplication"
android:allowBackup="true"
android:icon="@drawable/icon"
android:label="@string/app_name"
android:theme="@style/AppTheme">
<activity
android:name="com.tns.NativeScriptActivity"
android:label="@string/title_activity_kimera"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout|locale|uiMode"
android:theme="@style/LaunchScreenTheme">
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="__PACKAGE__" android:versionCode="10000" android:versionName="1.0">
<supports-screens android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" android:xlargeScreens="true" />
<!-- <uses-permission android:name="android.permission.CAMERA" /> -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- <uses-permission android:name="android.permission.READ_USER_DICTIONARY" /> -->
<!-- <uses-permission android:name="android.permission.INTERNET"/> -->
<!-- <uses-feature android:name="android.hardware.camera" android:required="true" /> -->
<application android:usesCleartextTraffic="true" android:name="com.tns.NativeScriptApplication" android:allowBackup="true" android:icon="@drawable/icon" android:label="@string/app_name" android:theme="@style/AppTheme" android:requestLegacyExternalStorage="true">
<activity android:name="com.tns.NativeScriptActivity" android:label="@string/title_activity_kimera" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout|locale|uiMode" android:theme="@style/LaunchScreenTheme">
<meta-data android:name="SET_THEME_ON_LAUNCH" android:resource="@style/AppTheme" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.tns.ErrorReportActivity"/>
<activity android:name="com.tns.ErrorReportActivity" />
</application>
</manifest>

View file

@ -20,7 +20,7 @@
<!-- theme to use AFTER launch screen is loaded-->
<style name="AppThemeBase" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:forceDarkAllowed">true</item>
<item name="android:forceDarkAllowed">false</item>
<item name="toolbarStyle">@style/NativeScriptToolbarStyle</item>
<item name="colorPrimary">@color/ns_primary</item>

View file

@ -181,6 +181,10 @@ TabView {
background: $grayD4;
}
}
.ns-dark .date-time-picker-spinners {
color: $grayL4;
background: $grayD4;
}
// ActionBar
ActionBar {
width: 100%;

View file

@ -75,6 +75,14 @@
</StackLayout>
<StackLayout row="1">
<StackLayout class="hr m-10"></StackLayout>
<StackLayout
orientation="horizontal"
class="sd-item orkm"
@tap="donate"
>
<Label class="bx" :text="icon.donate" margin="0 24 0 0" />
<Label text="Donate" />
</StackLayout>
<StackLayout
@tap="navigateTo(item.component, true, false)"
v-for="(item, index) in bottommenu"
@ -88,14 +96,6 @@
<Label class="bx" :text="icon[item.icon]" margin="0 24 0 0" />
<Label :text="item.title" />
</StackLayout>
<StackLayout
orientation="horizontal"
class="sd-item orkm"
@tap="donate"
>
<Label class="bx" :text="icon.donate" margin="0 24 0 0" />
<Label text="Donate" />
</StackLayout>
</StackLayout>
</GridLayout>
@ -104,7 +104,6 @@
<!-- Home -->
<EnRecipes
ref="enrecipes"
:passedRecipes="recipes"
:filterFavorites="filterFavorites"
:filterMustTry="filterMustTry"
:selectedCategory="selectedCategory"
@ -134,10 +133,6 @@ import About from "./About.vue"
import PromptDialog from "./modal/PromptDialog.vue"
import { mapState, mapActions } from "vuex"
import { Couchbase } from "nativescript-couchbase-plugin"
const cb = new Couchbase("enrecipes")
const cbCat = new Couchbase("categories")
let page
export default {
components: {
@ -145,6 +140,7 @@ export default {
Settings,
About,
},
data() {
return {
selectedCategory: null,
@ -180,11 +176,10 @@ export default {
},
],
catEditMode: false,
recipes: null,
}
},
computed: {
...mapState(["icon", "currentComponent"]),
...mapState(["icon", "recipes", "currentComponent"]),
categories() {
let arr = this.recipes.map((e) => {
return e.category
@ -193,7 +188,12 @@ export default {
},
},
methods: {
...mapActions(["setCurrentComponentAction", "renameCategoryAction"]),
...mapActions([
"setCurrentComponentAction",
"initializeRecipes",
"initializeCategories",
"renameCategoryAction",
]),
toggleCatEdit() {
this.catEditMode = !this.catEditMode
this.setComponent("EnRecipes")
@ -204,37 +204,19 @@ export default {
setComponent(comp) {
this.setCurrentComponentAction(comp)
},
editCategory(item) {
editCategory(category) {
this.releaseGlobalBackEvent()
this.$showModal(PromptDialog, {
props: {
title: `Rename category`,
hint: item,
hint: category,
action: "RENAME",
},
}).then((result) => {
}).then((newCategory) => {
this.hijackGlobalBackEvent()
if (result.length) {
if (this.categories.includes(result)) {
Toast.makeText("Category already exists!", "long").show()
} else {
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
}
if (newCategory.length) {
this.renameCategoryAction({ current: category, updated: newCategory })
this.catEditMode = false
}
})
},
@ -308,8 +290,7 @@ export default {
backstackVisible: false,
})
this.closeDrawer()
this.catEditMode = false
} else if (!this.catEditMode) {
} else if (!this.catEditMode || !isCategory) {
this.releaseGlobalBackEvent()
this.hijackGlobalBackEvent()
this.setComponent(to)
@ -320,6 +301,7 @@ export default {
this.$refs.enrecipes.updateFilter()
this.closeDrawer()
}
this.catEditMode = false
},
restartApp() {
// Code from nativescript-master-technology
@ -358,10 +340,8 @@ 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: [] })
})
if (!this.recipes.length) this.initializeRecipes()
if (!this.categories.length) this.initializeCategories()
},
}
</script>

View file

@ -1,5 +1,5 @@
<template>
<Page @loaded="initializePage" @unloaded="releaseBackEvent">
<Page @unloaded="releaseBackEvent">
<ActionBar :flat="viewIsScrolled ? false : true">
<GridLayout rows="*" columns="auto, *, auto," class="actionBarContainer">
<Label
@ -62,13 +62,22 @@
:text="icon.close"
androidElevation="8"
/>
<Label
v-else
@tap="takePicture"
class="bx fab-button"
:text="icon.camera"
androidElevation="8"
/>
<GridLayout v-else rows="auto" columns="*, auto, auto, *">
<Label
col="1"
@tap="takePicture"
class="bx fab-button"
:text="icon.camera"
androidElevation="8"
/>
<Label
col="2"
@tap="selectPicture"
class="bx fab-button"
:text="icon.image"
androidElevation="8"
/>
</GridLayout>
</StackLayout>
</AbsoluteLayout>
@ -268,7 +277,8 @@ import {
getFileAccess,
knownFolders,
} from "@nativescript/core"
import { Mediafilepicker } from "nativescript-mediafilepicker"
import * as imagepicker from "nativescript-imagepicker"
import * as camera from "@nativescript/camera"
import { mapState, mapActions } from "vuex"
@ -276,13 +286,8 @@ 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: ["recipeID", "selectedCategory"],
props: ["recipeIndex", "recipeID", "selectedCategory"],
data() {
return {
title: "New recipe",
@ -308,63 +313,33 @@ export default {
tried: false,
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",
],
tempRecipeContent: {
imageSrc: null,
title: null,
category: null,
prepTime: "00:00",
cookTime: "00:00",
portionSize: 1,
ingredients: [
{
item: "",
quantity: null,
unit: "unit",
},
],
instructions: [""],
notes: [""],
references: [""],
isFavorite: false,
tried: false,
lastModified: null,
},
blockModal: false,
cbCat: [],
newRecipeID: null,
}
},
computed: {
...mapState(["icon", "currentComponent"]),
...mapState(["icon", "units", "recipes", "categories", "currentComponent"]),
screenWidth() {
return Screen.mainScreen.widthDIPs
},
@ -380,31 +355,12 @@ export default {
},
},
methods: {
...mapActions(["setCurrentComponentAction"]),
initializePage() {
setTimeout((e) => {
this.setCurrentComponentAction("EditRecipe")
}, 500)
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")
}
},
...mapActions([
"setCurrentComponentAction",
"addRecipeAction",
"overwriteRecipeAction",
"addCategoryAction",
]),
getRandomID() {
let res = ""
let chars = "abcdefghijklmnopqrstuvwxyz0123456789"
@ -451,10 +407,20 @@ export default {
this.clearEmptyFields()
this.recipeContent.lastModified = new Date()
if (this.recipeID) {
cb.updateDocument(this.recipeID, this.recipeContent)
this.overwriteRecipeAction({
index: this.recipeIndex,
id: this.recipeID,
recipe: this.recipeContent,
})
} else {
this.recipeContent.id = this.newRecipeID
cb.createDocument(this.recipeContent, this.newRecipeID)
this.addRecipeAction({
id: this.newRecipeID,
recipe: this.recipeContent,
})
}
if (this.tempRecipeContent.imageSrc && !this.recipeContent.imageSrc) {
getFileAccess().deleteFile(this.tempRecipeContent.imageSrc)
}
this.$navigateBack()
},
@ -485,15 +451,11 @@ export default {
title: "New category",
action: "ADD",
},
}).then((result) => {
}).then((category) => {
this.hijackBackEvent()
if (result.length) {
this.recipeContent.category = result
this.categories.push(result)
this.categories.sort()
cbCat.updateDocument("categories", {
categories: [...this.categories],
})
if (category.length) {
this.recipeContent.category = category
this.addCategoryAction(category)
}
})
} else if (action) {
@ -546,56 +508,58 @@ export default {
}
},
takePicture() {
let mediafilepicker = new Mediafilepicker()
let vm = this
const options = {
width: this.screenWidth,
height: this.screenWidth,
lockSquare: true,
}
const androidOptions = {
isFreeStyleCropEnabled: true,
statusBarColor: "black",
setAspectRatioOptions: {
defaultIndex: 0,
aspectRatios: [
{
aspectRatioTitle: "1:1",
aspectRatioX: 1,
aspectRatioY: 1,
},
{
aspectRatioTitle: "16:9",
aspectRatioX: 16,
aspectRatioY: 9,
},
{
aspectRatioTitle: "18:9",
aspectRatioX: 18,
aspectRatioY: 9,
},
],
},
}
mediafilepicker.openImagePicker({
android: {
isCaptureMood: false, // if true then camera will open directly.
isNeedCamera: true,
maxNumberFiles: 1,
isNeedFolderList: false,
const vm = this
camera.requestPermissions().then(
() => {
camera
.takePicture({
width: vm.screenWidth,
height: vm.screenWidth,
keepAspectRatio: false,
saveToGallery: false,
})
.then((imageAsset) => {
let result = imageAsset._android
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
})
})
.catch((err) => {
console.log("Error -> " + err.message)
})
},
() => {
console.log("permission request rejected")
}
)
},
selectPicture() {
let context = imagepicker.create({
mode: "single",
mediaType: "Image",
})
mediafilepicker.on("getFiles", function(res) {
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
context
.authorize()
.then(() => context.present())
.then((selection) => {
let result = selection[0]._android
ImageSource.fromFile(result).then((savedImg) => {
let savedImgPath = path.join(
knownFolders.documents().getFolder("enrecipes").path,
`${this.getRandomID()}.jpg`
)
savedImg.saveToFile(savedImgPath, "jpg")
this.recipeContent.imageSrc = savedImgPath
})
})
.catch(function(e) {
console.log(e)
})
})
},
removePicture() {
confirm({
@ -605,7 +569,6 @@ export default {
cancelButtonText: "Cancel",
}).then((e) => {
if (e) {
getFileAccess().deleteFile(this.recipeContent.imageSrc)
this.recipeContent.imageSrc = null
}
})
@ -657,5 +620,21 @@ export default {
})
},
},
created() {
setTimeout((e) => {
this.setCurrentComponentAction("EditRecipe")
}, 500)
this.title = this.recipeID ? "Edit recipe" : "New recipe"
if (this.recipeID) {
let recipe = this.recipes.filter((e) => e.id === this.recipeID)[0]
Object.assign(this.recipeContent, recipe)
Object.assign(this.tempRecipeContent, recipe)
} else {
if (this.selectedCategory)
this.recipeContent.category = this.selectedCategory
this.newRecipeID = this.getRandomID()
}
this.hijackBackEvent()
},
}
</script>

View file

@ -40,14 +40,14 @@
/>
<Label class="title orkm" :text="currentComponent" col="1" />
<Label
v-if="passedRecipes.length"
v-if="recipes.length"
class="bx"
:text="icon.search"
col="2"
@tap="openSearch"
/>
<Label
v-if="passedRecipes.length"
v-if="recipes.length"
class="bx"
:text="icon.sort"
col="3"
@ -59,7 +59,7 @@
<RadListView
ref="listView"
itemHeight="112"
for="recipe in passedRecipes"
for="recipe in recipes"
swipeActions="true"
@itemSwipeProgressChanged="onSwiping"
@itemSwipeProgressEnded="onSwipeEnded"
@ -115,7 +115,7 @@
</v-template>
</RadListView>
<Label
v-if="!passedRecipes.length && !filterFavorites && !filterMustTry"
v-if="!recipes.length && !filterFavorites && !filterMustTry"
class="noResults"
text='Click the "+" icon to add a new recipe.'
textWrap="true"
@ -156,7 +156,6 @@
<script>
import { Utils, AndroidApplication } from "@nativescript/core"
import * as Toast from "nativescript-toast"
import EditRecipe from "./EditRecipe.vue"
import ViewRecipe from "./ViewRecipe.vue"
@ -164,12 +163,8 @@ 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",
@ -192,25 +187,25 @@ export default {
}
},
computed: {
...mapState(["icon", "currentComponent"]),
...mapState(["icon", "recipes", "currentComponent"]),
filteredRecipes() {
if (this.filterFavorites) {
return this.passedRecipes.filter(
return this.recipes.filter(
(e) =>
e.isFavorite && e.title.toLowerCase().includes(this.searchQuery)
)
} else if (this.filterMustTry) {
return this.passedRecipes.filter(
return this.recipes.filter(
(e) => !e.tried && e.title.toLowerCase().includes(this.searchQuery)
)
} else if (this.selectedCategory) {
return this.passedRecipes.filter(
return this.recipes.filter(
(e) =>
e.category === this.selectedCategory &&
e.title.toLowerCase().includes(this.searchQuery)
)
} else {
return this.passedRecipes.filter((e) =>
return this.recipes.filter((e) =>
e.title.toLowerCase().includes(this.searchQuery)
)
}
@ -343,7 +338,7 @@ export default {
}
},
onSwipeEnded({ index }) {
let recipeID = this.passedRecipes[index].id
let recipeID = this.recipes[index].id
if (this.rightAction && !this.deletionDialogActive)
this.deleteRecipe(index, recipeID)
this.rightAction = false
@ -353,13 +348,13 @@ export default {
this.$showModal(ConfirmDialog, {
props: {
title: "Delete recipe",
description: `Are you sure you want to delete the recipe "${this.passedRecipes[index].title}"?`,
description: `Are you sure you want to delete the recipe "${this.recipes[index].title}"?`,
cancelButtonText: "CANCEL",
okButtonText: "DELETE",
},
}).then((action) => {
if (action) {
cb.deleteDocument(recipeID)
this.deleteRecipeAction({ index, id: recipeID })
}
this.deletionDialogActive = false
})
@ -405,7 +400,7 @@ export default {
},
})
},
viewRecipe({ item }) {
viewRecipe({ item, index }) {
this.$navigateTo(ViewRecipe, {
transition: {
name: "fade",
@ -413,6 +408,7 @@ export default {
curve: "easeIn",
},
props: {
recipeIndex: index,
recipeID: item.id,
hijackGlobalBackEvent: this.hijackGlobalBackEvent,
releaseGlobalBackEvent: this.releaseGlobalBackEvent,

View file

@ -67,6 +67,9 @@ import {
} from "@nativescript/core"
import * as permissions from "nativescript-permissions"
import { Zip } from "nativescript-zip"
import * as Toast from "nativescript-toast"
import * as filepicker from "nativescript-plugin-filepicker"
import Theme from "@nativescript/theme"
import ActionDialog from "./modal/ActionDialog.vue"
@ -174,14 +177,22 @@ export default {
const sdDownloadPath = android.os.Environment.getExternalStoragePublicDirectory(
android.os.Environment.DIRECTORY_DOWNLOADS
).toString()
let date = new Date()
let fromPath = path.join(knownFolders.documents().path, "enrecipes")
let destPath = path.join(sdDownloadPath, "enrecipes.zip")
let destPath = path.join(
sdDownloadPath,
`enrecipes_${date.toString()}.zip`
)
console.log(fromPath, destPath, sdDownloadPath)
Zip.zip({
directory: fromPath,
archive: destPath,
})
.then((success) => {
Toast.makeText(
"Backup file successfully saved to Downloads",
"long"
).show()
console.log("success:" + success)
})
.catch((err) => {
@ -197,13 +208,22 @@ export default {
restoreData(args) {
let btn = args.object
this.highlight(args)
permissions
.requestPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
.then(() => {
alert("Restore successful!")
let vm = this
let context = filepicker.create({
mode: "single", // use "multiple" for multiple selection
extensions: ["zip"],
})
context
.authorize()
.then(function() {
return context.present()
})
.catch(() => {
console.log("Uh oh, no permissions - plan B time!")
.then(function(selection) {
let result = selection
console.log(result)
})
.catch(function(e) {
console.log(e)
})
},
},

View file

@ -27,7 +27,13 @@
verticalAlignment="bottom"
/>
</ScrollView>
<Label row="0" col="2" class="bx" :text="icon.share" @tap="" />
<Label
row="0"
col="2"
class="bx"
:text="icon.share"
@tap="shareRecipe"
/>
<Label
row="0"
col="3"
@ -260,18 +266,21 @@
</template>
<script>
import { Screen, Utils } from "@nativescript/core"
import { Screen, Utils, ImageSource, Device } from "@nativescript/core"
import * as Toast from "nativescript-toast"
import * as SocialShare from "nativescript-social-share"
import { mapState, mapActions } from "vuex"
import EditRecipe from "./EditRecipe.vue"
import { Couchbase } from "nativescript-couchbase-plugin"
const cb = new Couchbase("enrecipes")
export default {
props: ["recipeID", "hijackGlobalBackEvent", "releaseGlobalBackEvent"],
props: [
"recipeIndex",
"recipeID",
"hijackGlobalBackEvent",
"releaseGlobalBackEvent",
],
data() {
return {
busy: false,
@ -280,7 +289,7 @@ export default {
}
},
computed: {
...mapState(["icon"]),
...mapState(["icon", "recipes"]),
screenWidth() {
return Screen.mainScreen.widthDIPs
},
@ -291,17 +300,23 @@ export default {
},
},
methods: {
...mapActions(["toggleMustTryAction", "setCurrentComponentAction"]),
...mapActions(["toggleStateAction", "setCurrentComponentAction"]),
initializePage() {
this.recipe = cb.getDocument(this.recipeID)
this.releaseGlobalBackEvent()
this.busy = false
setTimeout((e) => {
this.setCurrentComponentAction("ViewRecipe")
}, 500)
this.portionScale = this.recipe.portionSize
},
roundedQuantity(quantity, unit) {
return Math.round(quantity * this.isPortionScalePositive * 100) / 100
roundedQuantity(quantity) {
return (
Math.round(
(quantity / this.recipe.portionSize) *
this.isPortionScalePositive *
100
) / 100
)
},
editRecipe() {
this.busy = true
@ -312,15 +327,28 @@ 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)
this.toggleStateAction({
index: this.recipeIndex,
id: this.recipeID,
recipe: this.recipe,
key,
})
},
shareRecipe() {
// if (this.recipe.imageSrc) {
// let image = ImageSource.fromFile(this.recipe.imageSrc)
// SocialShare.shareImage(image)
// } else {
// SocialShare.shareText("Text only")
// }
alert(Device.sdkVersion)
},
toggleFavorite() {
this.recipe.isFavorite
@ -345,7 +373,7 @@ export default {
},
},
created() {
this.recipe = cb.getDocument(this.recipeID)
this.recipe = this.recipes.filter((e) => e.id === this.recipeID)[0]
},
}
</script>

View file

@ -13,10 +13,10 @@ Vue.registerElement(
() => require("nativescript-ui-sidedrawer").RadSideDrawer
)
Vue.registerElement(
"Fab",
() => require("@nstudio/nativescript-floatingactionbutton").Fab
)
// Vue.registerElement(
// "Fab",
// () => require("@nstudio/nativescript-floatingactionbutton").Fab
// )
if (TNS_ENV !== "production") {
// Vue.use(VueDevtools)

View file

@ -1,11 +1,37 @@
import Vue from "vue"
import Vuex from "vuex"
import { Couchbase } from "nativescript-couchbase-plugin"
const recipesDB = new Couchbase("enrecipes")
const categoriesDB = new Couchbase("categories")
Vue.use(Vuex)
export default new Vuex.Store({
state: {
// recipes: [],
recipes: [],
categories: [],
units: [
"unit",
"tsp",
"Tbsp",
"oz",
"cup",
"pt",
"qt",
"lb",
"gal",
"ml",
"L",
"mg",
"g",
"kg",
"mm",
"cm",
"m",
"in",
"°C",
"°F",
],
icon: {
home: "\ued99",
heart: "\ued94",
@ -39,71 +65,133 @@ export default new Vuex.Store({
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
// },
initializeRecipes(state) {
let a = recipesDB.query({ select: [] })
a.forEach((e) => {
state.recipes.push(e)
})
},
initializeCategories(state) {
let isCategoriesStored = categoriesDB.query({ select: [] }).length
let cats
if (isCategoriesStored) {
cats = categoriesDB.getDocument("categories").categories
} else {
categoriesDB.createDocument(
{
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",
],
},
"categories"
)
cats = categoriesDB.getDocument("categories").categories
}
cats.forEach((e) => state.categories.push(e))
},
addRecipe(state, { id, recipe }) {
state.recipes.push(recipe)
recipesDB.createDocument(recipe, id)
},
addCategory(state, category) {
let a = state.categories.filter((e) => e === category).length
if (a == 0) {
state.categories.push(category)
state.categories.sort()
categoriesDB.updateDocument("categories", {
categories: [...state.categories],
})
}
},
overwriteRecipe(state, { index, id, recipe }) {
Object.assign(state.recipes[index], recipe)
recipesDB.updateDocument(id, recipe)
},
deleteRecipe(state, { index, id }) {
state.recipes.splice(index, 1)
recipesDB.deleteDocument(id)
},
toggleState(state, { index, id, recipe, key }) {
state.recipes[index][key] = !state.recipes[index][key]
recipesDB.updateDocument(id, recipe)
},
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 exists = state.categories.filter((e) => e === updated).length
state.categories.splice(state.categories.indexOf(current), 1)
// update recipes with updated category
if (!exists) {
state.categories.push(updated)
state.categories.sort()
categoriesDB.updateDocument("categories", {
categories: [...state.categories],
})
}
state.recipes.forEach((e, i) => {
if (e.category == current) {
state.recipes[i].category = updated
recipesDB.inBatch(() => {
recipesDB.updateDocument(state.recipes[i].id, state.recipes[i])
})
}
})
},
},
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)
// },
initializeRecipes({ commit }) {
commit("initializeRecipes")
},
initializeCategories({ commit }) {
commit("initializeCategories")
},
addRecipeAction({ commit }, recipe) {
commit("addRecipe", recipe)
},
addCategoryAction({ commit }, category) {
commit("addCategory", category)
},
overwriteRecipeAction({ commit }, updatedRecipe) {
commit("overwriteRecipe", updatedRecipe)
},
deleteRecipeAction({ commit }, recipe) {
commit("deleteRecipe", recipe)
},
toggleStateAction({ commit }, toggledRecipe) {
commit("toggleState", toggledRecipe)
},
setCurrentComponentAction({ commit }, comp) {
commit("setCurrentComponent", comp)
},
// renameCategoryAction({ commit }, category) {
// commit("renameCategory", category)
// },
renameCategoryAction({ commit }, category) {
commit("renameCategory", category)
},
},
})

62
package-lock.json generated
View file

@ -1095,17 +1095,20 @@
"to-fast-properties": "^2.0.0"
}
},
"@nativescript-community/perms": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/@nativescript-community/perms/-/perms-2.1.1.tgz",
"integrity": "sha512-Ay4v1lEGTQ5rYYlYA8CKcCXuxOuyU4633r/JXi9aRG8MgxfOT+rDuQLgSz+LLCYmBK1ndfHHfyUTilkaUj1H8Q=="
},
"@nativescript/android": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/@nativescript/android/-/android-7.0.1.tgz",
"integrity": "sha512-VsZCJ5zfZo0+/lFwKz+S7iFb7MA2jgACB7y8dNje3/cnZl+moKPNjFqitoEP0DY4gLz9LJNbFIIaUt84tMdUSQ==",
"dev": true
},
"@nativescript/camera": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/@nativescript/camera/-/camera-5.0.2.tgz",
"integrity": "sha512-frNeCLhdQ+W6oXIv05pALdmZDcwilw/NopLtQILtUwuLS7xhE+UMx6CqQxxCxMYzWKsvET2k9VLAo3mJGAoSeg==",
"requires": {
"nativescript-permissions": "~1.3.0"
}
},
"@nativescript/core": {
"version": "7.0.12",
"resolved": "https://registry.npmjs.org/@nativescript/core/-/core-7.0.12.tgz",
@ -1203,11 +1206,6 @@
"mkdirp": "^1.0.4"
}
},
"@nstudio/nativescript-floatingactionbutton": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@nstudio/nativescript-floatingactionbutton/-/nativescript-floatingactionbutton-3.0.3.tgz",
"integrity": "sha512-xA7a/CKQ+kkuFLfgqFClEu+Hl2stMo5BS0qnpYW0gt//MHPNJf/OLlWQ5r5g2rAtw/AKZJGnCewMx2SfWaengQ=="
},
"@types/anymatch": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/@types/anymatch/-/anymatch-1.3.1.tgz",
@ -5098,26 +5096,17 @@
"to-regex": "^3.0.1"
}
},
"nativescript-camera": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/nativescript-camera/-/nativescript-camera-4.5.0.tgz",
"integrity": "sha512-Ecw9JH0CNgnGKXfqD1oifMoIOSnKBgWkecwVpdKfrChkQaCdKDFWdfdJ6X8+YTSwJH4n43e74JmrPzLN2eitwQ==",
"requires": {
"nativescript-permissions": "~1.3.0"
}
},
"nativescript-couchbase-plugin": {
"version": "0.9.6",
"resolved": "https://registry.npmjs.org/nativescript-couchbase-plugin/-/nativescript-couchbase-plugin-0.9.6.tgz",
"integrity": "sha512-kMA9KHQX82TFaGnGUhY94KLOLss4pb5QmghgoEdu1sLwd94I/f1MQ+kHWbuBOdFmdQJw5oCK+Sey+A22Nd5jgA=="
},
"nativescript-mediafilepicker": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/nativescript-mediafilepicker/-/nativescript-mediafilepicker-4.0.1.tgz",
"integrity": "sha512-rBrZQR+46dCypIyLrzIlzmHgpmTSMGFR5a6snq8uUhtIqLlc674/nwWlNM1kFOxMh1kKxA+qyk74Of+NCKYoqQ==",
"nativescript-imagepicker": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/nativescript-imagepicker/-/nativescript-imagepicker-7.1.0.tgz",
"integrity": "sha512-YFVwmPz7mv7mNXA7vmnIXmqPZiWxH4RoJPDL3m34egV8Ae9mKJCXZxl2LyPraOP+T4v6iXsxV9NSbjg0kMDuNQ==",
"requires": {
"@nativescript-community/perms": "^2.1.1",
"ts-node": "^9.0.0"
"nativescript-permissions": "~1.3.0"
}
},
"nativescript-permissions": {
@ -5125,6 +5114,19 @@
"resolved": "https://registry.npmjs.org/nativescript-permissions/-/nativescript-permissions-1.3.11.tgz",
"integrity": "sha512-4ox9WpVJPLfepPauqECvPfbxVE1hVPVVBLZxOs3d9+2Yrr0mSkJO7D7BQ4OUS90hHfRdPhf70aJKWxzJoqi63g=="
},
"nativescript-plugin-filepicker": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/nativescript-plugin-filepicker/-/nativescript-plugin-filepicker-1.0.0.tgz",
"integrity": "sha512-BOf7ycOQJGcg7ayzfbyFooMjngQgBAg6HAaws4fKQBRnI39aw7VVqXruuHSCDPqLW681/7GuECwWxknmAalOnQ==",
"requires": {
"nativescript-permissions": "~1.3.0"
}
},
"nativescript-social-share": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/nativescript-social-share/-/nativescript-social-share-1.6.0.tgz",
"integrity": "sha512-PjSMseCWPGJbW0KPMgQBiTQke6I8cYxf0CGXtuJ0BnRhXrEjF3d+3kAnI8E3O8PeW/BFwNIqLYG4fkoQF4obyA=="
},
"nativescript-toast": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/nativescript-toast/-/nativescript-toast-2.0.0.tgz",
@ -7354,18 +7356,6 @@
}
}
},
"ts-node": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.0.0.tgz",
"integrity": "sha512-/TqB4SnererCDR/vb4S/QvSZvzQMJN8daAslg7MeaiHvD8rDZsSfXmNeNumyZZzMned72Xoq/isQljYSt8Ynfg==",
"requires": {
"arg": "^4.1.0",
"diff": "^4.0.1",
"make-error": "^1.1.1",
"source-map-support": "^0.5.17",
"yn": "3.1.1"
}
},
"tslib": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz",

View file

@ -8,15 +8,16 @@
"run": "ns run android"
},
"dependencies": {
"@nativescript/camera": "^5.0.2",
"@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",
"nativescript-mediafilepicker": "^4.0.0",
"nativescript-imagepicker": "^7.1.0",
"nativescript-permissions": "^1.3.9",
"nativescript-plugin-filepicker": "^1.0.0",
"nativescript-social-share": "^1.6.0",
"nativescript-toast": "^2.0.0",
"nativescript-ui-listview": "^9.0.4",
"nativescript-ui-sidedrawer": "^9.0.3",