added mealPlanner

This commit is contained in:
Vishnu Raghav B 2020-11-23 15:19:58 +05:30
parent 4621821597
commit ef215c7321
81 changed files with 760 additions and 965 deletions

View file

@ -10,7 +10,7 @@
<uses-permission android:name="android.permission.INTERNET" tools:node="remove" />
<uses-permission android:name="android.permission.RECORD_AUDIO" tools:node="remove" />
<application android:name="com.tns.NativeScriptApplication" android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:hardwareAccelerated="true" android:largeHeap="true" android:theme="@style/AppTheme" android:requestLegacyExternalStorage="true">
<activity android:name="com.tns.NativeScriptActivity" android:label="@string/title_activity_kimera" android:screenOrientation="portrait" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout|locale|uiMode" android:theme="@style/LaunchScreenTheme" android:windowSoftInputMode="adjustResize">
<activity android:name="com.tns.NativeScriptActivity" android:label="@string/title_activity_kimera" android:screenOrientation="userPortrait" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout|locale|uiMode" android:theme="@style/LaunchScreenTheme" android:windowSoftInputMode="adjustResize">
<meta-data android:name="SET_THEME_ON_LAUNCH" android:resource="@style/AppTheme" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />

View file

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

View file

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View file

Before

Width:  |  Height:  |  Size: 687 B

After

Width:  |  Height:  |  Size: 687 B

View file

Before

Width:  |  Height:  |  Size: 567 B

After

Width:  |  Height:  |  Size: 567 B

View file

Before

Width:  |  Height:  |  Size: 339 B

After

Width:  |  Height:  |  Size: 339 B

View file

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View file

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

View file

Before

Width:  |  Height:  |  Size: 517 B

After

Width:  |  Height:  |  Size: 517 B

View file

Before

Width:  |  Height:  |  Size: 197 B

After

Width:  |  Height:  |  Size: 197 B

View file

Before

Width:  |  Height:  |  Size: 519 B

After

Width:  |  Height:  |  Size: 519 B

View file

Before

Width:  |  Height:  |  Size: 390 B

After

Width:  |  Height:  |  Size: 390 B

View file

Before

Width:  |  Height:  |  Size: 336 B

After

Width:  |  Height:  |  Size: 336 B

View file

Before

Width:  |  Height:  |  Size: 229 B

After

Width:  |  Height:  |  Size: 229 B

View file

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View file

Before

Width:  |  Height:  |  Size: 302 B

After

Width:  |  Height:  |  Size: 302 B

View file

Before

Width:  |  Height:  |  Size: 173 B

After

Width:  |  Height:  |  Size: 173 B

View file

Before

Width:  |  Height:  |  Size: 312 B

After

Width:  |  Height:  |  Size: 312 B

View file

Before

Width:  |  Height:  |  Size: 345 B

After

Width:  |  Height:  |  Size: 345 B

View file

Before

Width:  |  Height:  |  Size: 324 B

After

Width:  |  Height:  |  Size: 324 B

View file

Before

Width:  |  Height:  |  Size: 198 B

After

Width:  |  Height:  |  Size: 198 B

View file

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

Before

Width:  |  Height:  |  Size: 300 B

After

Width:  |  Height:  |  Size: 300 B

View file

Before

Width:  |  Height:  |  Size: 161 B

After

Width:  |  Height:  |  Size: 161 B

View file

Before

Width:  |  Height:  |  Size: 341 B

After

Width:  |  Height:  |  Size: 341 B

View file

Before

Width:  |  Height:  |  Size: 626 B

After

Width:  |  Height:  |  Size: 626 B

View file

Before

Width:  |  Height:  |  Size: 547 B

After

Width:  |  Height:  |  Size: 547 B

View file

Before

Width:  |  Height:  |  Size: 266 B

After

Width:  |  Height:  |  Size: 266 B

View file

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

View file

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

View file

Before

Width:  |  Height:  |  Size: 437 B

After

Width:  |  Height:  |  Size: 437 B

View file

Before

Width:  |  Height:  |  Size: 165 B

After

Width:  |  Height:  |  Size: 165 B

View file

Before

Width:  |  Height:  |  Size: 550 B

After

Width:  |  Height:  |  Size: 550 B

View file

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

Before

Width:  |  Height:  |  Size: 969 B

After

Width:  |  Height:  |  Size: 969 B

View file

Before

Width:  |  Height:  |  Size: 434 B

After

Width:  |  Height:  |  Size: 434 B

View file

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

View file

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View file

Before

Width:  |  Height:  |  Size: 797 B

After

Width:  |  Height:  |  Size: 797 B

View file

Before

Width:  |  Height:  |  Size: 165 B

After

Width:  |  Height:  |  Size: 165 B

View file

Before

Width:  |  Height:  |  Size: 930 B

After

Width:  |  Height:  |  Size: 930 B

View file

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

Before

Width:  |  Height:  |  Size: 818 B

After

Width:  |  Height:  |  Size: 818 B

View file

Before

Width:  |  Height:  |  Size: 449 B

After

Width:  |  Height:  |  Size: 449 B

View file

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View file

Before

Width:  |  Height:  |  Size: 697 B

After

Width:  |  Height:  |  Size: 697 B

View file

Before

Width:  |  Height:  |  Size: 171 B

After

Width:  |  Height:  |  Size: 171 B

View file

Before

Width:  |  Height:  |  Size: 928 B

After

Width:  |  Height:  |  Size: 928 B

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ns_primary">
#fafafa
#ff5200
</color>
<color name="ns_primaryDark">
#ff5200

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ns_primary">
#f1f3f5
#ff5200
</color>
<color name="ns_primaryDark">
#ff5200

View file

@ -57,9 +57,6 @@
<item name="contentInsetEnd">
0dp
</item>
<item name="android:divider">
#ff0000
</item>
<item name="android:background">
@color/ns_primary
</item>
@ -77,8 +74,10 @@
<item name="searchHintIcon">
@null
</item>
<!-- <item name="closeIcon">
@null
</item> -->
<!--
<item name="closeIcon">
@null
</item>
-->
</style>
</resources>

View file

@ -6,7 +6,7 @@ $gray1: #f1f3f5;
$gray2: #e9ecef;
$gray3: #dee2e6;
$gray4: #ced4da;
$gray5: #adb5bd; // rgb(173,181,189)
$gray5: #adb5bd;
$gray6: #868e96;
$gray7: #495057;
$gray8: #343a40;
@ -255,7 +255,7 @@ ActionBar {
}
// prettier-ignore
Label {
padding: 0 16 0 0;
padding: 2 16 0 0;
font-size: 16;
vertical-alignment: center;
&.bx{
@ -544,14 +544,13 @@ TextField.combinationToken {
}
// -----------------------------
// MEAL PLANNER
.mealPlanner {
padding: 16 16 128;
.dayPlan {
padding: 0;
width: 100%;
.dayContainer {
padding: 8 0;
.plansContainer {
padding: 8 4;
color: $gray9;
&.breakfast {
border-radius: 4 4 0 0;
background: $breakfast;
}
&.lunch {
@ -561,17 +560,16 @@ TextField.combinationToken {
background: $dinner;
}
&.snacks {
border-radius: 0 0 4 4;
background: $snacks;
}
.periodLabel {
text-transform: uppercase;
vertical-alignment: center;
font-size: 16;
font-size: 14;
padding: 0 0 0 16;
}
.recipes {
margin: 8 8 0;
margin: 4 8 4;
.recipeTitle {
font-size: 14;
padding: 6 8;
@ -591,6 +589,7 @@ TextField.combinationToken {
// -----------------------------
// DIALOGS
.dialogContainer {
max-width: 480;
width: 100%;
color: $gray9;
background: $gray1;
@ -600,6 +599,7 @@ TextField.combinationToken {
background: $gray9;
}
.dialogTitle {
line-height: 6;
padding: 24 24 16;
font-size: 20;
}

View file

@ -13,7 +13,7 @@
<Label class="title orkm" text="About" col="1" />
</GridLayout>
</ActionBar>
<ScrollView scrollBarIndicatorVisible="false" @scroll="onScroll">
<ScrollView scrollBarIndicatorVisible="true" @scroll="onScroll">
<StackLayout class="main-container">
<StackLayout
horizontalAlignment="center"
@ -64,7 +64,7 @@
@tap="openURL('https://www.vishnuraghav.com')"
/>
<Label col="0" class="bx" :text="icon.user" />
<Label verticalAlignment="center" col="1" text="Vishnu Raghav" />
<Label verticalAlignment="center" col="1" text="Vishnu Raghav B" />
</GridLayout>
<GridLayout columns="auto, *" class="option">
<MDRipple
@ -90,8 +90,10 @@
<script>
import { Application, Utils } from "@nativescript/core"
import { mapActions, mapState } from "vuex"
import * as utils from "~/shared/utils"
export default {
props: ["showDrawer", "title"],
computed: {
...mapState(["icon", "currentComponent"]),
getVersion() {
@ -112,6 +114,9 @@ export default {
this.setCurrentComponentAction("About")
},
// HELPERS
showDrawer() {
utils.showDrawer()
},
onScroll(args) {
args.scrollY
? (this.viewIsScrolled = true)

View file

@ -1,14 +1,16 @@
<template>
<Page
@loaded="onPageLoad"
@unloaded="onPageUnload"
actionBarHidden="true"
:androidStatusBarBackground="appTheme == 'Light' ? '#f1f3f5' : '#212529'"
>
<RadSideDrawer
ref="drawer"
allowEdgeSwipe="true"
drawerContentSize="270"
showOverNavigation="true"
ref="drawer"
id="sideDrawer"
drawerContentSize="270"
gesturesEnabled="true"
drawerTransition="SlideInOnTopTransition"
>
@ -44,8 +46,9 @@
<MDRipple
row="0"
colSpan="3"
@tap="navigateTo(mealPlanner, true, false)"
@tap="navigateTo(MealPlanner, true, false)"
/>
<Label col="0" row="0" class="bx" :text="icon.calendar" />
<Label col="2" row="0" text="Meal Planner" />
</GridLayout>
@ -120,21 +123,18 @@
</GridLayout>
</StackLayout>
</GridLayout>
<GridLayout ~mainContent rows="*" columns="*">
<Frame row="0" col="0" ref="mainFrame" id="main-frame">
<!-- Home -->
<EnRecipes
ref="enrecipes"
:filterFavorites="filterFavorites"
:filterTrylater="filterTrylater"
:selectedCategory="selectedCategory"
:showDrawer="showDrawer"
:hijackGlobalBackEvent="hijackGlobalBackEvent"
:releaseGlobalBackEvent="releaseGlobalBackEvent"
:openAppSettingsPage="openAppSettingsPage"
/>
</Frame>
</GridLayout>
<Frame ~mainContent id="main-frame">
<!-- Home -->
<EnRecipes
ref="enrecipes"
:filterFavorites="filterFavorites"
:filterTrylater="filterTrylater"
:selectedCategory="selectedCategory"
:closeDrawer="closeDrawer"
:hijackGlobalBackEvent="hijackGlobalBackEvent"
:releaseGlobalBackEvent="releaseGlobalBackEvent"
/>
</Frame>
</RadSideDrawer>
</Page>
</template>
@ -153,22 +153,20 @@ import * as Toast from "nativescript-toast"
import * as application from "tns-core-modules/application"
import { mapActions, mapState } from "vuex"
import EnRecipes from "./EnRecipes.vue"
import MealPlanner from "./MealPlanner.vue"
import Settings from "./Settings.vue"
import About from "./About.vue"
import EnRecipes from "./EnRecipes"
import MealPlanner from "./MealPlanner"
import Settings from "./Settings"
import About from "./About"
import PromptDialog from "./modal/PromptDialog.vue"
import PromptDialog from "./modal/PromptDialog"
export default {
components: {
EnRecipes,
},
data() {
return {
selectedCategory: null,
filterFavorites: false,
filterTrylater: false,
MealPlanner: MealPlanner,
topmenu: [
{
title: "Home",
@ -200,15 +198,19 @@ export default {
],
editCategory: false,
appTheme: "Light",
mealPlanner: MealPlanner,
}
},
components: {
EnRecipes,
MealPlanner,
},
computed: {
...mapState([
"icon",
"recipes",
"categories",
"yieldUnits",
"mealPlans",
"currentComponent",
]),
categoriesWithRecipes() {
@ -224,6 +226,7 @@ export default {
"initializeRecipes",
"initializeCategories",
"initializeYieldUnits",
"initializeMealPlans",
"renameCategoryAction",
]),
onPageLoad() {
@ -235,6 +238,9 @@ export default {
// window.setNavigationBarColor(new Color("#e0e0e0").android)
}
},
onPageUnload() {
// this.releaseGlobalBackEvent()
},
// HELPERS
toggleCatEdit() {
@ -268,44 +274,7 @@ export default {
this.selectedCategory = e.item
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())
},
openAppSettingsPage() {
const intent = new android.content.Intent(
android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS
)
intent.addCategory(android.content.Intent.CATEGORY_DEFAULT)
intent.setData(
android.net.Uri.parse(
"package:" + Application.android.context.getPackageName()
)
)
Application.android.foregroundActivity.startActivity(intent)
},
showDrawer() {
this.$refs.drawer.nativeView.showDrawer()
},
closeDrawer() {
this.$refs.drawer.nativeView.closeDrawer()
},
@ -358,13 +327,6 @@ export default {
if (isTrueComponent) {
this.$navigateTo(to, {
frame: "main-frame",
props: {
showDrawer: this.showDrawer,
restartApp: this.restartApp,
hijackGlobalBackEvent: this.hijackGlobalBackEvent,
releaseGlobalBackEvent: this.releaseGlobalBackEvent,
openAppSettingsPage: this.openAppSettingsPage,
},
backstackVisible: false,
})
this.closeDrawer()
@ -391,9 +353,10 @@ export default {
setTimeout((e) => {
Theme.setMode(Theme[this.appTheme])
}, 10)
this.initializeRecipes()
this.initializeCategories()
this.initializeYieldUnits()
if (!this.recipes.length) this.initializeRecipes()
if (!this.categories.length) this.initializeCategories()
if (!this.yieldUnits.length) this.initializeYieldUnits()
if (!this.mealPlans.length) this.initializeMealPlans()
},
}
</script>

View file

@ -13,20 +13,20 @@
<Label class="title orkm" :text="title" col="1" />
<MDButton
variant="text"
v-if="hasChanges && !imageLoading"
v-if="hasChanges && !saving"
class="bx"
:text="icon.save"
col="2"
@tap="saveOperation"
/>
<MDActivityIndicator col="2" v-if="imageLoading" :busy="imageLoading" />
<MDActivityIndicator col="2" v-if="saving" :busy="saving" />
</GridLayout>
</ActionBar>
<ScrollView
width="100%"
height="100%"
@scroll="onScroll"
scrollBarIndicatorVisible="false"
scrollBarIndicatorVisible="true"
>
<StackLayout width="100%" padding="0 0 128">
<AbsoluteLayout>
@ -257,7 +257,7 @@
<StackLayout class="hr" margin="24 16"></StackLayout>
</StackLayout>
<StackLayout margin="0 16 24" v-if="recipes.length">
<StackLayout margin="0 16 24">
<Label text="Combinations" class="sectionTitle" />
<GridLayout
columns="*,8,auto"
@ -316,14 +316,10 @@ import ConfirmDialog from "./modal/ConfirmDialog.vue"
import PromptDialog from "./modal/PromptDialog.vue"
import ListPicker from "./modal/ListPicker.vue"
import * as utils from "~/shared/utils"
export default {
props: [
"recipeID",
"selectedCategory",
"openAppSettingsPage",
"filterFavorites",
"filterTrylater",
],
props: ["recipeID", "selectedCategory", "filterFavorites", "filterTrylater"],
data() {
return {
title: "New recipe",
@ -343,7 +339,7 @@ export default {
references: [],
combinations: [],
isFavorite: false,
tried: false,
tried: true,
lastTried: null,
lastModified: null,
},
@ -352,7 +348,7 @@ export default {
modalOpen: false,
newRecipeID: null,
showFab: false,
imageLoading: false,
saving: false,
cacheImagePath: null,
unSyncCombinations: [],
}
@ -680,7 +676,7 @@ export default {
} else {
Permissions.check("photo").then((res) => {
res[0] !== "authorized"
? confirmation().then((e) => e && this.openAppSettingsPage())
? confirmation().then((e) => e && utils.openAppSettingsPage())
: action()
})
}
@ -771,7 +767,6 @@ export default {
...this.recipeContent.combinations,
this.recipeContent.id,
]
console.log(existingCombinations)
let filteredRecipes = this.recipes.filter(
(e) => !existingCombinations.includes(e.id)
)
@ -838,7 +833,7 @@ export default {
clearEmpty("references")
},
saveOperation() {
this.imageLoading = true
this.saving = true
this.clearEmptyFields()
this.recipeContent.lastModified = new Date()
if (this.cacheImagePath) {
@ -884,7 +879,7 @@ export default {
})
}
setTimeout(() => {
this.imageLoading = false
this.saving = false
}, 100)
this.$navigateBack()
},

View file

@ -237,15 +237,16 @@ import ViewRecipe from "./ViewRecipe.vue"
import ActionDialog from "./modal/ActionDialog.vue"
import ConfirmDialog from "./modal/ConfirmDialog.vue"
import * as utils from "~/shared/utils"
export default {
props: [
"filterFavorites",
"filterTrylater",
"closeDrawer",
"selectedCategory",
"showDrawer",
"hijackGlobalBackEvent",
"releaseGlobalBackEvent",
"openAppSettingsPage",
],
components: {
EditRecipe,
@ -301,6 +302,9 @@ export default {
},
// HELPERS
showDrawer() {
utils.showDrawer()
},
openSearch() {
this.showSearch = true
this.showFAB = false
@ -355,6 +359,7 @@ export default {
},
searchBackEvent(args) {
args.cancel = true
this.closeDrawer()
this.closeSearch()
},
addRecipe() {
@ -363,7 +368,6 @@ export default {
this.$navigateTo(EditRecipe, {
props: {
selectedCategory: this.selectedCategory,
openAppSettingsPage: this.openAppSettingsPage,
filterFavorites: this.filterFavorites,
},
})
@ -371,16 +375,9 @@ export default {
viewRecipe(recipeID) {
this.showFAB = false
this.$navigateTo(ViewRecipe, {
// transition: {
// name: "fade",
// duration: 200,
// curve: "easeOut",
// },
props: {
filterTrylater: this.filterTrylater,
recipeID,
hijackGlobalBackEvent: this.hijackGlobalBackEvent,
releaseGlobalBackEvent: this.releaseGlobalBackEvent,
},
})
},

View file

@ -1,7 +1,7 @@
<template>
<Page @loaded="onPageLoad">
<ActionBar :flat="viewIsScrolled ? false : true">
<GridLayout rows="*" columns="auto, *">
<GridLayout rows="*" columns="auto, *, auto">
<MDButton
class="bx left"
variant="text"
@ -11,61 +11,97 @@
col="0"
/>
<Label class="title orkm" text="Meal Planner" col="1" />
<MDButton
class="bx left"
variant="text"
:text="icon.today"
automationText="today"
@tap="goToToday"
col="2"
/>
</GridLayout>
</ActionBar>
<ScrollView
width="100%"
height="100%"
scrollBarIndicatorVisible="false"
@scroll="onScroll"
>
<StackLayout class="mealPlanner">
<RadCalendar ref="calendar" @dateSelected="onDateSelected">
</RadCalendar>
<StackLayout
v-for="(meal, indexB) in mealTimes"
:key="'meal' + indexB"
class="dayContainer"
:class="meal"
>
<GridLayout columns="*, auto" class="header">
<Label col="0" class="periodLabel orkm" :text="meal" />
<MDButton
col="1"
variant="text"
class="bx addMeal"
:text="icon.plus"
/>
</GridLayout>
<GridLayout class="recipes" columns="*, auto">
<MDRipple />
<Label
verticalAlignment="center"
class="recipeTitle"
col="0"
text="getRecipeTitle(recipeID, indexA, meal)"
textWrap="true"
/>
<MDButton
variant="text"
col="1"
class="bx closeBtn"
:text="icon.close"
/>
</GridLayout>
<GridLayout rows="280, *">
<RadCalendar
class="orkm"
row="0"
ref="calendar"
locale="en-US"
@loaded="onCalendarLoad"
@dateSelected="onDateSelected"
:viewMode="viewMode"
:transitionMode="transitionMode"
:selectionMode="selectionMode"
:eventsViewMode="eventsViewMode"
:eventSource="getMealPlans"
></RadCalendar>
<ScrollView
row="1"
width="100%"
height="100%"
scrollBarIndicatorVisible="true"
>
<StackLayout class="dayPlan">
<StackLayout
v-for="(mealType, index) in mealTimes"
:key="'mealType' + index"
class="plansContainer"
:class="mealType"
>
<GridLayout columns="*, auto" class="header">
<Label col="0" class="periodLabel orkm" :text="mealType" />
<MDButton
col="1"
variant="text"
class="bx addMeal"
:text="icon.plus"
@tap="addRecipe(mealType)"
/>
</GridLayout>
<GridLayout
class="recipes"
columns="*, auto"
v-for="(recipeID, index) in getRecipes[mealType]"
:key="mealType + index"
>
<MDRipple @tap="viewRecipe(recipeID)" />
<Label
verticalAlignment="center"
class="recipeTitle"
col="0"
:text="getRecipeTitle(recipeID)"
textWrap="true"
/>
<MDButton
variant="text"
col="1"
class="bx closeBtn"
:text="icon.close"
@tap="removeRecipe(mealType, recipeID)"
/>
</GridLayout>
</StackLayout>
</StackLayout>
</StackLayout>
</ScrollView>
<!-- <GridLayout rows="*, auto, *, 88" columns="*" class="emptyStateContainer">
<StackLayout row="1" class="emptyState">
<Label class="title orkm" text="Coming soon!" textWrap="true" />
</StackLayout>
</GridLayout> -->
</ScrollView>
</GridLayout>
</Page>
</template>
<script>
import { ApplicationSettings, Color } from "@nativescript/core"
import { ApplicationSettings, Color, Page } from "@nativescript/core"
import {
CalendarViewMode,
CalendarTransitionMode,
CalendarSelectionMode,
CalendarMonthViewStyle,
CalendarSelectionShape,
DayCellStyle,
CalendarFontStyle,
CalendarCellAlignment,
CellStyle,
CalendarEventsViewMode,
CalendarEvent,
} from "nativescript-ui-calendar"
import { mapState, mapActions } from "vuex"
import ViewRecipe from "./ViewRecipe.vue"
@ -73,26 +109,224 @@ import ViewRecipe from "./ViewRecipe.vue"
import ActionDialogWithSearch from "./modal/ActionDialogWithSearch.vue"
import ConfirmDialog from "./modal/ConfirmDialog.vue"
import * as utils from "~/shared/utils"
export default {
props: ["showDrawer", "hijackGlobalBackEvent", "releaseGlobalBackEvent"],
data() {
return {
viewIsScrolled: false,
appTheme: "Light",
mealTimes: ["breakfast", "lunch", "dinner", "snacks"],
eventList: [],
selectedDayMealPlans: [],
viewMode: CalendarViewMode.Month,
transitionMode: CalendarTransitionMode.Slide,
selectionMode: CalendarSelectionMode.Single,
eventsViewMode: CalendarEventsViewMode.None,
color: {
white: new Color("#ffffff"),
gray1: new Color("#f1f3f5"),
gray2: new Color("#e9ecef"),
gray3: new Color("#dee2e6"),
gray4: new Color("#ced4da"),
gray5: new Color("#adb5bd"),
gray6: new Color("#868e96"),
gray7: new Color("#495057"),
gray8: new Color("#343a40"),
gray9: new Color("#212529"),
black: new Color("#111111"),
orange: new Color("#ff5200"),
breakfast: "#ffb180",
lunch: "#ceff80",
dinner: "#80ceff",
snacks: "#b180ff",
},
appFontRegular: "Orkney-Regular",
appFontMedium: "Orkney-Medium",
selectedDate: null,
}
},
computed: {
...mapState(["icon", "recipes"]),
...mapState(["icon", "recipes", "mealPlans"]),
isLightMode() {
return this.appTheme === "Light"
},
monthViewStyle() {
const monthViewStyle = new CalendarMonthViewStyle()
monthViewStyle.backgroundColor = this.isLightMode
? this.color.gray1
: this.color.gray9
monthViewStyle.showTitle = true
monthViewStyle.showWeekNumbers = false
monthViewStyle.showDayNames = true
const titleCellStyle = new DayCellStyle()
titleCellStyle.cellBackgroundColor = this.isLightMode
? this.color.gray2
: this.color.black
titleCellStyle.cellBorderWidth = 1
titleCellStyle.cellBorderColor = this.isLightMode
? this.color.gray2
: this.color.black
titleCellStyle.cellTextSize = 16
titleCellStyle.cellTextColor = this.isLightMode
? this.color.gray9
: this.color.gray1
titleCellStyle.cellTextFontName = this.appFontMedium
monthViewStyle.titleCellStyle = titleCellStyle
const dayNameCellStyle = new CellStyle()
dayNameCellStyle.cellBackgroundColor = this.isLightMode
? this.color.gray2
: this.color.black
dayNameCellStyle.cellTextColor = this.isLightMode
? this.color.gray9
: this.color.gray1
dayNameCellStyle.cellBorderWidth = 1
dayNameCellStyle.cellBorderColor = this.isLightMode
? this.color.gray2
: this.color.black
dayNameCellStyle.cellTextSize = 12
dayNameCellStyle.cellAlignment = CalendarCellAlignment.Center
dayNameCellStyle.cellTextFontName = this.appFontMedium
monthViewStyle.dayNameCellStyle = dayNameCellStyle
const dayCellStyle = new DayCellStyle()
dayCellStyle.showEventsText = false
dayCellStyle.eventTextColor = this.color.orange
dayCellStyle.eventFontName = this.appFontRegular
dayCellStyle.eventFontStyle = CalendarFontStyle.Bold
dayCellStyle.eventTextSize = 8
dayCellStyle.cellTextSize = 16
dayCellStyle.cellTextColor = this.isLightMode
? this.color.gray9
: this.color.gray2
dayCellStyle.cellAlignment = CalendarCellAlignment.Bottom
dayCellStyle.cellBackgroundColor = this.isLightMode
? this.color.gray1
: this.color.gray9
dayCellStyle.cellTextFontName = this.appFontRegular
dayCellStyle.cellBorderWidth = 1
dayCellStyle.cellBorderColor = this.isLightMode
? this.color.gray2
: this.color.black
monthViewStyle.dayCellStyle = dayCellStyle
const todayCellStyle = new DayCellStyle()
todayCellStyle.cellBackgroundColor = this.isLightMode
? this.color.gray1
: this.color.gray9
todayCellStyle.cellTextColor = this.color.orange
todayCellStyle.cellBorderWidth = 1
todayCellStyle.cellTextFontName = this.appFontMedium
todayCellStyle.cellTextFontStyle = CalendarFontStyle.Bold
todayCellStyle.cellTextSize = 16
todayCellStyle.cellAlignment = CalendarCellAlignment.Bottom
todayCellStyle.cellBorderColor = this.isLightMode
? this.color.gray2
: this.color.black
monthViewStyle.todayCellStyle = todayCellStyle
const selectedCellStyle = new DayCellStyle()
selectedCellStyle.eventTextSize = 1
selectedCellStyle.cellAlignment = CalendarCellAlignment.Bottom
selectedCellStyle.cellBackgroundColor = this.isLightMode
? this.color.white
: this.color.gray8
selectedCellStyle.cellBorderWidth = 1
selectedCellStyle.cellBorderColor = this.color.orange
selectedCellStyle.cellTextColor = this.isLightMode
? this.color.gray9
: this.color.gray1
selectedCellStyle.cellTextFontName = this.appFontMedium
selectedCellStyle.cellTextFontStyle = CalendarFontStyle.Bold
selectedCellStyle.cellTextSize = 16
monthViewStyle.selectedDayCellStyle = selectedCellStyle
return monthViewStyle
},
getRecipes() {
if (this.selectedDayMealPlans.length) {
return this.selectedDayMealPlans.reduce((acc, e) => {
switch (e.startDate.getHours()) {
case 0: //breakfast
acc["breakfast"] = [...(acc["breakfast"] || []), e.title]
break
case 5: //lunch
acc["lunch"] = [...(acc["lunch"] || []), e.title]
break
case 10: //dinner
acc["dinner"] = [...(acc["dinner"] || []), e.title]
break
case 15: //snacks
acc["snacks"] = [...(acc["snacks"] || []), e.title]
break
default:
break
}
return acc
}, {})
} else return 0
},
getMealPlans() {
const getDate = (date) => {
let d = new Date(date)
let result = new Date(
d.getFullYear(),
d.getMonth(),
d.getDate(),
d.getHours()
)
return result
}
let events = []
this.mealPlans.forEach((plan) => {
let e = new CalendarEvent(
plan.title,
getDate(plan.startDate),
getDate(plan.endDate),
false,
new Color(plan.eventColor)
)
events = [...events, e]
})
return events
},
},
methods: {
...mapActions(["setCurrentComponentAction"]),
onPageLoad() {
...mapActions([
"setCurrentComponentAction",
"initializeMealPlans",
"addMealPlanAction",
"deleteMealPlanAction",
]),
onPageLoad(args) {
this.setCurrentComponentAction("MealPlanner")
this.releaseGlobalBackEvent()
},
onCalendarLoad(args) {
args.object.monthViewStyle = this.monthViewStyle
args.object.android
.getGestureManager()
.setDoubleTapToChangeDisplayMode(false)
args.object.android
.getGestureManager()
.setPinchCloseToChangeDisplayMode(false)
if (args.object.selectedDate == null)
args.object.selectedDate = new Date()
if (args.object.nativeView.getEventAdapter()) {
args.object.nativeView
.getEventAdapter()
.getRenderer()
.setEventRenderMode(
com.telerik.widget.calendar.events.EventRenderMode.Shape
)
}
},
// HELPERS
showDrawer() {
utils.showDrawer()
},
onScroll(args) {
args.scrollY
? (this.viewIsScrolled = true)
@ -109,58 +343,134 @@ export default {
return date.toDateString().slice(0, -5)
},
getRecipeTitle(id) {
return this.recipes.filter((e) => e.id === id)[0].title
let recipe = this.recipes.filter((e) => e.id === id)[0]
return recipe ? recipe.title : "[Recipe not found]"
},
// NAVIGATION HANDLERS
viewRecipe(recipeID) {
this.$navigateTo(ViewRecipe, {
props: {
filterTrylater: true,
recipeID,
hijackGlobalBackEvent: this.hijackGlobalBackEvent,
releaseGlobalBackEvent: this.releaseGlobalBackEvent,
},
})
let recipe = this.recipes.filter((e) => e.id === recipeID)[0]
if (recipe) {
this.$navigateTo(ViewRecipe, {
props: {
filterTrylater: true,
recipeID,
},
})
}
},
// DATA HANDLERS
addRecipe(indexA, meal) {
let existingRecipes = [...this.meals[indexA][meal]]
let filteredRecipes = this.recipes.filter(
(e) => !existingRecipes.includes(e.id)
addRecipe(mealType) {
let filteredRecipes = this.recipes.filter((e) =>
this.getRecipes[mealType]
? !this.getRecipes[mealType].includes(e.id)
: true
)
this.$showModal(ActionDialogWithSearch, {
props: {
title: "Select a recipe",
recipes: filteredRecipes,
},
}).then((res) => {
res && this.meals[indexA][meal].push(res)
}).then((recipeID) => {
recipeID && this.newEvent(recipeID, mealType)
})
},
removeRecipeConfirm() {
removeRecipeConfirm(mealType) {
return this.$showModal(ConfirmDialog, {
props: {
title: `Remove recipe`,
title: `Remove recipe from ${mealType}`,
cancelButtonText: "CANCEL",
okButtonText: "REMOVE",
},
})
},
removeRecipe(indexA, meal, indexC) {
this.removeRecipeConfirm().then((res) => {
res && this.meals[indexA][meal].splice(indexC, 1)
removeRecipe(mealType, recipeID) {
let startHour = {
breakfast: 0,
lunch: 5,
dinner: 10,
snacks: 15,
}
this.removeRecipeConfirm(mealType).then((res) => {
if (res) {
let actualMealPlan = this.selectedDayMealPlans.filter(
(e) =>
e.startDate.getHours() === startHour[mealType] &&
e.title === recipeID
)[0]
let mealPlan = {
title: actualMealPlan.title,
startDate: actualMealPlan.startDate,
}
this.deleteMealPlanAction(mealPlan)
this.updateSelectedDatePlans()
}
})
},
// CALENDAR
onDateSelected() {
console.log("hello")
updateSelectedDatePlans() {
let date = new Date(this.selectedDate)
setTimeout(() => {
this.selectedDayMealPlans = this.$refs.calendar.nativeView.getEventsForDate(
date
)
}, 100)
},
onDateSelected(args) {
this.selectedDate = args.date
this.selectedDayMealPlans = args.object.getEventsForDate(args.date)
},
newEvent(recipeID, mealType) {
let date = new Date(this.selectedDate)
const selectedDate = () => {
return {
y: date.getFullYear(),
m: date.getMonth(),
d: date.getDate(),
}
}
let { y, m, d } = selectedDate()
let mealTime = {
breakfast: {
start: new Date(y, m, d, 0),
end: new Date(y, m, d, 4),
},
lunch: {
start: new Date(y, m, d, 5),
end: new Date(y, m, d, 9),
},
dinner: {
start: new Date(y, m, d, 10),
end: new Date(y, m, d, 14),
},
snacks: {
start: new Date(y, m, d, 15),
end: new Date(y, m, d, 19),
},
}
let event = new CalendarEvent(
recipeID,
mealTime[mealType].start,
mealTime[mealType].end,
false,
new Color(this.color[mealType])
)
this.addMealPlanAction({ event, eventColor: this.color[mealType] })
this.updateSelectedDatePlans()
},
goToToday() {
const date = new Date()
this.$refs.calendar.goToDate(date)
this.$refs.calendar.nativeView.selectedDate = date
},
},
created() {
this.appTheme = ApplicationSettings.getString("appTheme", "Light")
let d = new Date()
d.setHours(0, 0, 0)
this.selectedDate = d
},
}
</script>

View file

@ -13,7 +13,7 @@
<Label class="title orkm" text="Settings" col="1" />
</GridLayout>
</ActionBar>
<ScrollView scrollBarIndicatorVisible="false" @scroll="onScroll">
<ScrollView scrollBarIndicatorVisible="true" @scroll="onScroll">
<StackLayout class="main-container">
<Label text="Interface" class="group-header orkm" />
<GridLayout columns="auto, *" class="option">
@ -26,7 +26,7 @@
/>
<StackLayout col="1">
<Label text="Theme" />
<Label :text="appTheme" class="info" textWrap="true" />
<Label :text="appTheme" class="info" />
</StackLayout>
</GridLayout>
<StackLayout class="hr m-10"></StackLayout>
@ -37,11 +37,13 @@
<Label col="0" class="bx" :text="icon.export" />
<StackLayout col="1">
<Label text="Export a full backup" />
<GridLayout
class="progressContainer"
v-if="backupInProgress"
columns="*, 64"
>
<Label
v-if="!backupInProgress"
text="Generates a zip file that contains all your data. This file can be imported back."
class="info"
textWrap="true"
/>
<GridLayout class="progressContainer" v-else columns="*, 64">
<MDProgress
col="0"
:value="backupProgress"
@ -49,12 +51,6 @@
></MDProgress>
<Label col="1" :text="` ${backupProgress}%`" />
</GridLayout>
<Label
v-else
text="Generates a zip file that contains all your data. This file can be imported back."
class="info"
textWrap="true"
/>
</StackLayout>
</GridLayout>
<GridLayout columns="auto, *" class="option"
@ -95,13 +91,9 @@ import { mapState, mapActions } from "vuex"
import ActionDialog from "./modal/ActionDialog.vue"
import ConfirmDialog from "./modal/ConfirmDialog.vue"
import * as utils from "~/shared/utils"
export default {
props: [
"showDrawer",
"restartApp",
"releaseGlobalBackEvent",
"openAppSettingsPage",
],
data() {
return {
viewIsScrolled: false,
@ -116,6 +108,7 @@ export default {
"recipes",
"userCategories",
"userYieldUnits",
"mealPlans",
"currentComponent",
]),
},
@ -125,13 +118,15 @@ export default {
"importCategoriesAction",
"importYieldUnitsAction",
"importRecipesAction",
"importMealPlansAction",
]),
onPageLoad() {
this.setCurrentComponentAction("Settings")
this.releaseGlobalBackEvent()
},
// HELPERS
showDrawer() {
utils.showDrawer()
},
onScroll(args) {
args.scrollY
? (this.viewIsScrolled = true)
@ -160,7 +155,7 @@ export default {
if (result) {
this.appTheme = action
ApplicationSettings.setString("appTheme", action)
setTimeout((e) => this.restartApp(), 250)
setTimeout((e) => utils.restartApp(), 250)
}
})
}
@ -209,11 +204,6 @@ export default {
archive: destPath,
onProgress: (progress) => {
this.backupProgress = progress
if (progress == 100) {
setTimeout((e) => {
this.backupInProgress = false
}, 2000)
}
},
}).then((success) => {
Toast.makeText(
@ -225,8 +215,8 @@ export default {
},
exportFiles(option) {
const folder = path.join(knownFolders.documents().path, "EnRecipes")
const EnRecipesFile = File.fromPath(path.join(folder, "EnRecipes.json"))
let userCategoriesFile, userYieldUnitsFile
const EnRecipesFile = File.fromPath(path.join(folder, "recipes.json"))
let userCategoriesFile, userYieldUnitsFile, mealPlansFile
if (this.userCategories.length) {
userCategoriesFile = File.fromPath(
path.join(folder, "userCategories.json")
@ -237,6 +227,9 @@ export default {
path.join(folder, "userYieldUnits.json")
)
}
if (this.mealPlans.length) {
mealPlansFile = File.fromPath(path.join(folder, "mealPlans.json"))
}
switch (option) {
case "create":
this.writeDataToFile(EnRecipesFile, this.recipes)
@ -244,11 +237,14 @@ export default {
this.writeDataToFile(userCategoriesFile, this.userCategories)
this.userYieldUnits.length &&
this.writeDataToFile(userYieldUnitsFile, this.userYieldUnits)
this.mealPlans.length &&
this.writeDataToFile(mealPlansFile, this.mealPlans)
break
case "delete":
EnRecipesFile.remove()
this.userCategories.length && userCategoriesFile.remove()
this.userYieldUnits.length && userYieldUnitsFile.remove()
this.mealPlans.length && mealPlansFile.remove()
break
default:
break
@ -290,6 +286,9 @@ export default {
case "userYieldUnitsDB":
this.importYieldUnitsAction(data)
break
case "mealPlansDB":
this.importMealPlansAction(data)
break
default:
break
}
@ -312,9 +311,10 @@ export default {
overwrite: true,
}).then((extractedFolderPath) => {
let cacheFolderPath = extractedFolderPath + "/EnRecipes"
const EnRecipesFilePath = cacheFolderPath + "/EnRecipes.json"
const EnRecipesFilePath = cacheFolderPath + "/recipes.json"
const userCategoriesFilePath = cacheFolderPath + "/userCategories.json"
const userYieldUnitsFilePath = cacheFolderPath + "/userYieldUnits.json"
const mealPlansFilePath = cacheFolderPath + "/mealPlans.json"
if (Folder.exists(cacheFolderPath)) {
this.isFileDataValid([
{
@ -324,6 +324,7 @@ export default {
},
{ zipPath, path: userCategoriesFilePath, db: "userCategoriesDB" },
{ zipPath, path: userYieldUnitsFilePath, db: "userYieldUnitsDB" },
{ zipPath, path: mealPlansFilePath, db: "mealPlansDB" },
])
} else {
Folder.fromPath(extractedFolderPath).remove()
@ -368,7 +369,7 @@ export default {
let status = res[Object.keys(res)[0]]
if (status !== "authorized") {
confirmation(description).then((e) => {
e && this.openAppSettingsPage()
e && utils.openAppSettingsPage()
})
} else action()
})
@ -385,7 +386,7 @@ export default {
})
},
},
created() {
mounted() {
this.appTheme = ApplicationSettings.getString("appTheme", "Light")
},
}

View file

@ -66,7 +66,7 @@
class="viewRecipe"
>
<TabViewItem title="Overview">
<ScrollView scrollBarIndicatorVisible="false">
<ScrollView scrollBarIndicatorVisible="true">
<StackLayout>
<StackLayout
width="100%"
@ -221,7 +221,7 @@
</ScrollView>
</TabViewItem>
<TabViewItem title="Ingredients">
<ScrollView scrollBarIndicatorVisible="false">
<ScrollView scrollBarIndicatorVisible="true">
<GridLayout
v-if="!recipe.ingredients.length"
rows="*, auto, *, 88"
@ -265,7 +265,6 @@
:key="index"
>
<check-box
v-if="filterTrylater"
class="ingredient-check"
checkPadding="16"
fillColor="#ff5200"
@ -279,26 +278,12 @@
}`
"
/>
<Label
v-else
class="ingredient"
textWrap="true"
:text="
`${
roundedQuantity(item.quantity)
? roundedQuantity(item.quantity) + ' '
: ''
}${roundedQuantity(item.quantity) ? item.unit + ' ' : ''}${
item.item
}`
"
/>
</StackLayout>
</StackLayout>
</ScrollView>
</TabViewItem>
<TabViewItem title="Instructions">
<ScrollView scrollBarIndicatorVisible="false">
<ScrollView scrollBarIndicatorVisible="true">
<GridLayout
v-if="!recipe.instructions.length"
rows="*, auto, *, 88"
@ -343,7 +328,7 @@
</ScrollView>
</TabViewItem>
<TabViewItem title="Notes">
<ScrollView scrollBarIndicatorVisible="false">
<ScrollView scrollBarIndicatorVisible="true">
<GridLayout
v-if="!recipe.notes.length"
rows="*, auto, *, 88"
@ -385,7 +370,7 @@
</ScrollView>
</TabViewItem>
<TabViewItem title="References">
<ScrollView scrollBarIndicatorVisible="false">
<ScrollView scrollBarIndicatorVisible="true">
<GridLayout
v-if="!recipe.references.length"
rows="*, auto, *, 88"
@ -438,7 +423,7 @@
</ScrollView>
</TabViewItem>
<TabViewItem title="Combinations">
<ScrollView scrollBarIndicatorVisible="false">
<ScrollView scrollBarIndicatorVisible="true">
<GridLayout
v-if="!recipe.combinations.length"
rows="*, auto, *, 88"
@ -523,13 +508,7 @@ import ShareChooser from "./modal/ShareChooser.vue"
let feedback = new Feedback()
export default {
props: [
"filterTrylater",
"recipeID",
"recipeIndex",
"hijackGlobalBackEvent",
"releaseGlobalBackEvent",
],
props: ["filterTrylater", "recipeID"],
data() {
return {
busy: false,
@ -560,7 +539,6 @@ export default {
"setRecipeAsTriedAction",
]),
onPageLoad() {
this.releaseGlobalBackEvent()
this.busy = false
setTimeout((e) => {
this.setCurrentComponentAction("ViewRecipe")

View file

@ -2,7 +2,10 @@
<Page>
<StackLayout class="dialogContainer" :class="appTheme">
<Label class="dialogTitle orkm" :text="title" />
<StackLayout padding="0 24 24">
<StackLayout
v-if="filteredRecipes.length || searchTerm"
padding="0 24 24"
>
<TextField hint="Search" v-model="searchTerm" />
</StackLayout>
<ScrollView width="100%" :height="height ? height : screenHeight - 320">
@ -18,11 +21,11 @@
@tap="tapAction(recipe)"
/>
<Label
padding="0 24"
padding="24"
lineHeight="6"
v-if="!filteredRecipes.length"
text="Nothing here! Add some recipes that goes well with this and try again."
horizontalAlignment="center"
text="Nothing here! Add some recipes and try again."
textAlignment="center"
textWrap="true"
/>
</StackLayout>

View file

@ -1,7 +1,7 @@
<template>
<Page>
<StackLayout class="dialogContainer" :class="appTheme">
<Label class="dialogTitle orkm" :text="title" />
<Label class="dialogTitle orkm" :text="title" textWrap="true"/>
<Label
v-if="description"
class="dialogDescription"

View file

@ -23,10 +23,9 @@ Vue.use(ProgressPlugin)
import CalendarView from "nativescript-ui-calendar/vue"
Vue.use(CalendarView)
Vue.registerElement(
"RadSideDrawer",
() => require("nativescript-ui-sidedrawer").RadSideDrawer
)
import RadSideDrawer from "nativescript-ui-sidedrawer/vue"
Vue.use(RadSideDrawer)
import { CheckBox } from "@nstudio/nativescript-checkbox"
Vue.registerElement("CheckBox", () => CheckBox, {
model: {
@ -35,11 +34,6 @@ Vue.registerElement("CheckBox", () => CheckBox, {
},
})
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({

42
app/shared/utils.js Normal file
View file

@ -0,0 +1,42 @@
import { Application } from "@nativescript/core"
export const showDrawer = () => {
let sideDrawer = Application.getRootView().getViewById("sideDrawer")
sideDrawer && sideDrawer.showDrawer()
}
export const restartApp = () => {
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())
}
export const openAppSettingsPage = () => {
const intent = new android.content.Intent(
android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS
)
intent.addCategory(android.content.Intent.CATEGORY_DEFAULT)
intent.setData(
android.net.Uri.parse(
"package:" + Application.android.context.getPackageName()
)
)
Application.android.foregroundActivity.startActivity(intent)
}

View file

@ -1,10 +1,13 @@
import Vue from "vue"
import Vuex from "vuex"
import { Couchbase } from "nativescript-couchbase-plugin"
import { getFileAccess } from "@nativescript/core"
import { Color, getFileAccess } from "@nativescript/core"
import { CalendarEvent } from "nativescript-ui-calendar"
import { stat } from "fs"
const EnRecipesDB = new Couchbase("EnRecipes")
const userCategoriesDB = new Couchbase("userCategories")
const userYieldUnitsDB = new Couchbase("userYieldUnits")
const mealPlansDB = new Couchbase("mealPlans")
Vue.use(Vuex)
@ -116,6 +119,7 @@ export default new Vuex.Store({
units: [
"unit",
"tsp",
"dsp",
"tbsp",
"fl oz",
"cup",
@ -131,6 +135,7 @@ export default new Vuex.Store({
"kg",
"cm",
"in",
"leaf",
"clove",
"pinch",
"drop",
@ -142,6 +147,7 @@ export default new Vuex.Store({
],
yieldUnits: [],
userYieldUnits: [],
mealPlans: [],
icon: {
home: "\ued3b",
heart: "\ued36",
@ -183,7 +189,8 @@ export default new Vuex.Store({
export: "\ued07",
import: "\ued0c",
outline: "\ueb07",
calendar: "\uec57",
calendar: "\uec55",
today: "\ue97c",
},
currentComponent: "EnRecipes",
},
@ -230,12 +237,16 @@ export default new Vuex.Store({
}
state.yieldUnits = [...defaultYieldUnits, ...state.userYieldUnits]
},
addRecipe(state, { id, recipe }) {
state.recipes.push(recipe)
EnRecipesDB.createDocument(recipe, id)
initializeMealPlans(state) {
let isMealPlansDBStored = mealPlansDB.query({ select: [] }).length
if (isMealPlansDBStored) {
state.mealPlans = mealPlansDB.getDocument("mealPlans").mealPlans
} else {
mealPlansDB.createDocument({ mealPlans: [] }, "mealPlans")
}
},
importRecipes(state, recipes) {
console.log("hello")
let localRecipesIDs, partition
if (state.recipes.length) {
localRecipesIDs = state.recipes.map((e) => e.id)
@ -254,24 +265,59 @@ export default new Vuex.Store({
createDocuments(recipes)
}
function createDocuments(data) {
console.log("creating")
state.recipes = [...state.recipes, ...data]
data.forEach((recipe) => {
EnRecipesDB.createDocument(recipe, recipe.id)
})
}
function updateDocuments(data) {
console.log("updating")
data.forEach((recipe) => {
let recipeIndex = state.recipes
.map((e, i) => (e.id === recipe.id ? i : -1))
.map((e, i) => {
let d1 = new Date(e.lastModified).getTime()
let d2 = new Date(recipe.lastModified).getTime()
return e.id === recipe.id && d1 < d2 ? i : -1
})
.filter((e) => e >= 0)[0]
console.log(recipeIndex)
Object.assign(state.recipes[recipeIndex], recipe)
EnRecipesDB.updateDocument(recipe.id, recipe)
if (recipeIndex >= 0) {
Object.assign(state.recipes[recipeIndex], recipe)
EnRecipesDB.updateDocument(recipe.id, recipe)
}
})
}
},
importCategories(state, categories) {
state.userCategories = new Set([...state.userCategories, ...categories])
userCategoriesDB.updateDocument("userCategories", {
userCategories: [...state.userCategories],
})
state.categories = [...defaultCategories, ...state.userCategories]
state.categories.sort()
},
importYieldUnits(state, yieldUnits) {
state.userYieldUnits = new Set([...state.userYieldUnits, ...yieldUnits])
userYieldUnitsDB.updateDocument("userYieldUnits", {
userYieldUnits: [...state.userYieldUnits],
})
state.yieldUnits = [...defaultYieldUnits, ...state.userYieldUnits]
},
importMealPlans(state, mealPlans) {
let newMealPlans = mealPlans.filter(
(e) =>
!state.mealPlans.some(
(f) => f.title === e.title && f.startDate === e.startDate
)
)
state.mealPlans = [...state.mealPlans, ...newMealPlans]
mealPlansDB.updateDocument("mealPlans", {
mealPlans: [...state.mealPlans],
})
},
addRecipe(state, { id, recipe }) {
state.recipes.push(recipe)
EnRecipesDB.createDocument(recipe, id)
},
addCategory(state, category) {
let lowercase = state.categories.map((e) => e.toLowerCase())
if (lowercase.indexOf(category.toLowerCase()) == -1) {
@ -283,14 +329,6 @@ export default new Vuex.Store({
state.categories.sort()
}
},
importCategories(state, categories) {
state.userCategories = new Set([...state.userCategories, ...categories])
userCategoriesDB.updateDocument("userCategories", {
userCategories: [...state.userCategories],
})
state.categories = [...defaultCategories, ...state.userCategories]
state.categories.sort()
},
addYieldUnit(state, yieldUnit) {
let lowercase = state.yieldUnits.map((e) => e.toLowerCase())
if (lowercase.indexOf(yieldUnit.toLowerCase()) == -1) {
@ -301,20 +339,18 @@ export default new Vuex.Store({
state.yieldUnits = [...defaultYieldUnits, ...state.userYieldUnits]
}
},
importYieldUnits(state, yieldUnits) {
state.userYieldUnits = new Set([...state.userYieldUnits, ...yieldUnits])
userYieldUnitsDB.updateDocument("userYieldUnits", {
userYieldUnits: [...state.userYieldUnits],
addMealPlan(state, { event, eventColor }) {
state.mealPlans.push({
title: event.title,
startDate: event.startDate,
endDate: event.endDate,
eventColor,
})
mealPlansDB.updateDocument("mealPlans", {
mealPlans: [...state.mealPlans],
})
state.yieldUnits = [...defaultYieldUnits, ...state.userYieldUnits]
},
overwriteRecipe(state, { id, recipe }) {
let index = state.recipes.indexOf(
state.recipes.filter((e) => e.id === id)[0]
)
Object.assign(state.recipes[index], recipe)
EnRecipesDB.updateDocument(id, recipe)
},
deleteRecipe(state, { index, id }) {
getFileAccess().deleteFile(state.recipes[index].imageSrc)
state.recipes.splice(index, 1)
@ -326,6 +362,29 @@ export default new Vuex.Store({
}
})
},
deleteMealPlan(state, { title, startDate }) {
let mealPlan = state.mealPlans.filter((e) => {
console.log(e.startDate, startDate)
let sd = new Date(e.startDate).getTime()
return e.title === title && sd === startDate.getTime()
})[0]
let index = state.mealPlans.indexOf(mealPlan)
state.mealPlans.splice(index, 1)
state.mealPlans = [...state.mealPlans]
let mealPlans = mealPlansDB.getDocument("mealPlans").mealPlans
mealPlans.splice(index, 1)
mealPlansDB.updateDocument("mealPlans", {
mealPlans: [...mealPlans],
})
},
overwriteRecipe(state, { id, recipe }) {
let index = state.recipes.indexOf(
state.recipes.filter((e) => e.id === id)[0]
)
Object.assign(state.recipes[index], recipe)
EnRecipesDB.updateDocument(id, recipe)
},
toggleState(state, { id, recipe, key, setDate }) {
let index = state.recipes.indexOf(
state.recipes.filter((e) => e.id === id)[0]
@ -346,9 +405,6 @@ export default new Vuex.Store({
state.recipes[index].lastTried = new Date()
EnRecipesDB.updateDocument(state.recipes[index].id, state.recipes[index])
},
setCurrentComponent(state, comp) {
state.currentComponent = comp
},
renameCategory(state, { current, updated }) {
let lowercase = state.categories.map((e) => e.toLowerCase())
if (lowercase.indexOf(updated.toLowerCase()) == -1) {
@ -368,6 +424,9 @@ export default new Vuex.Store({
}
})
},
setCurrentComponent(state, comp) {
state.currentComponent = comp
},
unSyncCombinations(state, { id, combinations }) {
state.recipes.forEach((e, i) => {
if (combinations.includes(e.id)) {
@ -387,30 +446,46 @@ export default new Vuex.Store({
initializeYieldUnits({ commit }) {
commit("initializeYieldUnits")
},
addRecipeAction({ commit }, recipe) {
commit("addRecipe", recipe)
initializeMealPlans({ commit }) {
commit("initializeMealPlans")
},
importRecipesAction({ commit }, recipes) {
commit("importRecipes", recipes)
},
addCategoryAction({ commit }, category) {
commit("addCategory", category)
},
importCategoriesAction({ commit }, categories) {
commit("importCategories", categories)
},
addYieldUnitAction({ commit }, yieldUnit) {
commit("addYieldUnit", yieldUnit)
},
importYieldUnitsAction({ commit }, yieldUnits) {
commit("importYieldUnits", yieldUnits)
},
overwriteRecipeAction({ commit }, updatedRecipe) {
commit("overwriteRecipe", updatedRecipe)
importMealPlansAction({ commit }, mealPlans) {
commit("importMealPlans", mealPlans)
},
addRecipeAction({ commit }, recipe) {
commit("addRecipe", recipe)
},
addYieldUnitAction({ commit }, yieldUnit) {
commit("addYieldUnit", yieldUnit)
},
addCategoryAction({ commit }, category) {
commit("addCategory", category)
},
addMealPlanAction({ commit }, mealPlan) {
commit("addMealPlan", mealPlan)
},
deleteMealPlanAction({ commit }, mealPlan) {
commit("deleteMealPlan", mealPlan)
},
deleteRecipeAction({ commit }, recipe) {
commit("deleteRecipe", recipe)
},
overwriteRecipeAction({ commit }, updatedRecipe) {
commit("overwriteRecipe", updatedRecipe)
},
toggleStateAction({ commit }, toggledRecipe) {
commit("toggleState", toggledRecipe)
},
@ -420,12 +495,12 @@ export default new Vuex.Store({
setLastTriedDateAction({ commit }, index) {
commit("setLastTriedDate", index)
},
setCurrentComponentAction({ commit }, comp) {
commit("setCurrentComponent", comp)
},
renameCategoryAction({ commit }, category) {
commit("renameCategory", category)
},
setCurrentComponentAction({ commit }, comp) {
commit("setCurrentComponent", comp)
},
unSyncCombinationsAction({ commit }, combinations) {
commit("unSyncCombinations", combinations)
},

View file

@ -2,11 +2,11 @@ import { NativeScriptConfig } from "@nativescript/core"
export default {
id: "com.vishnuraghav.enrecipes",
appResourcesPath: "app/App_Resources",
appResourcesPath: "App_Resources",
android: {
v8Flags: "--expose_gc",
markingMode: "none",
codeCache: true,
},
appPath: "app",
}
// appPath: "app",
} as NativeScriptConfig

688
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -4,9 +4,6 @@
"description": "A native application built with NativeScript-Vue",
"author": "Vishnu Raghav <design@vishnuraghav.com>",
"license": "GPL",
"scripts": {
"run": "ns run android"
},
"dependencies": {
"@nativescript-community/perms": "^2.1.1",
"@nativescript-community/ui-material-activityindicator": "^5.0.30",
@ -27,19 +24,19 @@
"nativescript-ui-calendar": "^7.0.2",
"nativescript-ui-listview": "^9.0.4",
"nativescript-ui-sidedrawer": "^9.0.3",
"nativescript-vue": "^2.6.1",
"vuex": "^3.3.0"
"nativescript-vue": "^2.8.1",
"vuex": "^3.5.1"
},
"devDependencies": {
"@babel/core": "^7.0.0",
"@babel/preset-env": "^7.0.0",
"@babel/core": "^7.12.3",
"@babel/preset-env": "^7.12.1",
"@nativescript/android": "7.0.1",
"@types/node": "^14.0.27",
"babel-loader": "^8.1.0",
"nativescript-vue-template-compiler": "^2.6.0",
"node-sass": "^4.13.1",
"vue-loader": "^15.9.1",
"@nativescript/webpack": "~3.0.0"
"@nativescript/webpack": "^3.0.8",
"@types/node": "^14.14.8",
"babel-loader": "^8.2.1",
"nativescript-vue-template-compiler": "^2.8.1",
"node-sass": "^4.14.1",
"vue-loader": "^15.9.5"
},
"main": "main"
}