before ns migrate

This commit is contained in:
Vishnu Raghav B 2020-10-21 23:24:45 +05:30
parent eb9e2da756
commit ce53ddb126
40 changed files with 1437 additions and 1613 deletions

View file

@ -11,7 +11,7 @@
android { android {
defaultConfig { defaultConfig {
minSdkVersion 17 minSdkVersion 23
generatedDensities = [] generatedDensities = []
} }
aaptOptions { aaptOptions {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 550 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 461 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 664 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 472 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 780 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

View file

@ -1,10 +1,11 @@
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" android:gravity="fill"> <layer-list xmlns:android="http://schemas.android.com/apk/res/android" android:gravity="fill">
<item> <item>
<shape android:shape="rectangle"> <shape android:shape="rectangle">
<solid android:color="@android:color/white" /> <!-- <solid android:color="@android:color/white" /> -->
<solid android:color="#ff7043" />
</shape> </shape>
</item> </item>
<item> <item android:left="64dp" android:right="64dp">
<bitmap android:gravity="center" android:src="@drawable/logo" /> <bitmap android:gravity="center" android:src="@drawable/logo" />
</item> </item>
</layer-list> </layer-list>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 680 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 861 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4 KiB

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View file

@ -1,4 +1,12 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<color name="ns_accent">#ff7043</color> <color name="ns_primary">
#FFFFFF
</color>
<color name="ns_primaryDark">
#ff7043
</color>
<color name="ns_accent">
#ff7043
</color>
</resources> </resources>

View file

@ -1,23 +1,29 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<!-- Application theme --> <!-- Application theme -->
<style name="AppTheme" parent="AppThemeBase"> <style name="AppTheme" parent="AppThemeBase">
<item name="android:datePickerStyle">@style/SpinnerDatePicker</item> <item name="android:datePickerStyle">
<item name="android:timePickerStyle">@style/SpinnerTimePicker</item> @style/SpinnerDatePicker
</item>
<item name="android:timePickerStyle">
@style/SpinnerTimePicker
</item>
</style> </style>
<!-- Default style for DatePicker - in spinner mode --> <!-- Default style for DatePicker - in spinner mode -->
<style name="SpinnerDatePicker" parent="android:Widget.Material.Light.DatePicker"> <style name="SpinnerDatePicker" parent="android:Widget.Material.Light.DatePicker">
<item name="android:datePickerMode">spinner</item> <item name="android:datePickerMode">
spinner
</item>
</style> </style>
<!-- Default style for TimePicker - in spinner mode --> <!-- Default style for TimePicker - in spinner mode -->
<style name="SpinnerTimePicker" parent="android:Widget.Material.Light.TimePicker"> <style name="SpinnerTimePicker" parent="android:Widget.Material.Light.TimePicker">
<item name="android:timePickerMode">spinner</item> <item name="android:timePickerMode">
spinner
</item>
</style> </style>
<style name="NativeScriptToolbarStyle" parent="NativeScriptToolbarStyleBase"> <style name="NativeScriptToolbarStyle" parent="NativeScriptToolbarStyleBase">
<item name="android:elevation">4dp</item> <item name="android:elevation">
0dp
</item>
</style> </style>
</resources> </resources>

View file

@ -9,7 +9,4 @@
<color name="ns_accent"> <color name="ns_accent">
#ff7043 #ff7043
</color> </color>
<color name="ns_blue">
#272734
</color>
</resources> </resources>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="app_name">NativeScript-Vue Application</string> <string name="app_name">EnRecipes</string>
<string name="title_activity_kimera">NativeScript-Vue Application</string> <string name="title_activity_kimera">EnRecipes</string>
</resources> </resources>

View file

@ -12,7 +12,7 @@
<item name="android:windowBackground">@drawable/splash_screen</item> <item name="android:windowBackground">@drawable/splash_screen</item>
<item name="android:windowActionBarOverlay">true</item> <item name="android:windowActionBarOverlay">true</item>
<item name="android:windowTranslucentStatus">true</item> <item name="android:windowTranslucentStatus">false</item>
</style> </style>
<style name="LaunchScreenTheme" parent="LaunchScreenThemeBase"> <style name="LaunchScreenTheme" parent="LaunchScreenThemeBase">

View file

@ -37,7 +37,8 @@ Page {
.ns-light { .ns-light {
Page, Page,
ActionBar, ActionBar,
SearchBar { SearchBar,
TabView {
background: $grayL4; background: $grayL4;
color: $grayD4; color: $grayD4;
} }
@ -58,8 +59,10 @@ Page {
.fieldLabel { .fieldLabel {
background: $grayL4; background: $grayL4;
} }
.recipe-li,
.option-highlight { .option-highlight {
background: $grayL2;
}
.recipe-li {
background: white; background: white;
} }
.sd-item, .sd-item,
@ -102,7 +105,8 @@ Page {
.ns-dark { .ns-dark {
Page, Page,
ActionBar, ActionBar,
SearchBar { SearchBar,
TabView {
background: $grayD4; background: $grayD4;
color: $grayL4; color: $grayL4;
} }
@ -169,9 +173,10 @@ Page {
TextField, TextField,
TextView, TextView,
TimePickerField { TimePickerField {
width: 100%;
border-width: 1; border-width: 1;
font-size: 15; font-size: 14;
padding: 16; padding: 14;
margin: 8 0 0 0; margin: 8 0 0 0;
border-radius: 4; border-radius: 4;
placeholder-color: $gray; placeholder-color: $gray;
@ -195,7 +200,8 @@ ActionBar {
padding: 0; padding: 0;
height: 64; height: 64;
.bx { .bx {
padding: 16; padding: 16 12;
vertical-alignment: center;
} }
.leftAction { .leftAction {
padding: 16 16 16 4; padding: 16 16 16 4;
@ -207,8 +213,8 @@ ActionBar {
padding: 0; padding: 0;
} }
SearchBar { SearchBar {
width: 100%;
font-size: 16; font-size: 16;
margin-top: 4;
} }
.title { .title {
padding-left: 8; padding-left: 8;
@ -219,15 +225,25 @@ SearchBar {
// Side Drawer // Side Drawer
.sd-item { .sd-item {
border-radius: 4; border-radius: 4;
padding: 12 16; padding: 0 16;
font-size: 14; height: 48;
font-size: 16;
vertical-alignment: center;
// prettier-ignore
.bx, Label {
vertical-alignment: center;
}
} }
.sd-group-header { .sd-group-header {
padding: 12; width: 100%;
padding: 8 8 16;
font-size: 12; font-size: 12;
} }
// Home // Home
RadListView {
margin-bottom: 128;
}
.recipe-li { .recipe-li {
margin: 8 16; margin: 8 16;
border-radius: 6; border-radius: 6;
@ -235,6 +251,7 @@ SearchBar {
margin: 4 0; margin: 4 0;
} }
.recipe-cat { .recipe-cat {
font-size: 12;
padding: 0; padding: 0;
margin: 0; margin: 0;
} }
@ -248,21 +265,18 @@ SearchBar {
padding: 0; padding: 0;
} }
.recipe-favorite { .recipe-favorite {
font-size: 14; font-size: 12;
padding: 14 12 0 0; padding: 14 8 0 0;
} }
.recipe-cat, .recipe-cat,
.recipe-favorite { .recipe-favorite {
color: $orange; color: $orange;
} }
.recipe-favorite.hide {
opacity: 0;
}
} }
// Settings // Settings
.group-header { .group-header {
padding: 12; padding: 8;
color: #ff7043; color: #ff7043;
} }
.main-container { .main-container {
@ -317,22 +331,27 @@ SearchBar {
} }
.view-title { .view-title {
font-size: 22; font-size: 22;
line-height: 6;
margin-bottom: 16;
} }
.view-ingredient { .view-ingredient {
font-size: 14; font-size: 14;
line-height: 6; line-height: 6;
margin-top: 12; padding-bottom: 16;
} }
.view-favorited { .view-favorited {
color: #ff7043; color: #ff7043;
} }
.activity-indicator {
background: #ff7043;
}
.view-count { .view-count {
font-size: 10; font-size: 10;
width: 20; width: 20;
height: 20; height: 20;
padding: 3 0 0; padding-top: 3%;
margin-left: 6; margin: 0 0 0 6;
text-align: center; text-align: center;
border-radius: 100; border-radius: 100;
} }
@ -342,7 +361,7 @@ SearchBar {
.view-reference { .view-reference {
font-size: 14; font-size: 14;
line-height: 6; line-height: 6;
padding: 0 0 12 24; padding: 0 0 16 24;
margin: 0 0 0 15; margin: 0 0 0 15;
border-width: 0 0 0 2; border-width: 0 0 0 2;
} }
@ -368,3 +387,7 @@ SearchBar {
padding: 16; padding: 16;
margin: 8 0 0 0; margin: 8 0 0 0;
} }
.closeBtn {
padding: 4;
margin-top: 16;
}

View file

@ -1,5 +1,5 @@
<template> <template>
<Page> <Page @loaded="setCurrentComponent">
<ActionBar :flat="viewIsScrolled ? false : true"> <ActionBar :flat="viewIsScrolled ? false : true">
<!-- Settings Actionbar --> <!-- Settings Actionbar -->
<GridLayout rows="*" columns="auto, *" class="actionBarContainer"> <GridLayout rows="*" columns="auto, *" class="actionBarContainer">
@ -10,7 +10,7 @@
@tap="showDrawer" @tap="showDrawer"
col="0" col="0"
/> />
<Label class="title orkm" :text="title" col="1" /> <Label class="title orkm" text="About" col="1" />
</GridLayout> </GridLayout>
</ActionBar> </ActionBar>
<ScrollView scrollBarIndicatorVisible="false"> <ScrollView scrollBarIndicatorVisible="false">
@ -85,9 +85,12 @@ import { mapState, mapActions } from "vuex"
export default { export default {
props: ["highlight", "viewIsScrolled", "showDrawer", "title"], props: ["highlight", "viewIsScrolled", "showDrawer", "title"],
computed: { computed: {
...mapState(["icon"]), ...mapState(["icon",'currentComponent']),
}, },
methods: { methods: {
setCurrentComponent() {
this.$store.dispatch("setCurrentComponent", "About")
},
openURL(args, url) { openURL(args, url) {
this.highlight(args) this.highlight(args)
utils.openUrl(url) utils.openUrl(url)

View file

@ -6,10 +6,10 @@
drawerContentSize="270" drawerContentSize="270"
showOverNavigation="true" showOverNavigation="true"
gesturesEnabled="true" gesturesEnabled="true"
drawerTransition="RevealTransition" drawerTransition="SlideInOnTopTransition"
> >
<GridLayout <GridLayout
rows="auto, auto, *, auto, auto" rows="*, auto"
columns="*" columns="*"
~drawerContent ~drawerContent
padding="8" padding="8"
@ -17,62 +17,65 @@
> >
<StackLayout row="0"> <StackLayout row="0">
<StackLayout <StackLayout
@tap="localNavigation('EnRecipes', 'EnRecipes', true, false)" v-for="(item, index) in topmenu"
:key="index"
@tap="navigateTo(item.component, false, false)"
orientation="horizontal" orientation="horizontal"
class="sd-item orkm" class="sd-item orkm"
:class="{ :class="{
'selected-sd-item': 'selected-sd-item': currentComponent === item.component,
currentComponent === 'EnRecipes' &&
!filterFavorites &&
!selectedCategory,
}" }"
> >
<Label class="bx" :text="icon.home" margin="0 24 0 0" /> <Label class="bx" :text="icon[item.icon]" margin="0 24 0 0" />
<Label verticalAlignment="center" text="Home" /> <Label :text="item.title" />
</StackLayout> </StackLayout>
<StackLayout <StackLayout class="hr m-10"></StackLayout>
@tap="localNavigation('Favorites', 'Favorites', true, false)" <GridLayout
orientation="horizontal" class="sd-group-header orkm"
class="sd-item orkm" rows="auto"
:class="{ columns="*, auto"
'selected-sd-item':
currentComponent === 'EnRecipes' && filterFavorites,
}"
> >
<Label class="bx" :text="icon.heart" margin="0 24 0 0" /> <Label col="0" text="Categories" />
<Label verticalAlignment="center" text="Favorites" /> <Label
</StackLayout> @tap="toggleCatEdit"
</StackLayout> col="2"
<StackLayout :text="catEditMode ? 'DONE' : 'RENAME'"
orientation="horizontal" />
row="1" </GridLayout>
class="sd-group-header orkr" <ScrollView height="100%">
>
<Label text="Categories" />
</StackLayout>
<ScrollView row="2" scrollBarIndicatorVisible="false">
<StackLayout> <StackLayout>
<StackLayout <GridLayout
@tap="localNavigation(item, item, false, true)" @tap="navigateTo(item, false, true)"
v-for="(item, index) in categories" v-for="(item, index) in categories"
:key="index" :key="index"
orientation="horizontal"
class="sd-item orkm" class="sd-item orkm"
:class="{ :class="{
'selected-sd-item': 'selected-sd-item': currentComponent == item,
currentComponent === 'EnRecipes' && selectedCategory == item,
}" }"
columns="auto, *, auto"
> >
<Label class="bx" :text="icon.label" margin="0 24 0 0" /> <Label
<Label verticalAlignment="center" :text="item" /> col="0"
</StackLayout> class="bx"
:text="icon.label"
margin="0 24 0 0"
/>
<Label col="1" :text="item" />
<Label
v-if="catEditMode"
@tap="editCategory(item)"
col="2"
class="bx"
:text="icon.edit"
/>
</GridLayout>
</StackLayout> </StackLayout>
</ScrollView> </ScrollView>
</StackLayout>
<StackLayout row="3" class="hr m-10"></StackLayout> <StackLayout row="1">
<StackLayout row="4"> <StackLayout class="hr m-10"></StackLayout>
<StackLayout <StackLayout
@tap="navigateTo(item.component, item.title)" @tap="navigateTo(item.component, true, false)"
v-for="(item, index) in bottommenu" v-for="(item, index) in bottommenu"
:key="index" :key="index"
orientation="horizontal" orientation="horizontal"
@ -82,19 +85,30 @@
}" }"
> >
<Label class="bx" :text="icon[item.icon]" margin="0 24 0 0" /> <Label class="bx" :text="icon[item.icon]" margin="0 24 0 0" />
<Label verticalAlignment="center" :text="item.title" /> <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>
</StackLayout> </StackLayout>
</GridLayout> </GridLayout>
<GridLayout ~mainContent rows="*" columns="*"> <GridLayout ~mainContent rows="*" columns="*">
<Frame id="main-frame"> <Frame ref="mainFrame" id="main-frame">
<!-- Home --> <!-- Home -->
<EnRecipes <EnRecipes
:selectedCategory="selectedCategory" ref="enrecipes"
:filterFavorites="filterFavorites" :filterFavorites="filterFavorites"
:title="title" :filterMustTry="filterMustTry"
:selectedCategory="selectedCategory"
:showDrawer="showDrawer" :showDrawer="showDrawer"
:hijackGlobalBackEvent="hijackGlobalBackEvent"
:releaseGlobalBackEvent="releaseGlobalBackEvent"
/> />
</Frame> </Frame>
</GridLayout> </GridLayout>
@ -104,15 +118,20 @@
<script> <script>
import * as utils from "tns-core-modules/utils/utils" import * as utils from "tns-core-modules/utils/utils"
import { isAndroid } from "tns-core-modules/platform"
import * as application from "tns-core-modules/application" import * as application from "tns-core-modules/application"
import { getString } from "application-settings"
import Theme from "@nativescript/theme"
import * as Toast from "nativescript-toast"
import EnRecipes from "./EnRecipes.vue" import EnRecipes from "./EnRecipes.vue"
import Settings from "./Settings.vue" import Settings from "./Settings.vue"
import About from "./About.vue" import About from "./About.vue"
import PromptDialog from "./modal/PromptDialog.vue"
import { mapState } from "vuex" import { mapState } from "vuex"
import { Couchbase, ConcurrencyMode } from "nativescript-couchbase-plugin"
let page let page
export default { export default {
components: { components: {
@ -122,12 +141,26 @@ export default {
}, },
data() { data() {
return { return {
title: "EnRecipes",
selectedCategory: null, selectedCategory: null,
filterFavorites: false, filterFavorites: false,
searchQuery: "", filterMustTry: false,
showSearch: false, topmenu: [
currentComponent: "EnRecipes", {
title: "Home",
component: "EnRecipes",
icon: "home",
},
{
title: "Favorites",
component: "Favorites",
icon: "heart",
},
{
title: "Must-Try",
component: "Must-Try",
icon: "musttry",
},
],
bottommenu: [ bottommenu: [
{ {
title: "Settings", title: "Settings",
@ -140,10 +173,11 @@ export default {
icon: "info", icon: "info",
}, },
], ],
catEditMode: false,
} }
}, },
computed: { computed: {
...mapState(["recipes", "icon"]), ...mapState(["recipes", "categories", "icon", "currentComponent"]),
categories() { categories() {
let arr = this.recipes.map((e) => { let arr = this.recipes.map((e) => {
return e.category return e.category
@ -152,6 +186,39 @@ export default {
}, },
}, },
methods: { methods: {
toggleCatEdit() {
this.catEditMode = !this.catEditMode
this.setComponent("EnRecipes")
this.filterFavorites = this.filterMustTry = false
this.selectedCategory = null
this.$refs.enrecipes.updateFilter()
},
setComponent(comp) {
this.$store.dispatch("setCurrentComponent", comp)
},
editCategory(item) {
this.releaseGlobalBackEvent()
this.$showModal(PromptDialog, {
props: {
title: `Rename category`,
hint: item,
action: "RENAME",
},
}).then((result) => {
this.hijackGlobalBackEvent()
if (result.length) {
if (this.categories.includes(result)) {
Toast.makeText("Category already exists!", "long").show()
} else {
this.$store.dispatch("renameCategory", {
current: item,
updated: result,
})
this.catEditMode = false
}
}
})
},
highlight(args) { highlight(args) {
let temp = args.object.className let temp = args.object.className
args.object.className = `${temp} option-highlight` args.object.className = `${temp} option-highlight`
@ -159,70 +226,103 @@ export default {
args.object.className = temp args.object.className = temp
}, 100) }, 100)
}, },
// Navigation // Navigation
setSelectedCategory(e) { setSelectedCategory(e) {
this.selectedCategory = e.item this.selectedCategory = e.item
this.closeDrawer() this.closeDrawer()
}, },
removeBackEvent() { hijackGlobalBackEvent() {
application.android.off(
application.AndroidApplication.activityBackPressedEvent,
this.backEvent
)
},
backEvent(args) {
args.cancel = true
if (this.$refs.drawer.nativeView.getIsOpen()) this.closeDrawer()
else if (this.currentComponent !== "EnRecipes") {
this.$navigateBack({ frame: "main-frame" })
this.currentComponent = "EnRecipes"
} else if (this.filterFavorites || this.selectedCategory) {
this.title = "EnRecipes"
this.filterFavorites = false
this.selectedCategory = null
this.removeBackEvent()
}
},
localNavigation(to, title, filter, filterCategory) {
// navigateBackToHome
application.android.on( application.android.on(
application.AndroidApplication.activityBackPressedEvent, application.AndroidApplication.activityBackPressedEvent,
this.backEvent this.globalBackEvent
) )
if (this.currentComponent !== "EnRecipes") {
this.currentComponent = "EnRecipes"
this.$navigateBack({ frame: "main-frame" })
}
this.filterFavorites = false
this.selectedCategory = null
this.title = title
console.log(title)
if (filter) {
if (to === "Favorites") this.filterFavorites = true
} else if (filterCategory) this.selectedCategory = to
if (!this.filterFavorites && !this.selectedCategory)
this.removeBackEvent()
this.closeDrawer()
}, },
navigateTo(to, title) { releaseGlobalBackEvent() {
this.currentComponent = title application.android.off(
application.AndroidApplication.activityBackPressedEvent,
this.globalBackEvent
)
},
globalBackEvent(args) {
function preventDefault() {
args.cancel = true
}
let vm = this
function isFiltered() {
vm.filterFavorites
? vm.setComponent("Favorites")
: vm.filterMustTry
? vm.setComponent("Must-Try")
: vm.selectedCategory
? vm.setComponent(vm.selectedCategory)
: vm.setComponent("EnRecipes")
}
if (this.$refs.drawer && this.$refs.drawer.nativeView.getIsOpen()) {
preventDefault()
this.closeDrawer()
this.catEditMode = false
} else if (
["Favorites", "Must-Try", this.selectedCategory].includes(
this.currentComponent
)
) {
preventDefault()
this.setComponent("EnRecipes")
this.filterFavorites = this.filterMustTry = false
this.selectedCategory = null
this.$refs.enrecipes.updateFilter()
this.releaseGlobalBackEvent()
}
},
navigateTo(to, isTrueComponent, isCategory) {
if (isTrueComponent) {
this.$navigateTo(to, { this.$navigateTo(to, {
frame: "main-frame", frame: "main-frame",
// transition: {
// name: "slide",
// duration: 250,
// curve: "easeIn",
// },
props: { props: {
highlight: this.highlight, highlight: this.highlight,
viewIsScrolled: this.viewIsScrolled, viewIsScrolled: this.viewIsScrolled,
showDrawer: this.showDrawer, showDrawer: this.showDrawer,
title, restartApp: this.restartApp,
hijackGlobalBackEvent: this.hijackGlobalBackEvent,
releaseGlobalBackEvent: this.releaseGlobalBackEvent,
}, },
backstackVisible: false, backstackVisible: false,
}) })
this.closeDrawer() this.closeDrawer()
} else if (!this.catEditMode) {
this.releaseGlobalBackEvent()
this.hijackGlobalBackEvent()
this.setComponent(to)
this.$navigateBack({ frame: "main-frame", backstackVisible: false })
this.filterFavorites = to === "Favorites" ? true : false
this.filterMustTry = to === "Must-Try" ? true : false
this.selectedCategory = isCategory ? to : null
this.$refs.enrecipes.updateFilter()
this.closeDrawer()
}
},
restartApp() {
// Code from nativescript-master-technology
const mStartActivity = new android.content.Intent(
application.android.context,
application.android.startActivity.getClass()
)
const mPendingIntentId = parseInt(Math.random() * 100000, 10)
const mPendingIntent = android.app.PendingIntent.getActivity(
application.android.context,
mPendingIntentId,
mStartActivity,
android.app.PendingIntent.FLAG_CANCEL_CURRENT
)
const mgr = application.android.context.getSystemService(
android.content.Context.ALARM_SERVICE
)
mgr.set(
android.app.AlarmManager.RTC,
java.lang.System.currentTimeMillis() + 100,
mPendingIntent
)
android.os.Process.killProcess(android.os.Process.myPid())
}, },
showDrawer() { showDrawer() {
this.$refs.drawer.nativeView.showDrawer() this.$refs.drawer.nativeView.showDrawer()
@ -230,6 +330,14 @@ export default {
closeDrawer() { closeDrawer() {
this.$refs.drawer.nativeView.closeDrawer() this.$refs.drawer.nativeView.closeDrawer()
}, },
donate(args) {
this.highlight(args)
utils.openUrl("https://www.vishnuraghav.com/donate/")
},
},
created() {
let themeName = getString("application-theme", "Light")
Theme.setMode(Theme[themeName])
}, },
} }
</script> </script>

View file

@ -1,5 +1,5 @@
<template> <template>
<Page> <Page @loaded="setCurrentComponent" @unloaded="releaseBackEvent">
<ActionBar :flat="viewIsScrolled ? false : true"> <ActionBar :flat="viewIsScrolled ? false : true">
<GridLayout rows="*" columns="auto, *, auto," class="actionBarContainer"> <GridLayout rows="*" columns="auto, *, auto," class="actionBarContainer">
<Label <Label
@ -9,7 +9,8 @@
col="0" col="0"
@tap="navigateBack" @tap="navigateBack"
/> />
<Label class="title orkm" text="New recipe" col="1" /> <Label class="title orkm" :text="title" col="1" />
<Label <Label
v-if="hasEnoughDetails" v-if="hasEnoughDetails"
class="bx" class="bx"
@ -46,7 +47,7 @@
horizontalAlignment="center" horizontalAlignment="center"
class="bx" class="bx"
fontSize="160" fontSize="160"
:text="icon.dish" :text="icon.image"
/> />
</StackLayout> </StackLayout>
<StackLayout <StackLayout
@ -75,17 +76,14 @@
<StackLayout margin="0 16"> <StackLayout margin="0 16">
<AbsoluteLayout class="inputField"> <AbsoluteLayout class="inputField">
<TextField <TextField
width="100%"
hint="My Healthy Recipe" hint="My Healthy Recipe"
v-model="recipeContent.title" v-model="recipeContent.title"
autocapitalizationType="words" autocapitalizationType="words"
maxLength="32"
/> />
<Label top="0" class="fieldLabel" text="Title" /> <Label top="0" class="fieldLabel" text="Title" />
</AbsoluteLayout> </AbsoluteLayout>
<AbsoluteLayout class="inputField"> <AbsoluteLayout class="inputField">
<TextField <TextField
width="100%"
v-model="recipeContent.category" v-model="recipeContent.category"
editable="false" editable="false"
@tap="showCategories()" @tap="showCategories()"
@ -95,7 +93,6 @@
<GridLayout columns="*, 8, *"> <GridLayout columns="*, 8, *">
<AbsoluteLayout class="inputField" col="0"> <AbsoluteLayout class="inputField" col="0">
<TimePickerField <TimePickerField
width="100%"
timeFormat="HH:mm" timeFormat="HH:mm"
pickerTitle="Approx. preparation time" pickerTitle="Approx. preparation time"
@timeChange="onPrepTimeChange" @timeChange="onPrepTimeChange"
@ -105,7 +102,6 @@
</AbsoluteLayout> </AbsoluteLayout>
<AbsoluteLayout class="inputField" col="2"> <AbsoluteLayout class="inputField" col="2">
<TimePickerField <TimePickerField
width="100%"
timeFormat="HH:mm" timeFormat="HH:mm"
pickerTitle="Approx. cooking time" pickerTitle="Approx. cooking time"
@timeChange="onCookTimeChange" @timeChange="onCookTimeChange"
@ -157,11 +153,8 @@
@tap="showUnits($event)" @tap="showUnits($event)"
/> />
<Label <Label
verticalAlignment="center"
col="6" col="6"
padding="4" class="bx closeBtn"
margin="8 0 0 0"
class="bx"
:text="icon.close" :text="icon.close"
@tap="removeIngredient(index)" @tap="removeIngredient(index)"
/> />
@ -189,18 +182,9 @@
v-model="recipeContent.instructions[index]" v-model="recipeContent.instructions[index]"
editable="true" editable="true"
/> />
<!-- <TextField
col="0"
v-model="recipeContent.instructions[index]"
:hint="`Step ${index + 1}`"
/> -->
<Label <Label
verticalAlignment="center"
col="2" col="2"
padding="4" class="bx closeBtn"
margin="8 0 0 0"
class="bx"
:text="icon.close" :text="icon.close"
@tap="removeInstruction(index)" @tap="removeInstruction(index)"
/> />
@ -228,11 +212,8 @@
editable="true" editable="true"
/> />
<Label <Label
verticalAlignment="center"
col="2" col="2"
padding="4" class="bx closeBtn"
margin="8 0 0 0"
class="bx"
:text="icon.close" :text="icon.close"
@tap="removeNote(index)" @tap="removeNote(index)"
/> />
@ -259,11 +240,8 @@
hint="Website or Video URL" hint="Website or Video URL"
/> />
<Label <Label
verticalAlignment="center"
col="2" col="2"
padding="4" class="bx closeBtn"
margin="8 0 0 0"
class="bx"
:text="icon.close" :text="icon.close"
@tap="removeReference(index)" @tap="removeReference(index)"
/> />
@ -284,32 +262,17 @@
import { screen } from "tns-core-modules/platform" import { screen } from "tns-core-modules/platform"
import { Mediafilepicker } from "nativescript-mediafilepicker" import { Mediafilepicker } from "nativescript-mediafilepicker"
import { mapState, mapActions } from "vuex" import { mapState, mapActions } from "vuex"
import * as application from "tns-core-modules/application"
import ActionDialog from "./modal/ActionDialog.vue"
import PromptDialog from "./modal/PromptDialog.vue"
import ConfirmDialog from "./modal/ConfirmDialog.vue"
export default { export default {
props: ["recipeIndex", "selectedCategory"],
data() { data() {
return { return {
title: "New recipe",
viewIsScrolled: false, viewIsScrolled: false,
units: [
"unit",
"tsp",
"Tbsp",
"oz",
"cup",
"pt",
"qt",
"lb",
"gal",
"ml",
"L",
"mg",
"g",
"kg",
"mm",
"cm",
"m",
"in",
"°C",
"°F",
],
recipeContent: { recipeContent: {
imageSrc: null, imageSrc: null,
title: null, title: null,
@ -319,7 +282,7 @@ export default {
portionSize: 1, portionSize: 1,
ingredients: [ ingredients: [
{ {
item: null, item: "",
quantity: null, quantity: null,
unit: "unit", unit: "unit",
}, },
@ -328,71 +291,97 @@ export default {
notes: [""], notes: [""],
references: [""], references: [""],
isFavorite: false, isFavorite: false,
tried: false,
lastModified: null,
}, },
categories: [ tempRecipeContent: {},
"Appetizers", blockModal: false,
"BBQ",
"Beverages",
"Breads",
"Breakfast",
"Desserts",
"Dinner",
"Drinks",
"Healthy",
"Lunch",
"Main dishes",
"Meat",
"Noodles",
"Pasta",
"Poultry",
"Rice",
"Salads",
"Sauces",
"Seafood",
"Side dishes",
"Snacks",
"Soups",
"Vegan",
"Vegetarian",
"ADD NEW CATEGORY",
],
} }
}, },
computed: { computed: {
...mapState(["icon"]), ...mapState(["icon", "units", "categories", "currentComponent", "recipes"]),
screenWidth() { screenWidth() {
return screen.mainScreen.widthDIPs return screen.mainScreen.widthDIPs
}, },
hasEnoughDetails() { hasEnoughDetails() {
let recipe = this.recipeContent if (this.recipeIndex) {
return recipe.title && recipe.category return (
JSON.stringify(this.recipeContent) !==
JSON.stringify(this.tempRecipeContent)
)
} else {
return this.recipeContent.title
}
}, },
}, },
methods: { methods: {
setTime(time) { setCurrentComponent() {
if (Date.parse(this.recipeContent[time])) { setTimeout((e) => {
let date = new Date(this.recipeContent[time]) this.$store.dispatch("setCurrentComponent", "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])
} else {
if (this.selectedCategory)
this.recipeContent.category = this.selectedCategory
Object.assign(this.tempRecipeContent, this.recipeContent)
}
this.hijackBackEvent()
},
setTime(key, time) {
if (Date.parse(time)) {
let date = new Date(time)
let h = date.getHours() let h = date.getHours()
let m = date.getMinutes() let m = date.getMinutes()
this.recipeContent[time] = this.recipeContent[key] =
(h < 10 ? "0" + h : h) + ":" + (m < 10 ? "0" + m : m) (h < 10 ? "0" + h : h) + ":" + (m < 10 ? "0" + m : m)
} }
// console.log(this.recipeContent[time]) },
clearEmptyFields() {
if (!this.recipeContent.portionSize) {
this.recipeContent.portionSize = 1
}
if (!this.recipeContent.category) {
this.recipeContent.category = "Undefined"
}
this.recipeContent.ingredients.forEach((e, i) => {
if (!e.item.length) {
this.recipeContent.ingredients.splice(i, 1)
}
})
let vm = this
function removeEmpty(arr) {
vm.recipeContent[arr].forEach((e, i) => {
if (!e.length) {
vm.recipeContent[arr].splice(i, 1)
}
})
}
removeEmpty("instructions")
removeEmpty("notes")
removeEmpty("references")
}, },
saveRecipe() { saveRecipe() {
this.setTime("prepTime") this.clearEmptyFields()
this.setTime("cookTime") this.recipeContent.lastModified = new Date()
// console.log(this.recipeContent) if (this.recipeIndex >= 0) {
this.$store.dispatch("overwriteRecipe", {
index: this.recipeIndex,
recipe: this.recipeContent,
})
} else {
this.$store.dispatch("addRecipe", this.recipeContent) this.$store.dispatch("addRecipe", this.recipeContent)
}
this.$navigateBack() this.$navigateBack()
}, },
onPrepTimeChange(args) { onPrepTimeChange(args) {
this.recipeContent.prepTime = args.value this.setTime("prepTime", args.value)
}, },
onCookTimeChange(args) { onCookTimeChange(args) {
this.recipeContent.cookTime = args.value this.setTime("cookTime", args.value)
}, },
onScroll(args) { onScroll(args) {
args.scrollY args.scrollY
@ -400,25 +389,77 @@ export default {
: (this.viewIsScrolled = false) : (this.viewIsScrolled = false)
}, },
showCategories() { showCategories() {
action("Select a category", "Cancel", [...this.categories]).then( this.releaseBackEvent()
(result) => { this.$showModal(ActionDialog, {
if (result != "Cancel") this.recipeContent.category = result props: {
} title: "Category",
) list: [...this.categories],
height: "75%",
action: "NEW CATEGORY",
}, },
navigateBack() { }).then((action) => {
confirm({ if (action == "NEW CATEGORY") {
message: this.$showModal(PromptDialog, {
"Are you sure you want discard unsaved changes to this recipe?", props: {
cancelButtonText: "Keep Editing", title: "New category",
okButtonText: "Discard", action: "ADD",
}).then((res) => { },
if (res) { }).then((result) => {
this.$navigateBack() this.hijackBackEvent()
if (result.length) {
this.recipeContent.category = result
this.$store.dispatch("addCategory", result)
}
})
} else if (action) {
this.recipeContent.category = action
this.hijackBackEvent()
} else {
this.hijackBackEvent()
} }
}) })
}, },
navigateBack() {
if (this.hasEnoughDetails) {
this.blockModal = true
this.$showModal(ConfirmDialog, {
props: {
title: "Discard changes",
description:
"Are you sure you want discard unsaved changes to this recipe?",
cancelButtonText: "KEEP EDITING",
okButtonText: "DISCARD",
},
}).then((action) => {
this.blockModal = false
if (action) {
this.$navigateBack()
this.releaseBackEvent()
}
})
} else {
this.$navigateBack()
this.releaseBackEvent()
}
},
hijackBackEvent() {
application.android.on(
application.AndroidApplication.activityBackPressedEvent,
this.backEvent
)
},
releaseBackEvent() {
application.android.off(
application.AndroidApplication.activityBackPressedEvent,
this.backEvent
)
},
backEvent(args) {
if (this.hasEnoughDetails && !this.blockModal) {
args.cancel = true
this.navigateBack()
}
},
takePicture() { takePicture() {
let mediafilepicker = new Mediafilepicker() let mediafilepicker = new Mediafilepicker()
let vm = this let vm = this
@ -462,7 +503,7 @@ export default {
}, },
removePicture() { removePicture() {
confirm({ confirm({
title: "Delete Recipe Photo", title: "Delete Photo",
message: "Are you sure you want to delete the recipe photo?", message: "Are you sure you want to delete the recipe photo?",
okButtonText: "Delete", okButtonText: "Delete",
cancelButtonText: "Cancel", cancelButtonText: "Cancel",
@ -473,7 +514,7 @@ export default {
addIngredient() { addIngredient() {
this.recipeContent.ingredients.push({ this.recipeContent.ingredients.push({
item: null, item: "",
quantity: null, quantity: null,
unit: "unit", unit: "unit",
}) })
@ -504,11 +545,17 @@ export default {
}, },
showUnits(e) { showUnits(e) {
action("Select measuring unit", "Cancel", [...this.units]).then( this.releaseBackEvent()
(result) => { this.$showModal(ActionDialog, {
if (result != "Cancel") e.object.text = result props: {
} title: "Unit",
) list: [...this.units],
height: "75%",
},
}).then((action) => {
this.hijackBackEvent()
if (action) e.object.text = action
})
}, },
}, },
} }

View file

@ -1,12 +1,12 @@
<template> <template>
<Page> <Page @loaded="setCurrentComponent">
<ActionBar :flat="viewIsScrolled ? false : true"> <ActionBar :flat="viewIsScrolled ? false : true">
<!-- Search Actionbar --> <!-- Search Actionbar -->
<GridLayout <GridLayout
v-if="showSearch" v-if="showSearch"
rows="*"
columns="auto, *" columns="auto, *"
class="actionBarContainer" class="actionBarContainer"
verticalAlignment="center"
> >
<Label <Label
class="bx leftAction" class="bx leftAction"
@ -15,20 +15,20 @@
col="0" col="0"
@tap="closeSearch" @tap="closeSearch"
/> />
<!-- @loaded="searchBarLoaded" -->
<SearchBar <SearchBar
@loaded="searchBarLoaded"
id="searchField"
col="1" col="1"
hint="Search" hint="Search"
textFieldHintColor="#bdbdbd" textFieldHintColor="#bdbdbd"
v-model="searchQuery" v-model="searchQuery"
@textChange="updateFilter"
@clear="updateFilter"
/> />
</GridLayout> </GridLayout>
<!-- Home Actionbar --> <!-- Home Actionbar -->
<GridLayout <GridLayout
v-else v-else
rows="*" columns="auto, *, auto, auto"
columns="auto, *, auto,"
class="actionBarContainer" class="actionBarContainer"
> >
<Label <Label
@ -38,84 +38,61 @@
@tap="showDrawer" @tap="showDrawer"
col="0" col="0"
/> />
<Label class="title orkm" :text="title" col="1" /> <Label class="title orkm" :text="currentComponent" col="1" />
<Label <Label class="bx" :text="icon.search" col="2" @tap="openSearch" />
class="bx" <Label class="bx" :text="icon.sort" col="3" @tap="sortDialog" />
:text="icon.search"
col="2"
@tap="showSearch = true"
/>
</GridLayout> </GridLayout>
</ActionBar> </ActionBar>
<AbsoluteLayout> <AbsoluteLayout>
<RadListView <RadListView
v-if="filteredRecipes.length"
ref="listView" ref="listView"
for="recipe in filteredRecipes" itemHeight="112"
for="recipe in recipes"
swipeActions="true" swipeActions="true"
@itemSwipeProgressChanged="onSwiping" @itemSwipeProgressChanged="onSwiping"
@itemSwipeProgressEnded="onSwipeEnded" @itemSwipeProgressEnded="onSwipeEnded"
@scrolled="onScroll($event)" @scrolled="onScroll($event)"
@itemTap="viewRecipe" @itemTap="viewRecipe"
:filteringFunction="filterFunction"
:sortingFunction="sortFunction"
> >
<v-template> <v-template>
<GridLayout <GridLayout
class="recipe-li" class="recipe-li"
rows="128" rows="112"
columns="auto, *, auto" columns="112, *"
androidElevation="2" androidElevation="1"
> >
<Image <Image col="0" src="res://icon" stretch="fill" />
src="res://icon" <StackLayout class="recipe-info" col="1">
stretch="fill" <Label :text="recipe.category" class="orkm recipe-cat" />
col="0"
width="128"
height="128"
/>
<StackLayout
class="recipe-info"
col="1"
horizontalAlignment="left"
verticalAlignment="top"
>
<Label :text="recipe.category" class="orkm h4 recipe-cat" />
<Label :text="recipe.title" class="orkm recipe-title" /> <Label :text="recipe.title" class="orkm recipe-title" />
<Label <Label
:text="recipeTotalTime(recipe.prepTime, recipe.cookTime)" :text="recipeTotalTime(recipe.prepTime, recipe.cookTime)"
class="h4 recipe-time" class="h4 recipe-time"
/> />
</StackLayout> </StackLayout>
<Label
verticalAlignment="top"
col="2"
class="bx recipe-favorite"
:class="{ hide: !recipe.isFavorite }"
:text="icon.heart"
/>
</GridLayout> </GridLayout>
</v-template> </v-template>
<v-template name="itemswipe"> <v-template name="itemswipe">
<GridLayout columns="auto, *, auto"> <GridLayout columns="*, auto">
<StackLayout <StackLayout id="delete-action" col="1" class="swipe-item right">
id="favorite-action"
col="0"
class="swipe-item left"
verticalAlignment="top"
>
<Label class="bx" padding="8 6 0 0" :text="icon.heart" />
</StackLayout>
<StackLayout
id="delete-action"
col="2"
class="swipe-item right"
verticalAlignment="top"
>
<Label class="bx" padding="8 0 0 6" :text="icon.trash" /> <Label class="bx" padding="8 0 0 6" :text="icon.trash" />
</StackLayout> </StackLayout>
</GridLayout> </GridLayout>
</v-template> </v-template>
<v-template name="footer">
<StackLayout height="128"></StackLayout>
</v-template>
</RadListView> </RadListView>
<Label
v-if="!recipes.length && !filterFavorites && !filterMustTry"
class="noResults"
horizontalAlignment="center"
text='Click the "+" icon to add a new recipe.'
textAlignment="center"
textWrap="true"
/>
<Label <Label
v-if="!filteredRecipes.length && searchQuery" v-if="!filteredRecipes.length && searchQuery"
class="noResults" class="noResults"
@ -134,12 +111,15 @@
textAlignment="center" textAlignment="center"
textWrap="true" textWrap="true"
/> />
<GridLayout <Label
id="btnFabContainer" v-if="!filteredRecipes.length && filterMustTry && !searchQuery"
rows="*,88" class="noResults"
columns="*,88" horizontalAlignment="center"
v-if="!showSearch" text="Your Must-Try recipes will be listed here."
> textAlignment="center"
textWrap="true"
/>
<GridLayout id="btnFabContainer" rows="*,88" columns="*,88">
<Label <Label
row="1" row="1"
col="1" col="1"
@ -157,15 +137,25 @@
import * as utils from "tns-core-modules/utils/utils" import * as utils from "tns-core-modules/utils/utils"
import * as application from "tns-core-modules/application" import * as application from "tns-core-modules/application"
import * as gestures from "tns-core-modules/ui/gestures" import * as gestures from "tns-core-modules/ui/gestures"
import * as Toast from "nativescript-toast"
import { ObservableArray } from "tns-core-modules/data/observable-array" import { ObservableArray } from "tns-core-modules/data/observable-array"
import EditRecipe from "./EditRecipe.vue" import EditRecipe from "./EditRecipe.vue"
import ViewRecipe from "./ViewRecipe.vue" import ViewRecipe from "./ViewRecipe.vue"
import ActionDialog from "./modal/ActionDialog.vue"
import ConfirmDialog from "./modal/ConfirmDialog.vue"
import { mapState, mapActions } from "vuex" import { mapState, mapActions } from "vuex"
export default { export default {
props: ["filterFavorites", "selectedCategory", "title", "showDrawer"], props: [
"filterFavorites",
"filterMustTry",
"selectedCategory",
"showDrawer",
"hijackGlobalBackEvent",
"releaseGlobalBackEvent",
],
components: { components: {
EditRecipe, EditRecipe,
ViewRecipe, ViewRecipe,
@ -173,80 +163,182 @@ export default {
data() { data() {
return { return {
searchQuery: "", searchQuery: "",
showSearch: false,
viewIsScrolled: false, viewIsScrolled: false,
leftAction: false, showSearch: false,
// leftAction: false,
rightAction: false, rightAction: false,
sortType: "Natural order",
} }
}, },
computed: { computed: {
...mapState(["recipes", "icon"]), ...mapState(["recipes", "icon", "currentComponent"]),
recipesByCategory() {
return this.recipes.reduce((acc, e) => {
acc[e.category] = [...(acc[e.category] || []), e]
return acc
}, {})
},
filteredRecipes() { filteredRecipes() {
if (this.selectedCategory) { if (this.filterFavorites) {
return this.recipesByCategory[this.selectedCategory].filter((e) => { return this.recipes.filter(
if (e.title.toLowerCase().includes(this.searchQuery)) return e (e) =>
}) e.isFavorite && e.title.toLowerCase().includes(this.searchQuery)
} else if (this.filterFavorites) { )
console.log("fav") } else if (this.filterMustTry) {
return this.recipes.filter((e) => { return this.recipes.filter(
if (e.isFavorite) { (e) => !e.tried && e.title.toLowerCase().includes(this.searchQuery)
if (e.title.toLowerCase().includes(this.searchQuery)) return e )
} } else if (this.selectedCategory) {
}) return this.recipes.filter(
(e) =>
e.category === this.selectedCategory &&
e.title.toLowerCase().includes(this.searchQuery)
)
} else { } else {
return this.recipes.filter((e) => { return this.recipes.filter((e) =>
if (e.title.toLowerCase().includes(this.searchQuery)) return e e.title.toLowerCase().includes(this.searchQuery)
}) )
} }
}, },
}, },
methods: { methods: {
openSearch() {
this.showSearch = true
this.hijackLocalBackEvent()
},
hijackLocalBackEvent() {
this.releaseGlobalBackEvent()
application.android.on(
application.AndroidApplication.activityBackPressedEvent,
this.searchBackEvent
)
},
releaseLocalBackEvent() {
application.android.off(
application.AndroidApplication.activityBackPressedEvent,
this.searchBackEvent
)
this.hijackGlobalBackEvent()
},
searchBackEvent(args) {
args.cancel = true
this.closeSearch()
},
closeSearch() {
this.searchQuery = ""
utils.ad.dismissSoftInput()
this.showSearch = false
this.updateFilter()
this.releaseLocalBackEvent()
},
sortDialog() {
this.releaseGlobalBackEvent()
this.$showModal(ActionDialog, {
props: {
title: "Sort by",
list: ["Natural order", "Title", "Duration", "Last modified"],
height: "auto",
},
}).then((action) => {
if (action && action !== "Cancel" && this.sortType !== action) {
this.sortType = action
this.updateSort()
}
this.hijackGlobalBackEvent()
})
},
updateSort() {
let listView = this.$refs.listView.nativeView
listView.sortingFunction = undefined
listView.sortingFunction = this.sortFunction
},
sortFunction(item, otherItem) {
const titleOrder = item.title
.toLowerCase()
.localeCompare(otherItem.title.toLowerCase(), "en", {
ignorePunctuation: true,
})
let d1 = this.recipeDuration(item.prepTime, item.cookTime)
let d2 = this.recipeDuration(otherItem.prepTime, otherItem.cookTime)
let ld1 = new Date(item.lastModified)
let ld2 = new Date(otherItem.lastModified)
switch (this.sortType) {
case "Title":
return titleOrder > 0 ? -1 : titleOrder < 0 ? 1 : 0
break
case "Duration":
return d1 > d2 ? -1 : d1 < d2 ? 1 : 0
break
case "Last modified":
return ld1 < ld2 ? -1 : ld1 > ld2 ? 1 : 0
break
default:
return 0
break
}
},
setComponent(comp) {
this.$store.dispatch("setCurrentComponent", comp)
this.hijackGlobalBackEvent()
},
updateFilter() {
let listView = this.$refs.listView.nativeView
setTimeout((e) => {
listView.filteringFunction = undefined
listView.filteringFunction = this.filterFunction
}, 1)
},
filterFunction(item) {
if (this.filterFavorites) {
return item.isFavorite
? item.title.toLowerCase().includes(this.searchQuery)
: false
} else if (this.filterMustTry) {
return item.tried
? false
: item.title.toLowerCase().includes(this.searchQuery)
} else if (this.selectedCategory) {
return item.category === this.selectedCategory
? item.title.toLowerCase().includes(this.searchQuery)
: false
} else {
return item.title.toLowerCase().includes(this.searchQuery)
}
},
setCurrentComponent() {
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
const leftItem = swipeView.getViewById("favorite-action")
const rightItem = swipeView.getViewById("delete-action") const rightItem = swipeView.getViewById("delete-action")
swipeLimits.left = leftItem.getMeasuredWidth() - 12
swipeLimits.right = rightItem.getMeasuredWidth() - 12 swipeLimits.right = rightItem.getMeasuredWidth() - 12
swipeLimits.threshold = swipeLimits.left - 4 swipeLimits.threshold = swipeLimits.right - 6
if (data.x > swipeLimits.threshold) { if (data.x < -swipeLimits.threshold) {
this.leftAction = true
this.$refs.listView.notifySwipeToExecuteFinished()
} else if (data.x < -swipeLimits.threshold) {
this.rightAction = true this.rightAction = true
this.$refs.listView.notifySwipeToExecuteFinished() swipeView.notifySwipeToExecuteFinished()
} }
}, },
onSwipeEnded({ index }) { onSwipeEnded({ index }) {
let context = this.recipes.indexOf(this.filteredRecipes[index]) if (this.rightAction) this.deleteRecipe(index)
if (this.leftAction) this.toggleFavorite(context) this.rightAction = false
else if (this.rightAction) this.deleteRecipe()
this.leftAction = this.rightAction = false
}, },
toggleFavorite(index) { deleteRecipe(index) {
this.$store.dispatch("toggleFavorite", index) this.$showModal(ConfirmDialog, {
props: {
title: "Delete recipe",
description: `Are you sure you want to delete the recipe "${this.recipes[index].title}"?`,
cancelButtonText: "CANCEL",
okButtonText: "DELETE",
}, },
deleteRecipe() { }).then((action) => {
alert("Are you sure you want to delete?") if (action) {
this.$store.dispatch("deleteRecipe", index)
}
})
}, },
// swipeAction(args, index) { getTotalTime(prepTime, cookTime) {
// let vm = this
// args.object.on(gestures.GestureTypes.swipe, function(args) {
// console.log("Swipe Direction: " + args.direction)
// if (args.direction === 1) {
// vm.filteredRecipes[index].isFavorite = !vm.filteredRecipes[index]
// .isFavorite
// console.log(vm.filteredRecipes[index].isFavorite)
// }
// })
// },
recipeTotalTime(prepTime, cookTime) {
let pT = prepTime.split(":") let pT = prepTime.split(":")
let cT = cookTime.split(":") let cT = cookTime.split(":")
let hrs = parseInt(pT[0]) + parseInt(cT[0]) let hrs = parseInt(pT[0]) + parseInt(cT[0])
@ -255,42 +347,26 @@ export default {
hrs += Math.floor(mins / 60) hrs += Math.floor(mins / 60)
mins -= 60 mins -= 60
} }
return {
hrs,
mins,
}
},
recipeTotalTime(prepTime, cookTime) {
let { hrs, mins } = this.getTotalTime(prepTime, cookTime)
return hrs ? `${hrs}h ${mins}m` : `${mins}m` return hrs ? `${hrs}h ${mins}m` : `${mins}m`
}, },
recipeDuration(prepTime, cookTime) {
let { hrs, mins } = this.getTotalTime(prepTime, cookTime)
return `${hrs}${mins}`
},
onScroll(args) { onScroll(args) {
args.scrollOffset args.scrollOffset
? (this.viewIsScrolled = true) ? (this.viewIsScrolled = true)
: (this.viewIsScrolled = false) : (this.viewIsScrolled = false)
}, },
// SearchBar
searchBarLoaded() {
application.android.on(
application.AndroidApplication.activityBackPressedEvent,
this.backEvent
)
},
backEvent(args) {
if (this.showSearch) {
args.cancel = true
this.closeSearch()
}
this.removeBackEvent()
},
removeBackEvent() {
application.android.off(
application.AndroidApplication.activityBackPressedEvent,
this.backEvent
)
},
closeSearch() {
this.searchQuery = ""
this.showSearch = false
utils.ad.dismissSoftInput()
},
FabTapped() {
alert("fab tapped")
},
addRecipe() { addRecipe() {
this.releaseGlobalBackEvent()
this.$navigateTo(EditRecipe, { this.$navigateTo(EditRecipe, {
transition: { transition: {
name: "slide", name: "slide",
@ -299,11 +375,11 @@ export default {
}, },
props: { props: {
viewIsScrolled: this.viewIsScrolled, viewIsScrolled: this.viewIsScrolled,
selectedCategory: this.selectedCategory,
}, },
}) })
}, },
viewRecipe({ item }) { viewRecipe({ item }) {
// console.log(item)
this.$navigateTo(ViewRecipe, { this.$navigateTo(ViewRecipe, {
transition: { transition: {
name: "fade", name: "fade",
@ -311,7 +387,9 @@ export default {
curve: "easeIn", curve: "easeIn",
}, },
props: { props: {
recipe: item, recipeIndex: this.recipes.indexOf(item),
hijackGlobalBackEvent: this.hijackGlobalBackEvent,
releaseGlobalBackEvent: this.releaseGlobalBackEvent,
}, },
}) })
}, },

View file

@ -1,5 +1,5 @@
<template> <template>
<Page> <Page @loaded="setCurrentComponent">
<ActionBar :flat="viewIsScrolled ? false : true"> <ActionBar :flat="viewIsScrolled ? false : true">
<!-- Settings Actionbar --> <!-- Settings Actionbar -->
<GridLayout rows="*" columns="auto, *" class="actionBarContainer"> <GridLayout rows="*" columns="auto, *" class="actionBarContainer">
@ -10,7 +10,7 @@
@tap="showDrawer" @tap="showDrawer"
col="0" col="0"
/> />
<Label class="title orkm" :text="title" col="1" /> <Label class="title orkm" text="Settings" col="1" />
</GridLayout> </GridLayout>
</ActionBar> </ActionBar>
<ScrollView scrollBarIndicatorVisible="false"> <ScrollView scrollBarIndicatorVisible="false">
@ -22,6 +22,7 @@
class="option" class="option"
@tap="selectThemes" @tap="selectThemes"
> >
<!-- @tap="selectThemes" -->
<Label verticalAlignment="center" class="bx" :text="icon.theme" /> <Label verticalAlignment="center" class="bx" :text="icon.theme" />
<StackLayout> <StackLayout>
<Label text="Theme" class="option-title" /> <Label text="Theme" class="option-title" />
@ -57,16 +58,24 @@
</template> </template>
<script> <script>
import { Menu } from "nativescript-menu"
import * as permissions from "nativescript-permissions" import * as permissions from "nativescript-permissions"
import * as application from "tns-core-modules/application" import * as application from "tns-core-modules/application"
import { getString, setString } from "application-settings" import { getString, setString } from "application-settings"
import Theme from "@nativescript/theme" import Theme from "@nativescript/theme"
import ActionDialog from "./modal/ActionDialog.vue"
import ConfirmDialog from "./modal/ConfirmDialog.vue"
import { mapState, mapActions } from "vuex" import { mapState, mapActions } from "vuex"
export default { export default {
props: ["highlight", "viewIsScrolled", "showDrawer", "title"], props: [
"highlight",
"viewIsScrolled",
"showDrawer",
"restartApp",
"hijackGlobalBackEvent",
"releaseGlobalBackEvent",
],
data() { data() {
return { return {
interface: { interface: {
@ -98,23 +107,44 @@ export default {
} }
}, },
computed: { computed: {
...mapState(["icon"]), ...mapState(["icon", "currentComponent"]),
}, },
methods: { methods: {
setCurrentComponent() {
this.$store.dispatch("setCurrentComponent", "Settings")
this.releaseGlobalBackEvent()
},
showDialog(args) {
this.highlight(args)
this.$showModal(ActionDialog)
},
selectThemes(args) { selectThemes(args) {
this.highlight(args) this.highlight(args)
let btn = args.object this.$showModal(ActionDialog, {
Menu.popup({ props: {
view: btn, title: "Theme",
actions: this.themesArray, list: ["Light", "Dark"],
height: "96",
},
}).then((action) => {
if (action && action !== "Cancel" && this.themeName !== action) {
this.$showModal(ConfirmDialog, {
props: {
title: "App Reload Required",
description:
"The app needs to be reloaded for the theme change to take effect.",
cancelButtonText: "CANCEL",
okButtonText: "RELOAD",
},
}).then((result) => {
if (result) {
this.interface.theme.subTitle = this.themeName = action
setString("application-theme", action)
setTimeout((e) => this.restartApp(), 250)
}
}) })
.then((action) => { }
this.interface.theme.subTitle = this.themeName = action.title
console.log(this.themeName)
setString("application-theme", action.title)
Theme.toggleMode()
}) })
.catch(console.log)
}, },
selectBackupDir(args) { selectBackupDir(args) {
this.highlight(args) this.highlight(args)

View file

@ -1,41 +1,48 @@
<template> <template>
<Page> <Page @loaded="setCurrentComponent">
<ActionBar margin="0" flat="true"> <ActionBar height="128" margin="0" flat="true">
<GridLayout <GridLayout
rows="*" rows="64, 64"
columns="auto, *, auto,auto" columns="auto, *, auto,auto, auto"
class="actionBarContainer" class="actionBarContainer"
> >
<Label <Label
row="0"
col="0" col="0"
class="bx leftAction" class="bx leftAction"
:text="icon.back" :text="icon.back"
automationText="Back" automationText="Back"
@tap="navigateBack" @tap="$navigateBack()"
verticalAlignment="top"
/> />
<ScrollView
row="1"
col="1"
colSpan="3"
orientation="horizontal"
scrollBarIndicatorVisible="false"
>
<Label <Label
class="title orkm" class="title orkm"
:text="recipe.title" :text="recipe.title"
lineHeight="4"
col="1"
textWrap="true"
verticalAlignment="bottom" verticalAlignment="bottom"
/> />
</ScrollView>
<Label row="0" col="2" class="bx" :text="icon.share" @tap="" />
<Label <Label
col="2" row="0"
class="bx"
:text="icon.share"
@tap=""
verticalAlignment="top"
/>
<Label
col="3" col="3"
class="bx" class="bx"
:class="{ 'view-favorited': recipe.isFavorite }" :class="{ 'view-favorited': recipe.isFavorite }"
:text="recipe.isFavorite ? icon.heart : icon.heartOutline" :text="recipe.isFavorite ? icon.heart : icon.heartOutline"
@tap="toggleFavorite" @tap="toggleFavorite"
verticalAlignment="top" />
<Label
row="0"
col="4"
class="bx"
:class="{ 'view-favorited': !recipe.tried }"
:text="recipe.tried ? icon.musttryOutline : icon.musttry"
@tap="toggleMustTry"
/> />
</GridLayout> </GridLayout>
</ActionBar> </ActionBar>
@ -43,7 +50,7 @@
<TabView androidElevation="0" width="100%" height="100%"> <TabView androidElevation="0" width="100%" height="100%">
<TabViewItem title="Overview"> <TabViewItem title="Overview">
<ScrollView scrollBarIndicatorVisible="false"> <ScrollView scrollBarIndicatorVisible="false">
<StackLayout class=""> <StackLayout>
<StackLayout <StackLayout
width="100%" width="100%"
:height="screenWidth" :height="screenWidth"
@ -62,13 +69,13 @@
horizontalAlignment="center" horizontalAlignment="center"
class="bx" class="bx"
fontSize="160" fontSize="160"
:text="icon.dish" :text="icon.image"
/> />
</StackLayout> </StackLayout>
<StackLayout margin="16 16 128"> <StackLayout margin="16 16 144">
<Label class="view-cat orkm" :text="recipe.category" /> <Label class="view-cat orkm" :text="recipe.category" />
<Label <Label
class="view-title p-b-8 orkm" class="view-title orkm"
:text="recipe.title" :text="recipe.title"
textWrap="true" textWrap="true"
/> />
@ -88,9 +95,9 @@
</StackLayout> </StackLayout>
</ScrollView> </ScrollView>
</TabViewItem> </TabViewItem>
<TabViewItem title="Ingredients" v-if="recipe.ingredients[0].item"> <TabViewItem title="Ingredients" v-if="recipe.ingredients.length">
<ScrollView scrollBarIndicatorVisible="false"> <ScrollView scrollBarIndicatorVisible="false">
<StackLayout padding="16 16 128"> <StackLayout padding="16 16 124">
<AbsoluteLayout class="inputField"> <AbsoluteLayout class="inputField">
<TextField <TextField
width="50%" width="50%"
@ -101,7 +108,7 @@
</AbsoluteLayout> </AbsoluteLayout>
<StackLayout margin="24 0 8 0"> <StackLayout margin="24 0 8 0">
<Label <Label
class="view-title p-b-8 orkm" class="view-title orkm"
:text=" :text="
`Ingredients for ${portionScale}${ `Ingredients for ${portionScale}${
portionScale > 1 portionScale > 1
@ -128,9 +135,9 @@
</StackLayout> </StackLayout>
</ScrollView> </ScrollView>
</TabViewItem> </TabViewItem>
<TabViewItem title="Instructions" v-if="recipe.instructions[0].length"> <TabViewItem title="Instructions" v-if="recipe.instructions.length">
<ScrollView scrollBarIndicatorVisible="false"> <ScrollView scrollBarIndicatorVisible="false">
<StackLayout padding="16 16 128"> <StackLayout padding="32 16 132">
<GridLayout <GridLayout
columns="auto ,*" columns="auto ,*"
v-for="(instruction, index) in recipe.instructions" v-for="(instruction, index) in recipe.instructions"
@ -158,9 +165,9 @@
</StackLayout> </StackLayout>
</ScrollView> </ScrollView>
</TabViewItem> </TabViewItem>
<TabViewItem title="Notes" v-if="recipe.notes[0].length"> <TabViewItem title="Notes" v-if="recipe.notes.length">
<ScrollView scrollBarIndicatorVisible="false"> <ScrollView scrollBarIndicatorVisible="false">
<StackLayout padding="16 16 128"> <StackLayout padding="32 16 132">
<GridLayout <GridLayout
columns="auto ,*" columns="auto ,*"
v-for="(note, index) in recipe.notes" v-for="(note, index) in recipe.notes"
@ -184,9 +191,9 @@
</StackLayout> </StackLayout>
</ScrollView> </ScrollView>
</TabViewItem> </TabViewItem>
<TabViewItem title="References" v-if="recipe.references[0].length"> <TabViewItem title="References" v-if="recipe.references.length">
<ScrollView scrollBarIndicatorVisible="false"> <ScrollView scrollBarIndicatorVisible="false">
<StackLayout padding="16 16 128"> <StackLayout padding="32 16 132">
<GridLayout <GridLayout
columns="auto ,*" columns="auto ,*"
v-for="(reference, index) in recipe.references" v-for="(reference, index) in recipe.references"
@ -214,6 +221,7 @@
</TabView> </TabView>
<GridLayout id="btnFabContainer" rows="*,88" columns="*,88"> <GridLayout id="btnFabContainer" rows="*,88" columns="*,88">
<Label <Label
v-if="!busy"
row="1" row="1"
col="1" col="1"
class="bx btnFab" class="bx btnFab"
@ -221,6 +229,7 @@
androidElevation="8" androidElevation="8"
@tap="editRecipe" @tap="editRecipe"
/> />
<ActivityIndicator v-else row="1" col="1" :busy="busy" />
</GridLayout> </GridLayout>
</AbsoluteLayout> </AbsoluteLayout>
</Page> </Page>
@ -229,18 +238,26 @@
<script> <script>
import { screen } from "tns-core-modules/platform" import { screen } from "tns-core-modules/platform"
import * as utils from "tns-core-modules/utils/utils" import * as utils from "tns-core-modules/utils/utils"
import { getNumber, setNumber } from "application-settings"
import * as Toast from "nativescript-toast"
import EditRecipe from "./EditRecipe.vue"
import { mapState, mapActions } from "vuex" import { mapState, mapActions } from "vuex"
export default { export default {
props: ["recipe"], props: ["recipeIndex", "hijackGlobalBackEvent", "releaseGlobalBackEvent"],
data() { data() {
return { return {
busy: false,
portionScale: 1, portionScale: 1,
} }
}, },
computed: { computed: {
...mapState(["icon", "recipes"]), ...mapState(["icon", "recipes"]),
recipe() {
return this.recipes[this.recipeIndex]
},
screenWidth() { screenWidth() {
return screen.mainScreen.widthDIPs return screen.mainScreen.widthDIPs
}, },
@ -254,18 +271,33 @@ export default {
roundedQuantity(quantity, unit) { roundedQuantity(quantity, unit) {
return Math.round(quantity * this.isPortionScalePositive * 100) / 100 return Math.round(quantity * this.isPortionScalePositive * 100) / 100
}, },
// indexChange(args) {
// let newIndex = args.value
// console.log("Current tab index: " + newIndex)
// },
navigateBack() {
this.$navigateBack()
},
editRecipe() { editRecipe() {
alert("edit recipe") this.busy = true
this.$navigateTo(EditRecipe, {
transition: {
name: "slide",
duration: 250,
curve: "easeIn",
},
props: {
recipeIndex: this.recipeIndex,
},
// backstackVisible: false,
})
}, },
toggleFavorite() { toggleFavorite() {
this.$store.dispatch("toggleFavorite", this.recipes.indexOf(this.recipe)) this.recipe.isFavorite
? Toast.makeText("Removed from Favorites").show()
: Toast.makeText("Added to Favorites").show()
this.$store.dispatch("toggleFavorite", this.recipeIndex)
},
toggleMustTry() {
this.recipe.tried
? Toast.makeText("Added to Must-Try").show()
: Toast.makeText("Removed from Must-Try").show()
this.$store.dispatch("toggleMustTry", this.recipeIndex)
}, },
getTime(time) { getTime(time) {
let t = time.split(":") let t = time.split(":")
@ -276,14 +308,13 @@ export default {
openURL(args, url) { openURL(args, url) {
utils.openUrl(url) utils.openUrl(url)
}, },
setCurrentComponent() {
this.releaseGlobalBackEvent()
this.busy = false
setTimeout((e) => {
this.$store.dispatch("setCurrentComponent", "ViewRecipe")
}, 500)
},
}, },
} }
</script> </script>
<style lang="scss" scoped>
ActionBar {
height: 128;
}
.actionBarContainer .bx {
margin-top: 4;
}
</style>

View file

@ -0,0 +1,64 @@
<template>
<Page>
<StackLayout class="dialogContainer">
<Label class="dialogTitle orkm" :text="title" />
<StackLayout class="actionsContainer">
<ListView
width="100%"
:height="height"
for="item in list"
@itemTap="tapAction"
separatorColor="transparent"
>
<v-template>
<StackLayout class="actionItem">
<Label :text="item" />
</StackLayout>
</v-template>
</ListView>
</StackLayout>
<GridLayout rows="auto" columns="auto, *, auto">
<Label
v-if="action"
col="0"
class="cancel orkm pull-left"
:text="action"
@tap="$modal.close(action)"
/>
<Label
col="2"
class="cancel orkm pull-right"
text="CANCEL"
@tap="$modal.close(false)"
/>
</GridLayout>
</StackLayout>
</Page>
</template>
<script>
export default {
props: ["title", "list", "height", "action"],
methods: {
tapAction({ item }) {
this.$modal.close(item)
},
},
}
</script>
<style lang="scss" scoped>
.dialogTitle {
padding: 24 24 12;
font-size: 20;
}
.actionItem {
width: 100%;
font-size: 16;
padding: 8 20;
}
.cancel {
padding: 24;
font-size: 12;
color: #ff7043;
}
</style>

View file

@ -0,0 +1,45 @@
<template>
<Page>
<StackLayout class="dialogContainer">
<Label class="dialogTitle orkm" :text="title" />
<Label class="dialogDescription" :text="description" textWrap="true" />
<StackLayout
orientation="horizontal"
class="actionsContainer"
horizontalAlignment="right"
>
<Label
class="action orkm pull-right"
:text="cancelButtonText"
@tap="$modal.close(false)"
/>
<Label
class="action orkm pull-right"
:text="okButtonText"
@tap="$modal.close(true)"
/>
</StackLayout>
</StackLayout>
</Page>
</template>
<script>
export default {
props: ["title", "description", "cancelButtonText", "okButtonText"],
}
</script>
<style lang="scss" scoped>
.dialogTitle {
padding: 24 24 12;
font-size: 20;
}
.dialogDescription {
font-size: 16;
padding: 0 24 16;
}
.action {
padding: 24 24 24 8;
font-size: 12;
color: #ff7043;
}
</style>

View file

@ -0,0 +1,49 @@
<template>
<Page>
<StackLayout class="dialogContainer">
<Label class="dialogTitle orkm" :text="title" />
<TextField
width="100%"
:hint="hint"
v-model="category"
autocapitalizationType="words"
/>
<StackLayout orientation="horizontal" horizontalAlignment="right">
<Label class="action orkm" text="CANCEL" @tap="$modal.close(false)" />
<Label
class="action orkm"
:text="action"
@tap="$modal.close(category)"
/>
</StackLayout>
</StackLayout>
</Page>
</template>
<script>
export default {
props: ["title", "hint", "action"],
data() {
return {
category: null,
}
},
}
</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

@ -1,55 +1,25 @@
// import VueDevtools from "nativescript-vue-devtools"
import Vue from "nativescript-vue" import Vue from "nativescript-vue"
import App from "./components/App" import App from "./components/App"
import RadListView from "nativescript-ui-listview/vue"
// Vue.registerElement(
// "RadListView",
// () => require("nativescript-ui-listview/vue").RadListView
// )
Vue.use(RadListView)
// Vue.use(VueDevtools)
// Vue.registerElement(
// "CheckBox",
// () => require("@nstudio/nativescript-checkbox").CheckBox,
// {
// model: {
// prop: "checked",
// event: "checkedChange",
// },
// }
// )
import DateTimePicker from "nativescript-datetimepicker/vue"
Vue.use(DateTimePicker)
// import VueDevtools from 'nativescript-vue-devtools'
// import { TNSFontIcon, fonticon } from 'nativescript-fonticon'
// TNSFontIcon.debug = true
// TNSFontIcon.paths = {
// // bx: './assets/boxicons.css',
// fa: './assets/fontawesome.css',
// }
// TNSFontIcon.loadCss()
// Vue.filter('fonticon', fonticon)
if (TNS_ENV !== "production") {
// Vue.use(VueDevtools)
}
import store from "./store" import store from "./store"
// Prints Vue logs when --env.production is *NOT* set while building import RadListView from "nativescript-ui-listview/vue"
Vue.config.silent = TNS_ENV === "production" Vue.use(RadListView)
import DateTimePicker from "nativescript-datetimepicker/vue"
Vue.use(DateTimePicker)
Vue.registerElement( Vue.registerElement(
"RadSideDrawer", "RadSideDrawer",
() => require("nativescript-ui-sidedrawer").RadSideDrawer () => require("nativescript-ui-sidedrawer").RadSideDrawer
) )
if (TNS_ENV !== "production") {
// Vue.use(VueDevtools)
}
// Prints Vue logs when --env.production is *NOT* set while building
Vue.config.silent = TNS_ENV === "production"
new Vue({ new Vue({
store, store,
render: (h) => h("frame", [h(App)]), render: (h) => h("frame", [h(App)]),

View file

@ -6,188 +6,178 @@ Vue.use(Vuex)
export default new Vuex.Store({ export default new Vuex.Store({
state: { state: {
recipes: [ recipes: [
{ // {
imageSrc: null, // imageSrc: null,
title: "Mediterranean Salad", // title: "Mediterranean Salad",
category: "Salads", // category: "Salads",
prepTime: "00:10", // prepTime: "12:25",
cookTime: "00:20", // cookTime: "00:30",
portionSize: 1, // portionSize: 1,
ingredients: [ // ingredients: [
{ // {
item: "Cucumbers, Seeded And Sliced", // item: "Cucumbers, Seeded And Sliced",
quantity: 3, // quantity: 3,
unit: null, // unit: "unit",
}, // },
{ // {
item: "Crumbled Feta Cheese", // item: "Crumbled Feta Cheese",
quantity: 1.5, // quantity: 1.5,
unit: "cup", // unit: "cup",
}, // },
{ // {
item: "Black Olives, Pitted And Sliced", // item: "Black Olives, Pitted And Sliced",
quantity: 1, // quantity: 1,
unit: "cup", // unit: "cup",
}, // },
{ // {
item: "Diced Roma Tomatoes", // item: "Diced Roma Tomatoes",
quantity: 3, // quantity: 3,
unit: "cup", // unit: "cup",
}, // },
{ // {
item: "Diced Oil Packed Sun Dried Tomatoes, Drained, Oil Reserved", // item: "Diced Oil Packed Sun Dried Tomatoes, Drained, Oil Reserved",
quantity: 0.3, // quantity: 0.3,
unit: "cup", // unit: "cup",
}, // },
{ // {
item: "Onion, Sliced", // item: "Onion, Sliced",
quantity: 1.5, // quantity: 1.5,
unit: null, // unit: "unit",
}, // },
{ // {
item: "Cucumbers, Seeded And Sliced", // item: "Cucumbers, Seeded And Sliced",
quantity: 3, // quantity: 3,
unit: null, // unit: "unit",
}, // },
{ // {
item: "Crumbled Feta Cheese", // item: "Crumbled Feta Cheese",
quantity: 1.5, // quantity: 1.5,
unit: "cup", // unit: "cup",
}, // },
{ // {
item: "Black Olives, Pitted And Sliced", // item: "Black Olives, Pitted And Sliced",
quantity: 1, // quantity: 1,
unit: "cup", // unit: "cup",
}, // },
{ // {
item: "Diced Roma Tomatoes", // item: "Diced Roma Tomatoes",
quantity: 3, // quantity: 3,
unit: "cup", // unit: "cup",
}, // },
{ // {
item: "Diced Oil Packed Sun Dried Tomatoes, Drained, Oil Reserved", // item: "Diced Oil Packed Sun Dried Tomatoes, Drained, Oil Reserved",
quantity: 0.3, // quantity: 0.3,
unit: "cup", // unit: "cup",
}, // },
{ // {
item: "Onion, Sliced", // item: "Onion, Sliced",
quantity: 1.5, // quantity: 1.5,
unit: null, // unit: "unit",
}, // },
{ // {
item: "Cucumbers, Seeded And Sliced", // item: "Cucumbers, Seeded And Sliced",
quantity: 3, // quantity: 3,
unit: null, // unit: "unit",
}, // },
{ // {
item: "Crumbled Feta Cheese", // item: "Crumbled Feta Cheese",
quantity: 1.5, // quantity: 1.5,
unit: "cup", // unit: "cup",
}, // },
{ // {
item: "Black Olives, Pitted And Sliced", // item: "Black Olives, Pitted And Sliced",
quantity: 1, // quantity: 1,
unit: "cup", // unit: "cup",
}, // },
{ // {
item: "Diced Roma Tomatoes", // item: "Diced Roma Tomatoes",
quantity: 3, // quantity: 3,
unit: "cup", // unit: "cup",
}, // },
{ // {
item: "Diced Oil Packed Sun Dried Tomatoes, Drained, Oil Reserved", // item: "Diced Oil Packed Sun Dried Tomatoes, Drained, Oil Reserved",
quantity: 0.3, // quantity: 0.3,
unit: "cup", // unit: "cup",
}, // },
{ // {
item: "Onion, Sliced", // item: "Onion, Sliced",
quantity: 1.5, // quantity: 1.5,
unit: null, // unit: "unit",
}, // },
], // ],
instructions: [ // 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.", // "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. 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. 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.",
"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.",
"Chill until serving.", // "Chill until serving.",
"Chill until serving.", // "Chill until serving.",
"Chill until serving.", // "Chill until serving.",
"Chill until serving.", // "Chill until serving.",
], // ],
notes: [ // 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.", // "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: [ // 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/",
"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, // isFavorite: true,
}, // tried: false,
{ // lastModified: "2020-10-18T17:37:51.798Z",
imageSrc: null, // },
title: "Fresh Tomato Sauce", // {
category: "Sauces", // imageSrc: null,
prepTime: "00:20", // title: "Fresh Tomato Sauce",
cookTime: "00:25", // category: "Sauces",
portionSize: 1, // prepTime: "00:45",
ingredients: [ // cookTime: "00:35",
{ // portionSize: 1,
item: null, // ingredients: [],
quantity: null, // instructions: [],
unit: null, // notes: [],
}, // references: [],
], // isFavorite: true,
instructions: [""], // tried: true,
notes: [""], // lastModified: "2020-10-15T17:37:51.798Z",
references: [""], // },
isFavorite: true, // {
}, // imageSrc: null,
{ // title: "Creamy Mushroom Herb Pasta",
imageSrc: null, // category: "Lunch",
title: "Creamy Mushroom Herb Pasta", // prepTime: "00:10",
category: "Lunch", // cookTime: "00:15",
prepTime: "00:45", // portionSize: 1,
cookTime: "00:25", // ingredients: [],
portionSize: 1, // instructions: [],
ingredients: [ // notes: [],
{ // references: [],
item: null, // isFavorite: false,
quantity: null, // tried: false,
unit: null, // lastModified: "2020-10-12T17:37:51.798Z",
}, // },
], // {
instructions: [""], // imageSrc: null,
notes: [""], // title: "Grilled Cheese Sandwich",
references: [""], // category: "Lunch",
isFavorite: false, // prepTime: "00:50",
}, // cookTime: "00:12",
{ // portionSize: 1,
imageSrc: null, // ingredients: [],
title: "Grilled Cheese Sandwich", // instructions: [],
category: "Lunch", // notes: [],
prepTime: "00:20", // references: [],
cookTime: "00:10", // isFavorite: false,
portionSize: 1, // tried: true,
ingredients: [ // lastModified: "2020-10-03T17:37:51.798Z",
{ // },
item: null,
quantity: null,
unit: null,
},
],
instructions: [""],
notes: [""],
references: [""],
isFavorite: false,
},
], ],
viewIsScrolled: false, viewIsScrolled: false,
icon: { icon: {
@ -202,7 +192,7 @@ export default new Vuex.Store({
sort: "\ueb2b", sort: "\ueb2b",
plus: "\ueb89", plus: "\ueb89",
close: "\uec4e", close: "\uec4e",
dish: "\uea71", image: "\ueae9",
back: "\ue988", back: "\ue988",
save: "\uee48", save: "\uee48",
camera: "\uecc2", camera: "\uecc2",
@ -216,22 +206,127 @@ export default new Vuex.Store({
file: "\ued60", file: "\ued60",
user: "\uee8e", user: "\uee8e",
trash: "\uee83", trash: "\uee83",
donate: "\ued41",
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: { mutations: {
addRecipe(state, recipe) { addRecipe(state, recipe) {
state.recipes.push(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) { toggleFavorite(state, index) {
state.recipes[index].isFavorite = !state.recipes[index].isFavorite 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
}
})
}
},
}, },
actions: { actions: {
addRecipe({ commit }, recipe) { addRecipe({ commit }, recipe) {
commit("addRecipe", recipe) commit("addRecipe", recipe)
}, },
addCategory({ commit }, category) {
commit("addCategory", category)
},
overwriteRecipe({ commit }, updatedRecipe) {
commit("overwriteRecipe", updatedRecipe)
},
deleteRecipe({ commit }, index) {
commit("deleteRecipe", index)
},
toggleFavorite({ commit }, index) { toggleFavorite({ commit }, index) {
commit("toggleFavorite", index) commit("toggleFavorite", index)
}, },
toggleMustTry({ commit }, index) {
commit("toggleMustTry", index)
},
setCurrentComponent({ commit }, comp) {
commit("setCurrentComponent", comp)
},
renameCategory({ commit }, category) {
commit("renameCategory", category)
},
}, },
}) })

1022
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -19,20 +19,15 @@
}, },
"dependencies": { "dependencies": {
"@nativescript/theme": "^2.2.1", "@nativescript/theme": "^2.2.1",
"@nstudio/nativescript-checkbox": "^1.0.0",
"@vue/devtools": "^5.3.3",
"nativescript-camera": "^4.5.0", "nativescript-camera": "^4.5.0",
"nativescript-couchbase-plugin": "^0.9.6",
"nativescript-datetimepicker": "^1.2.3", "nativescript-datetimepicker": "^1.2.3",
"nativescript-fonticon": "^2.0.2",
"nativescript-mediafilepicker": "^4.0.0", "nativescript-mediafilepicker": "^4.0.0",
"nativescript-menu": "^1.1.6",
"nativescript-permissions": "^1.3.9", "nativescript-permissions": "^1.3.9",
"nativescript-socketio": "^3.3.1", "nativescript-toast": "^2.0.0",
"nativescript-toasty": "^3.0.0-alpha.2",
"nativescript-ui-listview": "^8.2.0", "nativescript-ui-listview": "^8.2.0",
"nativescript-ui-sidedrawer": "^8.0.1", "nativescript-ui-sidedrawer": "^8.0.1",
"nativescript-vue": "^2.6.1", "nativescript-vue": "^2.6.1",
"nativescript-vue-devtools": "^1.4.0",
"tns-core-modules": "^6.5.1", "tns-core-modules": "^6.5.1",
"vuex": "^3.3.0" "vuex": "^3.3.0"
}, },