diff --git a/app/app.scss b/app/app.scss
index 927e684e..f6142399 100644
--- a/app/app.scss
+++ b/app/app.scss
@@ -15,17 +15,18 @@ Page {
font-family: "Inter-Medium";
font-size: 14;
}
-.tb {
- font-family: "Inter-Bold";
-}
.ico {
font-family: "enrecipes";
font-size: 24;
vertical-alignment: center;
&.sm {
font-size: 16;
+ opacity: 0.5;
}
}
+.tb {
+ font-family: "Inter-Bold";
+}
.tac {
text-align: center;
}
@@ -54,8 +55,7 @@ Page {
border-color: $gray2;
}
.appbar,
- .modal,
- .topPlate {
+ .modal {
background: $gray0;
}
.fieldLabel,
@@ -71,11 +71,7 @@ Page {
color: $gray1;
background: $gray9;
}
- Progress {
- progress-background-color: $gray4;
- }
- .fab,
- .hlMsg {
+ .fab {
color: $gray1;
}
}
@@ -95,8 +91,7 @@ Page {
border-color: $gray7;
}
.appbar,
- .modal,
- .topPlate {
+ .modal {
color: $gray0;
background: $gray8;
}
@@ -113,18 +108,15 @@ Page {
color: $gray9;
background: $gray1;
}
- Progress {
- progress-background-color: $gray5;
- }
- .fab,
- .hlMsg {
+ .fab {
color: $gray9;
}
}
.Black {
color: $gray2;
background: $gray10;
- Page {
+ Page,
+ .filters {
background: $gray10;
}
TextField,
@@ -136,8 +128,7 @@ Page {
border-color: $gray8;
}
.appbar,
- .modal,
- .topPlate {
+ .modal {
color: $gray1;
background: $gray9;
}
@@ -154,11 +145,7 @@ Page {
color: $gray10;
background: $gray2;
}
- Progress {
- progress-background-color: $gray5;
- }
- .fab,
- .hlMsg {
+ .fab {
color: $gray10;
}
}
@@ -191,7 +178,8 @@ TextView {
width: 100%;
}
Progress {
- progress-color: $orange;
+ margin: 16;
+ background-color: $gray5;
}
Switch {
background-color: $orange;
@@ -200,7 +188,7 @@ Switch {
// -----------------------------
// Side Drawer
.segment {
- border-radius: 8;
+ border-radius: 12;
margin: 0 4 0 0;
padding: 0 12;
.value {
@@ -216,7 +204,7 @@ Button {
background-color: transparent;
z-index: 0;
padding: 8;
- border-radius: 8;
+ border-radius: 12;
min-width: 0;
min-height: 0;
&:active {
@@ -276,7 +264,7 @@ Button {
padding: 8 16;
.recipeInfo {
vertical-alignment: top;
- padding: 4 0 4 8;
+ padding: 2 0 2 8;
}
.title {
padding: 0 0 4;
@@ -318,7 +306,7 @@ Button {
background-color: transparent;
}
.imgHolder {
- border-radius: 8;
+ border-radius: 12;
}
// -----------------------------
// SETTINGS
@@ -328,6 +316,7 @@ Button {
}
.options-list {
.option {
+ vertical-align: center;
padding: 14 8;
margin: 0 16;
.ico {
@@ -353,7 +342,7 @@ Button {
.icon {
margin: 16;
background: $orange;
- border-radius: 99;
+ border-radius: 16;
horizontal-alignment: center;
}
.name {
@@ -367,16 +356,21 @@ Button {
// -----------------------------
// VIEW RECIPE
.photo {
- border-radius: 8;
+ border-radius: 12;
margin: 24 16 0 0;
vertical-align: top;
}
+.photoviewer {
+ width: 96;
+ height: 96;
+ opacity: 0;
+ background: #000;
+}
.attribute {
margin: 8 16;
.title {
margin-right: 8;
font-size: 12;
- color: $gray6;
}
.value {
@extend .tb;
@@ -425,18 +419,19 @@ Button {
line-height: 4;
padding: 16 0;
}
+.dateInfo {
+ padding: 32 16 16;
+ font-size: 12;
+ line-height: 4;
+}
// -----------------------------
// APPBAR
.appbar {
- z-index: 99;
+ z-index: 32;
min-height: 56;
margin: 8;
padding: 4;
- border-radius: 10;
- elevation: 16;
- &.hlMsg {
- background: $orange;
- }
+ border-radius: 16;
.title {
@extend .tb;
@extend .tw;
@@ -451,7 +446,7 @@ Button {
}
}
.toolbar {
- z-index: 98;
+ z-index: 24;
padding: 4;
margin-bottom: 0;
horizontal-alignment: left;
@@ -469,7 +464,7 @@ Button {
width: 48;
height: 48;
margin: 0 4 0 0;
- border-radius: 8;
+ border-radius: 12;
background: $orange;
}
// -----------------------------
@@ -482,10 +477,6 @@ Button {
margin: 32 0 16;
}
.countdown {
- background-color: transparent;
- width: 48;
- height: 48;
- z-index: 0;
font-size: 17;
color: $orange;
}
@@ -507,7 +498,7 @@ Button {
text-align: center;
}
.day {
- border-radius: 8;
+ border-radius: 12;
}
.hasPlans {
color: $orange;
@@ -536,7 +527,7 @@ Button {
.modal {
max-width: 320;
width: 100%;
- border-radius: 10;
+ border-radius: 12;
margin: 72 0;
.title {
@extend .tb;
@@ -566,7 +557,7 @@ Button {
background: transparent;
}
.shareItem {
- border-radius: 8;
+ border-radius: 12;
margin: 0 8 8;
text-align: center;
.ico {
@@ -624,6 +615,7 @@ ActivityIndicator {
}
@keyframes fade {
0% {
+ opacity: 1;
}
100% {
opacity: 0.5;
diff --git a/app/components/EditRecipe.vue b/app/components/EditRecipe.vue
index cdad4b42..e4ec6ef5 100644
--- a/app/components/EditRecipe.vue
+++ b/app/components/EditRecipe.vue
@@ -10,8 +10,8 @@
@@ -41,9 +41,9 @@
@@ -51,9 +51,9 @@
@@ -75,9 +75,7 @@
@@ -87,9 +85,7 @@
ref="cookTime"
:text="timeRequired('cookTime')"
editable="false"
- @focus="
- modalOpen === false && setTimeRequired(true, 'cookTime')
- "
+ @focus="!modalOpen && setTimeRequired(true, 'cookTime')"
@tap="setTimeRequired(false, 'cookTime')"
/>
@@ -99,7 +95,7 @@
@@ -120,9 +116,9 @@
@@ -134,15 +130,13 @@
/>
@@ -161,10 +155,10 @@
ref="ingredient"
@loaded="setInputTypeText($event, 'sentence')"
col="4"
- v-model="recipeContent.ingredients[index].item"
+ v-model="recipe.ingredients[index].item"
:hint="`${$options.filters.L('it')} ${index + 1}`"
@returnPress="
- index + 1 == recipeContent.ingredients.length && addIngredient()
+ index + 1 == recipe.ingredients.length && addIngredient()
"
/>
@@ -187,13 +181,13 @@
/>
@@ -299,18 +287,16 @@ import {
Screen,
Utils,
Observable,
+ CoreTypes,
} from "@nativescript/core";
-import * as Permissions from "@nativescript-community/perms";
-// import * as Filepicker from "nativescript-plugin-filepicker";
-import { ImageCropper } from "nativescript-imagecropper";
import { localize } from "@nativescript/localize";
+import { ImageCropper } from "nativescript-imagecropper";
import { mapState, mapActions } from "vuex";
import ActionDialog from "./modal/ActionDialog.vue";
import ActionDialogWithSearch from "./modal/ActionDialogWithSearch.vue";
import ConfirmDialog from "./modal/ConfirmDialog.vue";
import PromptDialog from "./modal/PromptDialog.vue";
import ListPicker from "./modal/ListPicker.vue";
-import ViewRecipe from "./ViewRecipe";
import * as utils from "~/shared/utils";
let undoTimer;
export default {
@@ -323,7 +309,7 @@ export default {
data() {
return {
title: "newRec",
- recipeContent: {
+ recipe: {
imageSrc: null,
title: undefined,
cuisine: "Undefined",
@@ -348,12 +334,10 @@ export default {
created: null,
inBag: false,
},
- tempRecipeContent: {},
+ tempRecipe: {},
tags: undefined,
- blockModal: false,
modalOpen: false,
newRecipeID: null,
- showFab: false,
saving: false,
cacheImagePath: null,
unSyncCombinations: [],
@@ -378,18 +362,13 @@ export default {
"selectedCuisine",
"selectedCategory",
"selectedTag",
+ "appTheme",
]),
screenWidth() {
return Screen.mainScreen.widthDIPs;
},
- appTheme() {
- return Application.systemAppearance();
- },
hasChanges() {
- return (
- JSON.stringify(this.recipeContent) !==
- JSON.stringify(this.tempRecipeContent)
- );
+ return JSON.stringify(this.recipe) !== JSON.stringify(this.tempRecipe);
},
},
methods: {
@@ -403,7 +382,7 @@ export default {
onPageLoad(args) {
const page = args.object;
page.bindingContext = new Observable();
- this.showFab = true;
+ this.hijackBackEvent();
},
onPageUnload() {
this.releaseBackEvent();
@@ -419,30 +398,470 @@ export default {
this.scrollPos = Math.abs(y);
let ab = this.appbar.translateY;
if (!scrollUp && ab == 0) {
- this.animateInOut(
- 250,
- false,
- (val) => (this.appbar.translateY = val * 64)
- );
+ this.appbar.animate({
+ translate: { x: 0, y: 64 },
+ duration: 250,
+ curve: CoreTypes.AnimationCurve.ease,
+ });
} else if (scrollUp && ab == 64) {
Utils.ad.dismissSoftInput();
- this.animateInOut(
- 250,
- true,
- (val) => (this.appbar.translateY = val * 64)
- );
+ this.appbar.animate({
+ translate: { x: 0, y: 0 },
+ duration: 250,
+ curve: CoreTypes.AnimationCurve.ease,
+ });
}
}
},
+
+ // PHOTO HANDLERS
+ imageHandler() {
+ this.clearEmptyFields(true);
+ if (this.recipe.imageSrc) {
+ this.modalOpen = true;
+ this.$showModal(ConfirmDialog, {
+ props: {
+ title: "recPic",
+ secondButtonText: "rBtn",
+ cancelButtonText: "cBtn",
+ okButtonText: "repBtn",
+ },
+ }).then((action) => {
+ this.modalOpen = false;
+ if (action > 0) this.imagePicker();
+ else if (action < 0) this.recipe.imageSrc = null;
+ });
+ } else this.imagePicker();
+ },
+ imagePicker() {
+ let aT = this.appTheme;
+ utils.getRecipePhoto().then((uri) => {
+ if (uri != null) {
+ this.cacheImagePath = path.join(
+ knownFolders.temp().path,
+ `${this.getRandomID()}.jpg`
+ );
+ utils.copyPhotoToCache(uri, this.cacheImagePath).then((imgPath) => {
+ if (imgPath) {
+ ImageSource.fromFile(imgPath).then((image) => {
+ ImageCropper.prototype
+ .show(
+ image,
+ {
+ width: 1080,
+ height: 1080,
+ },
+ {
+ hideBottomControls: true,
+ toolbarTitle: localize("cPic"),
+ statusBarColor: "#ff5200",
+ toolbarTextColor: aT == "Light" ? "#212529" : "#f1f3f5",
+ toolbarColor:
+ aT == "Light"
+ ? "#f1f3f5"
+ : aT == "Dark"
+ ? "#212529"
+ : "#000000",
+ cropFrameColor: "#ff5200",
+ }
+ )
+ .then((cropped) => {
+ cropped.image.saveToFile(this.cacheImagePath, "jpg", 75);
+ this.recipe.imageSrc = this.cacheImagePath;
+ });
+ });
+ }
+ });
+ }
+ });
+ },
+
+ // DATA LIST
+ showCuisine(focus) {
+ this.modalOpen = true;
+ this.$showModal(ActionDialog, {
+ props: {
+ title: "cui",
+ list: this.cuisines,
+ action: "aNBtn",
+ },
+ }).then((action) => {
+ if (action == "aNBtn") {
+ this.$showModal(PromptDialog, {
+ props: {
+ title: "newCui",
+ action: "aBtn",
+ },
+ }).then((item) => {
+ this.modalOpen = false;
+ if (item.length) {
+ this.recipe.cuisine = item;
+ this.addListItemAction({
+ item,
+ listName: "cuisines",
+ });
+ if (focus) this.autoFocusField("category", false);
+ }
+ });
+ } else {
+ this.modalOpen = false;
+ if (action) {
+ this.recipe.cuisine = action;
+ if (focus) this.autoFocusField("category", false);
+ } else
+ this.cuisines.includes(this.recipe.cuisine)
+ ? mull
+ : (this.recipe.cuisine = "Undefined");
+ }
+ });
+ },
+ showCategories(focus) {
+ this.modalOpen = true;
+ this.$showModal(ActionDialog, {
+ props: {
+ title: "cat",
+ list: this.categories,
+ action: "aNBtn",
+ },
+ }).then((action) => {
+ if (action == "aNBtn") {
+ this.$showModal(PromptDialog, {
+ props: {
+ title: "nwCat",
+ action: "aBtn",
+ },
+ }).then((item) => {
+ this.modalOpen = false;
+ if (item.length) {
+ this.recipe.category = item;
+ this.addListItemAction({
+ item,
+ listName: "categories",
+ });
+ if (focus) this.autoFocusField("tags", true);
+ }
+ });
+ } else {
+ this.modalOpen = false;
+ if (action) {
+ this.recipe.category = action;
+ if (focus) this.autoFocusField("tags", true);
+ } else
+ this.categories.includes(this.recipe.category)
+ ? mull
+ : (this.recipe.category = "Undefined");
+ }
+ });
+ },
+ showYieldUnits(focus) {
+ this.modalOpen = true;
+ this.$showModal(ActionDialog, {
+ props: {
+ title: "yieldU",
+ list: this.yieldUnits,
+ action: "aNBtn",
+ },
+ }).then((action) => {
+ if (action == "aNBtn") {
+ this.$showModal(PromptDialog, {
+ props: {
+ title: "nwYiU",
+ action: "aBtn",
+ },
+ }).then((item) => {
+ this.modalOpen = false;
+ if (item.length) {
+ this.recipe.yield.unit = item;
+ this.addListItemAction({
+ item,
+ listName: "yieldUnits",
+ });
+ if (focus) this.autoFocusField("difficultyLevel", false);
+ }
+ });
+ } else {
+ this.modalOpen = false;
+ if (action) {
+ this.recipe.yield.unit = action;
+ if (focus) this.autoFocusField("difficultyLevel", false);
+ } else
+ this.yieldUnits.includes(this.recipe.yield.unit)
+ ? mull
+ : (this.recipe.yield.unit = "Serving");
+ }
+ });
+ },
+ showDifficultyLevel(focus) {
+ this.modalOpen = true;
+ this.$showModal(ActionDialog, {
+ props: {
+ title: "Difficulty level",
+ list: this.difficultyLevels,
+ },
+ }).then((action) => {
+ this.modalOpen = false;
+ if (action) {
+ this.recipe.difficulty = action;
+ if (focus) this.addIngredient();
+ } else
+ this.difficultyLevels.includes(this.recipe.difficulty)
+ ? mull
+ : (this.recipe.difficulty = "Easy");
+ });
+ },
+ showUnits(e, focus, index) {
+ this.modalOpen = true;
+ this.$showModal(ActionDialog, {
+ props: {
+ title: "Unit",
+ list: this.units,
+ action: "aNBtn",
+ },
+ }).then((action) => {
+ if (action == "aNBtn") {
+ this.$showModal(PromptDialog, {
+ props: {
+ title: "newUnit",
+ action: "aBtn",
+ },
+ }).then((item) => {
+ this.modalOpen = false;
+ if (item.length) {
+ this.recipe.ingredients[index].unit = item;
+ this.addListItemAction({
+ item,
+ listName: "units",
+ });
+ if (focus && this.recipe.ingredients.length - 1 === index)
+ this.autoFocusRefField("ingredient", index);
+ }
+ });
+ } else {
+ this.modalOpen = false;
+ if (action) {
+ this.recipe.ingredients[index].unit = action;
+ if (focus && this.recipe.ingredients.length - 1 === index)
+ this.autoFocusRefField("ingredient", index);
+ }
+ }
+ });
+ },
+ showCombinations() {
+ Utils.ad.dismissSoftInput();
+ this.modalOpen = true;
+ let existingCombinations = [...this.recipe.combinations, this.recipe.id];
+ let filteredRecipes = this.recipes.filter(
+ (e) => !existingCombinations.includes(e.id)
+ );
+ this.$showModal(ActionDialogWithSearch, {
+ props: {
+ title: "selRec",
+ recipes: filteredRecipes,
+ },
+ }).then((res) => {
+ this.modalOpen = false;
+ if (res) this.recipe.combinations.push(res);
+ });
+ },
+
+ // INPUT FIELD HANDLERS
+ addIngredient() {
+ let ingredients = this.recipe.ingredients;
+ let unit = ingredients.length
+ ? ingredients[ingredients.length - 1].unit
+ : "unit";
+ this.recipe.ingredients.push({
+ item: "",
+ quantity: null,
+ unit,
+ });
+ },
+ removeIngredient(index) {
+ this.modalOpen = true;
+ if (this.recipe.ingredients[index].item.length) {
+ let item = this.recipe.ingredients[index];
+ this.recipe.ingredients.splice(index, 1);
+ this.showUndoBar("rmIng").then(
+ (res) => res && this.recipe.ingredients.splice(index, 0, item)
+ );
+ } else {
+ this.recipe.ingredients.splice(index, 1);
+ }
+ setTimeout((e) => (this.modalOpen = false), 200);
+ },
+ addInstruction() {
+ this.recipe.instructions.push("");
+ },
+ removeInstruction(index) {
+ if (this.recipe.instructions[index].length) {
+ let item = this.recipe.instructions[index];
+ this.recipe.instructions.splice(index, 1);
+ this.showUndoBar("rmIns").then(
+ (res) => res && this.recipe.instructions.splice(index, 0, item)
+ );
+ } else this.recipe.instructions.splice(index, 1);
+ },
+ addNote() {
+ this.recipe.notes.push("");
+ },
+ removeNote(index) {
+ if (this.recipe.notes[index].length) {
+ let item = this.recipe.notes[index];
+ this.recipe.notes.splice(index, 1);
+ this.showUndoBar("rmN").then((res) =>
+ this.recipe.notes.splice(index, 0, item)
+ );
+ } else this.recipe.notes.splice(index, 1);
+ },
+ getCombinationTitle(id) {
+ return this.recipes.filter((e) => e.id === id)[0].title;
+ },
+ removeCombination(id) {
+ let index = this.recipe.combinations.indexOf(id);
+ this.recipe.combinations.splice(index, 1);
+ this.unSyncCombinations.push(id);
+ this.showUndoBar("rmCmb").then((res) =>
+ this.recipe.combinations.splice(index, 0, id)
+ );
+ },
+
+ // SAVE OPERATION
+ clearEmptyFields(bool) {
+ if (!this.recipe.title && !bool) this.recipe.title = localize("untRec");
+ if (!this.recipe.yield.quantity) this.recipe.yield.quantity = 1;
+ this.recipe.ingredients = this.recipe.ingredients.filter((e) => e.item);
+ let vm = this;
+
+ function clearEmpty(arr) {
+ vm.recipe[arr] = vm.recipe[arr].filter((e) => e);
+ }
+ clearEmpty("instructions");
+ clearEmpty("notes");
+ },
+ saveOperation() {
+ this.saving = this.modalOpen = true;
+ this.clearEmptyFields();
+ this.recipe.lastModified = new Date();
+ ApplicationSettings.setString("previousCuisine", this.recipe.cuisine);
+ ApplicationSettings.setString("previousCategory", this.recipe.category);
+ ApplicationSettings.setString(
+ "previousYieldUnit",
+ this.recipe.yield.unit
+ );
+ if (this.cacheImagePath) {
+ let recipeImage = path.join(
+ knownFolders.documents().getFolder("EnRecipes").getFolder("Images")
+ .path,
+ `${this.getRandomID()}.jpg`
+ );
+ let binarySource = File.fromPath(this.cacheImagePath).readSync();
+ File.fromPath(recipeImage).writeSync(binarySource);
+ this.recipe.imageSrc = recipeImage;
+ knownFolders.temp().clear();
+ }
+ if (this.recipe.imageSrc) {
+ if (
+ this.tempRecipe.imageSrc &&
+ this.tempRecipe.imageSrc !== this.recipe.imageSrc
+ ) {
+ getFileAccess().deleteFile(this.tempRecipe.imageSrc);
+ }
+ } else if (this.tempRecipe.imageSrc) {
+ getFileAccess().deleteFile(this.tempRecipe.imageSrc);
+ }
+ this.unSyncCombinationsAction({
+ id: this.recipeID,
+ combinations: this.unSyncCombinations,
+ });
+ this.saveRecipe();
+ },
+ saveRecipe() {
+ if (this.recipeID) {
+ this.overwriteRecipeAction({
+ id: this.recipeID,
+ recipe: this.recipe,
+ });
+ } else {
+ this.recipe.id = this.newRecipeID;
+ this.addRecipeAction({
+ id: this.newRecipeID,
+ recipe: this.recipe,
+ });
+ }
+ setTimeout(() => (this.saving = false), 100);
+ this.$navigateBack();
+ },
+
+ // UNDO OPERATION
+ showUndoBar(message) {
+ return new Promise((resolve, reject) => {
+ this.showUndo = true;
+ this.appbar.translateY = 0;
+ this.snackMsg = message;
+ this.countdown = 5;
+ let a = 5;
+ clearTimeout(undoTimer);
+ undoTimer = setInterval(() => {
+ if (this.undo) {
+ this.showUndo = this.undo = false;
+ clearTimeout(undoTimer);
+ resolve(true);
+ }
+ this.countdown = Math.round((a -= 0.1));
+ if (this.countdown < 1) {
+ this.showUndo = false;
+ clearTimeout(undoTimer);
+ reject(true);
+ }
+ }, 100);
+ });
+ },
+ undoDel() {
+ this.undo = true;
+ },
+
+ // HELPERS
+ autoFocusField(ref, showSoftInput) {
+ this.$refs[ref].nativeView.focus();
+ if (showSoftInput) {
+ setTimeout(() => {
+ Utils.ad.showSoftInput(this.$refs[ref].nativeView.android);
+ }, 100);
+ }
+ },
+ autoFocusRefField(ref, index) {
+ this.$refs[ref][index].nativeView.focus();
+ setTimeout(() => {
+ Utils.ad.showSoftInput(this.$refs[ref][index].nativeView.android);
+ }, 100);
+ },
+ splitTags() {
+ let tags = [];
+ let string;
+ if (this.tags) {
+ tags = this.tags
+ .split(" ")
+ .map((e) => {
+ string = e.replace(/^[^\w\s]+/, "");
+ if (/^[A-Za-z]+/.test(string)) {
+ return string.charAt(0).toUpperCase() + string.slice(1);
+ }
+ })
+ .filter((e) => e);
+ }
+ this.recipe.tags = tags;
+ },
+ joinTags() {
+ this.tags = this.recipe.tags.join(" ");
+ },
timeRequired(time) {
- let t = this.recipeContent[time].split(":");
+ let t = this.recipe[time].split(":");
let h = parseInt(t[0]);
let m = parseInt(t[1]);
let hr = localize("hr");
let min = localize("min");
return h ? (m ? `${h} ${hr} ${m} ${min}` : `${h} ${hr}`) : `${m} ${min}`;
},
- // HELPERS
focusField(args, type) {
if (type) this.setInputTypeText(args, type);
if (!args.object.text) {
@@ -473,21 +892,19 @@ export default {
common
);
break;
- default:
- break;
}
},
getRandomID() {
let res = "";
let chars = "abcdefghijklmnopqrstuvwxyz0123456789";
- for (let i = 0; i < 20; i++) {
+ for (let i = 0; i < 16; i++) {
res += chars.charAt(Math.floor(Math.random() * chars.length));
}
return res;
},
setTimeRequired(focus, time) {
this.modalOpen = true;
- let t = this.recipeContent[time].split(":");
+ let t = this.recipe[time].split(":");
let hr = t[0];
let min = t[1];
this.$showModal(ListPicker, {
@@ -498,9 +915,9 @@ export default {
selectedMin: min,
},
}).then((result) => {
+ this.modalOpen = false;
if (result) {
- this.recipeContent[time] = result;
- this.modalOpen = false;
+ this.recipe[time] = result;
if (focus) {
switch (time) {
case "prepTime":
@@ -509,239 +926,18 @@ export default {
case "cookTime":
this.autoFocusField("yieldQuantity", true);
break;
- default:
- break;
}
}
}
});
},
getTitleCount(title, type) {
- let count = this.recipeContent[type].length;
+ let count = this.recipe[type].length;
let text = count ? ` (${count})` : "";
return localize(title) + text;
},
- // DATA LIST
- showCuisine(focus) {
- this.modalOpen = true;
- this.releaseBackEvent();
- this.$showModal(ActionDialog, {
- props: {
- title: "cui",
- list: this.cuisines,
- action: "aNBtn",
- },
- }).then((action) => {
- if (action == "aNBtn") {
- this.$showModal(PromptDialog, {
- props: {
- title: "newCui",
- action: "aBtn",
- },
- }).then((item) => {
- this.hijackBackEvent();
- if (item.length) {
- this.recipeContent.cuisine = item;
- this.addListItemAction({
- item,
- listName: "cuisines",
- });
- this.modalOpen = false;
- if (focus) this.autoFocusField("category", false);
- }
- });
- } else if (action) {
- this.recipeContent.cuisine = action;
- this.hijackBackEvent();
- this.modalOpen = false;
- if (focus) this.autoFocusField("category", false);
- } else {
- this.cuisines.includes(this.recipeContent.cuisine)
- ? mull
- : (this.recipeContent.cuisine = "Undefined");
- this.hijackBackEvent();
- }
- });
- },
- showCategories(focus) {
- this.modalOpen = true;
- this.releaseBackEvent();
- this.$showModal(ActionDialog, {
- props: {
- title: "cat",
- list: this.categories,
- action: "aNBtn",
- },
- }).then((action) => {
- if (action == "aNBtn") {
- this.$showModal(PromptDialog, {
- props: {
- title: "nwCat",
- action: "aBtn",
- },
- }).then((item) => {
- this.hijackBackEvent();
- if (item.length) {
- this.recipeContent.category = item;
- this.addListItemAction({
- item,
- listName: "categories",
- });
- this.modalOpen = false;
- if (focus) this.autoFocusField("tags", true);
- }
- });
- } else if (action) {
- this.recipeContent.category = action;
- this.hijackBackEvent();
- this.modalOpen = false;
- if (focus) this.autoFocusField("tags", true);
- } else {
- this.categories.includes(this.recipeContent.category)
- ? mull
- : (this.recipeContent.category = "Undefined");
- this.hijackBackEvent();
- }
- });
- },
- showYieldUnits(focus) {
- this.modalOpen = true;
- this.releaseBackEvent();
- this.$showModal(ActionDialog, {
- props: {
- title: "yieldU",
- list: this.yieldUnits,
- action: "aNBtn",
- },
- }).then((action) => {
- if (action == "aNBtn") {
- this.$showModal(PromptDialog, {
- props: {
- title: "nwYiU",
- action: "aBtn",
- },
- }).then((item) => {
- this.hijackBackEvent();
- if (item.length) {
- this.recipeContent.yield.unit = item;
- this.addListItemAction({
- item,
- listName: "yieldUnits",
- });
- this.modalOpen = false;
- if (focus) this.autoFocusField("difficultyLevel", false);
- }
- });
- } else if (action) {
- this.recipeContent.yield.unit = action;
- this.hijackBackEvent();
- this.modalOpen = false;
- if (focus) this.autoFocusField("difficultyLevel", false);
- } else {
- this.yieldUnits.includes(this.recipeContent.yield.unit)
- ? mull
- : (this.recipeContent.yield.unit = "Serving");
- this.hijackBackEvent();
- }
- });
- },
- showDifficultyLevel(focus) {
- this.modalOpen = true;
- this.releaseBackEvent();
- this.$showModal(ActionDialog, {
- props: {
- title: "Difficulty level",
- list: this.difficultyLevels,
- },
- }).then((action) => {
- if (action) {
- this.recipeContent.difficulty = action;
- this.hijackBackEvent();
- this.modalOpen = false;
- if (focus) this.addIngredient();
- } else {
- this.difficultyLevels.includes(this.recipeContent.difficulty)
- ? mull
- : (this.recipeContent.difficulty = "Easy");
- this.hijackBackEvent();
- }
- });
- },
- showUnits(e, focus, index) {
- this.modalOpen = true;
- this.releaseBackEvent();
- this.$showModal(ActionDialog, {
- props: {
- title: "Unit",
- list: this.units,
- action: "aNBtn",
- },
- }).then((action) => {
- if (action == "aNBtn") {
- this.$showModal(PromptDialog, {
- props: {
- title: "newUnit",
- action: "aBtn",
- },
- }).then((item) => {
- this.hijackBackEvent();
- if (item.length) {
- this.recipeContent.ingredients[index].unit = item;
- this.addListItemAction({
- item,
- listName: "units",
- });
- this.modalOpen = false;
- if (focus && this.recipeContent.ingredients.length - 1 === index)
- this.autoFocusRefField("ingredient", index);
- }
- });
- } else if (action) {
- this.recipeContent.ingredients[index].unit = action;
- this.hijackBackEvent();
- this.modalOpen = false;
- if (focus && this.recipeContent.ingredients.length - 1 === index)
- this.autoFocusRefField("ingredient", index);
- }
- });
- },
- autoFocusField(ref, showSoftInput) {
- this.$refs[ref].nativeView.focus();
- if (showSoftInput) {
- setTimeout(() => {
- Utils.ad.showSoftInput(this.$refs[ref].nativeView.android);
- }, 100);
- }
- },
- autoFocusRefField(ref, index) {
- this.$refs[ref][index].nativeView.focus();
- setTimeout(() => {
- Utils.ad.showSoftInput(this.$refs[ref][index].nativeView.android);
- }, 100);
- },
+
// NAVIGATION HANDLERS
- navigateBack() {
- if (this.hasChanges) {
- this.blockModal = true;
- this.$showModal(ConfirmDialog, {
- props: {
- title: "unsaved",
- description: localize("disc"),
- cancelButtonText: "disBtn",
- okButtonText: "kEdit",
- },
- }).then((action) => {
- this.blockModal = false;
- if (action != null && !action) {
- this.$navigateBack();
- this.releaseBackEvent();
- }
- });
- } else {
- this.$navigateBack();
- this.releaseBackEvent();
- }
- },
hijackBackEvent() {
AndroidApplication.on(
AndroidApplication.activityBackPressedEvent,
@@ -755,324 +951,26 @@ export default {
);
},
backEvent(args) {
- if (this.hasChanges && !this.blockModal) {
+ if (!this.modalOpen) {
args.cancel = true;
this.navigateBack();
}
},
- // DATA HANDLERS
- imageHandler() {
- this.clearEmptyFields(true);
- if (this.recipeContent.imageSrc) {
- this.blockModal = true;
+ navigateBack() {
+ if (this.hasChanges) {
+ this.modalOpen = true;
this.$showModal(ConfirmDialog, {
props: {
- title: "recPic",
- secondButtonText: "rBtn",
- cancelButtonText: "cBtn",
- okButtonText: "repBtn",
+ title: "unsaved",
+ description: localize("disc"),
+ cancelButtonText: "disBtn",
+ okButtonText: "kEdit",
},
}).then((action) => {
- this.blockModal = false;
- if (action > 0) {
- this.permissionCheck(this.permissionConfirmation, this.imagePicker);
- } else if (action < 0) {
- this.recipeContent.imageSrc = null;
- this.releaseBackEvent();
- } else if (action != null) {
- this.releaseBackEvent();
- }
+ this.modalOpen = false;
+ if (action != null && !action) this.$navigateBack();
});
- } else {
- this.permissionCheck(this.permissionConfirmation, this.imagePicker);
- }
- },
- permissionConfirmation() {
- return this.$showModal(ConfirmDialog, {
- props: {
- title: "grant",
- description: localize("reqAcc"),
- cancelButtonText: "nNBtn",
- okButtonText: "conBtn",
- },
- });
- },
- permissionCheck(confirmation, action) {
- if (!ApplicationSettings.getBoolean("storagePermissionAsked", false)) {
- confirmation().then((e) => {
- if (e) {
- Permissions.request("photo").then((status) => {
- switch (status[0]) {
- case "authorized":
- action();
- break;
- case "never_ask_again":
- ApplicationSettings.setBoolean(
- "storagePermissionAsked",
- true
- );
- break;
- case "denied":
- // Toast.makeText(localize("dend")).show();
- break;
- default:
- break;
- }
- });
- }
- });
- } else {
- Permissions.check("photo").then((res) => {
- res[0] !== "authorized"
- ? confirmation().then((e) => e && utils.openAppSettingsPage())
- : action();
- });
- }
- },
- imagePicker() {
- ApplicationSettings.setBoolean("storagePermissionAsked", true);
- // Filepicker.create({
- // mode: "single",
- // extensions: ["png", "jpeg", "jpg"],
- // })
- // .present()
- // .then((selection) => {
- // this.cacheImagePath = path.join(
- // knownFolders.temp().path,
- // `${this.getRandomID()}.jpg`
- // );
- // let imgPath = selection[0];
- // ImageSource.fromFile(imgPath).then((image) => {
- // ImageCropper.prototype
- // .show(
- // image,
- // {
- // width: 1080,
- // height: 1080,
- // },
- // {
- // hideBottomControls: true,
- // toolbarTitle: localize("cPic"),
- // statusBarColor: "#ff5200",
- // toolbarTextColor:
- // this.appTheme == "light" ? "#1A1A1A" : "#e9ecef",
- // toolbarColor:
- // this.appTheme == "light" ? "#e9ecef" : "#1A1A1A",
- // cropFrameColor: "#ff5200",
- // }
- // )
- // .then((cropped) => {
- // cropped.image.saveToFile(this.cacheImagePath, "jpg", 75);
- // this.recipeContent.imageSrc = this.cacheImagePath;
- // });
- // });
- // });
- },
- // INPUT FIELD HANDLERS
- splitTags() {
- let tags = [];
- let string;
- if (this.tags) {
- tags = this.tags
- .split(" ")
- .map((e) => {
- string = e.replace(/^[^\w\s]+/, "");
- if (/^[A-Za-z]+/.test(string)) {
- return string.charAt(0).toUpperCase() + string.slice(1);
- }
- })
- .filter((e) => e);
- }
- this.recipeContent.tags = tags;
- },
- joinTags() {
- this.tags = this.recipeContent.tags.join(" ");
- },
- showUndoBar(message) {
- return new Promise((resolve, reject) => {
- this.showUndo = true;
- this.appbar.translateY = 0;
- this.snackMsg = message;
- this.countdown = 5;
- let a = 5;
- clearTimeout(undoTimer);
- undoTimer = setInterval(() => {
- if (this.undo) {
- this.showUndo = this.undo = false;
- clearTimeout(undoTimer);
- resolve(true);
- }
- this.countdown = Math.round((a -= 0.1));
- if (this.countdown < 1) {
- this.showUndo = false;
- clearTimeout(undoTimer);
- reject(true);
- }
- }, 100);
- });
- },
- undoDel() {
- this.undo = true;
- },
- addIngredient() {
- let ingredients = this.recipeContent.ingredients;
- let unit = ingredients.length
- ? ingredients[ingredients.length - 1].unit
- : "unit";
- this.recipeContent.ingredients.push({
- item: "",
- quantity: null,
- unit,
- });
- },
- removeIngredient(index) {
- this.modalOpen = true;
- if (this.recipeContent.ingredients[index].item.length) {
- let item = this.recipeContent.ingredients[index];
- this.recipeContent.ingredients.splice(index, 1);
- this.showUndoBar("rmIng").then(
- (res) => res && this.recipeContent.ingredients.splice(index, 0, item)
- );
- } else {
- this.recipeContent.ingredients.splice(index, 1);
- }
- setTimeout((e) => (this.modalOpen = false), 200);
- },
- addInstruction() {
- this.recipeContent.instructions.push("");
- },
- removeInstruction(index) {
- if (this.recipeContent.instructions[index].length) {
- let item = this.recipeContent.instructions[index];
- this.recipeContent.instructions.splice(index, 1);
- this.showUndoBar("rmIns").then(
- (res) => res && this.recipeContent.instructions.splice(index, 0, item)
- );
- } else this.recipeContent.instructions.splice(index, 1);
- },
- addNote() {
- this.recipeContent.notes.push("");
- },
- removeNote(index) {
- if (this.recipeContent.notes[index].length) {
- let item = this.recipeContent.notes[index];
- this.recipeContent.notes.splice(index, 1);
- this.showUndoBar("rmN").then((res) =>
- this.recipeContent.notes.splice(index, 0, item)
- );
- } else this.recipeContent.notes.splice(index, 1);
- },
- getCombinationTitle(id) {
- return this.recipes.filter((e) => e.id === id)[0].title;
- },
- showCombinations() {
- Utils.ad.dismissSoftInput();
- this.modalOpen = true;
- this.releaseBackEvent();
- let existingCombinations = [
- ...this.recipeContent.combinations,
- this.recipeContent.id,
- ];
- let filteredRecipes = this.recipes.filter(
- (e) => !existingCombinations.includes(e.id)
- );
- this.$showModal(ActionDialogWithSearch, {
- props: {
- title: "selRec",
- recipes: filteredRecipes,
- },
- }).then((res) => {
- this.hijackBackEvent();
- if (res) {
- this.recipeContent.combinations.push(res);
- }
- });
- },
- removeCombination(id) {
- let index = this.recipeContent.combinations.indexOf(id);
- this.recipeContent.combinations.splice(index, 1);
- this.unSyncCombinations.push(id);
- this.showUndoBar("rmCmb").then((res) =>
- this.recipeContent.combinations.splice(index, 0, id)
- );
- },
- // SAVE OPERATION
- clearEmptyFields(bool) {
- if (!this.recipeContent.title && !bool)
- this.recipeContent.title = localize("untRec");
- if (!this.recipeContent.yield.quantity)
- this.recipeContent.yield.quantity = 1;
- this.recipeContent.ingredients = this.recipeContent.ingredients.filter(
- (e) => e.item
- );
- let vm = this;
-
- function clearEmpty(arr) {
- vm.recipeContent[arr] = vm.recipeContent[arr].filter((e) => e);
- }
- clearEmpty("instructions");
- clearEmpty("notes");
- },
- saveOperation() {
- this.saving = this.modalOpen = true;
- this.clearEmptyFields();
- this.recipeContent.lastModified = new Date();
- ApplicationSettings.setString(
- "previousCuisine",
- this.recipeContent.cuisine
- );
- ApplicationSettings.setString(
- "previousCategory",
- this.recipeContent.category
- );
- ApplicationSettings.setString(
- "previousYieldUnit",
- this.recipeContent.yield.unit
- );
- if (this.cacheImagePath) {
- let recipeImage = path.join(
- knownFolders.documents().getFolder("EnRecipes").getFolder("Images")
- .path,
- `${this.getRandomID()}.jpg`
- );
- let binarySource = File.fromPath(this.cacheImagePath).readSync();
- File.fromPath(recipeImage).writeSync(binarySource);
- this.recipeContent.imageSrc = recipeImage;
- knownFolders.temp().clear();
- }
- if (this.recipeContent.imageSrc) {
- if (
- this.tempRecipeContent.imageSrc &&
- this.tempRecipeContent.imageSrc !== this.recipeContent.imageSrc
- ) {
- getFileAccess().deleteFile(this.tempRecipeContent.imageSrc);
- }
- } else if (this.tempRecipeContent.imageSrc) {
- getFileAccess().deleteFile(this.tempRecipeContent.imageSrc);
- }
- this.unSyncCombinationsAction({
- id: this.recipeID,
- combinations: this.unSyncCombinations,
- });
- this.saveRecipe();
- },
- saveRecipe() {
- if (this.recipeID) {
- this.overwriteRecipeAction({
- id: this.recipeID,
- recipe: this.recipeContent,
- });
- } else {
- this.recipeContent.id = this.newRecipeID;
- this.addRecipeAction({
- id: this.newRecipeID,
- recipe: this.recipeContent,
- });
- }
- setTimeout(() => {
- this.saving = false;
- }, 100);
- this.$navigateBack();
+ } else this.$navigateBack();
},
},
created() {
@@ -1082,19 +980,16 @@ export default {
this.title = this.recipeID ? "editRec" : "newRec";
if (this.recipeID) {
let recipe = this.recipes.filter((e) => e.id === this.recipeID)[0];
- Object.assign(this.recipeContent, JSON.parse(JSON.stringify(recipe)));
- Object.assign(
- this.tempRecipeContent,
- JSON.parse(JSON.stringify(this.recipeContent))
- );
- if (this.recipeContent.tags.length) this.joinTags();
+ Object.assign(this.recipe, JSON.parse(JSON.stringify(recipe)));
+ Object.assign(this.tempRecipe, JSON.parse(JSON.stringify(this.recipe)));
+ if (this.recipe.tags.length) this.joinTags();
} else {
- this.recipeContent.cuisine = this.selectedCuisine
+ this.recipe.cuisine = this.selectedCuisine
? /all/.test(this.selectedCuisine)
? "Undefined"
: this.selectedCuisine
: ApplicationSettings.getString("previousCuisine", "Undefined");
- this.recipeContent.category = this.selectedCategory
+ this.recipe.category = this.selectedCategory
? /all/.test(this.selectedCategory)
? "Undefined"
: this.selectedCategory
@@ -1103,20 +998,16 @@ export default {
this.tags = this.selectedTag;
this.splitTags();
}
- this.recipeContent.yield.unit = ApplicationSettings.getString(
+ this.recipe.yield.unit = ApplicationSettings.getString(
"previousYieldUnit",
"Serving"
);
- if (this.filterFavourites) this.recipeContent.isFavorite = true;
- if (this.filterTrylater) this.recipeContent.tried = false;
- this.recipeContent.created = new Date();
- Object.assign(
- this.tempRecipeContent,
- JSON.parse(JSON.stringify(this.recipeContent))
- );
+ if (this.filterFavourites) this.recipe.isFavorite = true;
+ if (this.filterTrylater) this.recipe.tried = false;
+ this.recipe.created = new Date();
+ Object.assign(this.tempRecipe, JSON.parse(JSON.stringify(this.recipe)));
this.newRecipeID = this.getRandomID();
}
- this.hijackBackEvent();
},
};
diff --git a/app/components/EnRecipes.vue b/app/components/EnRecipes.vue
index 45939e86..b44e1d34 100644
--- a/app/components/EnRecipes.vue
+++ b/app/components/EnRecipes.vue
@@ -8,7 +8,7 @@
for="recipe in getList"
@loaded="onListLoad"
:itemTemplateSelector="getLayout"
- :colWidth="layout == 'grid' ? '50%' : '100%'"
+ :colWidth="layout == 'grid' || layout == 'photogrid' ? '50%' : '100%'"
@scroll="!selectMode && onScroll($event)"
>
@@ -31,20 +31,20 @@
v-for="(item, index) in topmenu"
:key="index"
:class="{
- select: currentComponent === item.component,
+ select: currentComponent === item.title,
}"
- @touch="touchSelector($event, item.component)"
+ @touch="touchSelector($event, item.title, item.title)"
>
-
+
+
+
+
+
+
+
+
+
+
-
+
@@ -200,7 +239,7 @@
@@ -224,7 +263,7 @@
"
>
-
+
@@ -273,7 +312,7 @@
rows="auto"
columns="auto"
class="appbar toolbar"
- v-if="showTools"
+ :hidden="!showTools"
>
-
+ colSpan="3"
+ orientation="horizontal"
+ :hidden="!recipes.length || selectMode || showSearch"
+ >
+
+
+
+
-
-
= 27 && window.setNavigationBarColor(new Color(color).android);
@@ -551,32 +584,29 @@ export default {
setColors("#000000");
break;
}
- sdkv >= 23 && this.appTheme == "Light"
- ? decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR)
- : decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_DARK_STATUS_BAR);
-
- sdkv >= 27 && this.appTheme == "Light"
- ? decorView.setSystemUiVisibility(
- View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
- )
- : decorView.setSystemUiVisibility(
- View.SYSTEM_UI_FLAG_DARK_NAVIGATION_BAR
- );
+ if (sdkv >= 27)
+ this.appTheme == "Light"
+ ? decorView.setSystemUiVisibility(
+ View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
+ )
+ : decorView.setSystemUiVisibility(
+ View.SYSTEM_UI_FLAG_DARK_NAVIGATION_BAR
+ );
},
onPageLoad(args) {
const page = args.object;
page.bindingContext = new Observable();
this.filterFavourites
- ? this.setComponent("Favourites")
+ ? this.setComponent("favourites")
: this.filterTrylater
- ? this.setComponent("Try Later")
+ ? this.setComponent("trylater")
: this.selectedCuisine
? this.setComponent("Filtered recipes")
: this.setComponent("EnRecipes");
if (this.shakeEnabled) {
if (utils.hasAccelerometer())
startAccelerometerUpdates((data) => this.onSensorData(data));
- else this.setShakeAction(false);
+ else this.setShake(false);
}
this.hijackBackEvent();
setTimeout(() => {
@@ -606,22 +636,25 @@ export default {
this.scrollPos = Math.abs(y);
let ab = this.appbar.translateY;
if (!scrollUp && ab == 0) {
- this.animateInOut(
- 250,
- false,
- (val) => (this.appbar.translateY = val * 64)
- );
+ this.appbar.animate({
+ translate: { x: 0, y: 64 },
+ duration: 250,
+ curve: CoreTypes.AnimationCurve.ease,
+ });
} else if (scrollUp && ab == 64) {
- this.animateInOut(
- 250,
- true,
- (val) => (this.appbar.translateY = val * 64)
- );
+ this.appbar.animate({
+ translate: { x: 0, y: 0 },
+ duration: 250,
+ curve: CoreTypes.AnimationCurve.ease,
+ });
}
}
},
getSpanSize(index) {
- return this.layout == "grid" && (index == 0 || index == 1) ? 2 : 1;
+ return (this.layout == "grid" || this.layout == "photogrid") &&
+ (index == 0 || index == 1)
+ ? 2
+ : 1;
},
getLayout(args, index, items) {
return index == 0 ? "header" : index == 1 ? "lists" : this.layout;
@@ -646,7 +679,7 @@ export default {
props: {
title: "srt",
list: [
- "Title",
+ "title",
"Rating",
"Quickest first",
"Slowest first",
@@ -658,7 +691,7 @@ export default {
},
}).then((action) => {
if (action && action !== "Cancel" && this.sortType !== action) {
- this.setSortTypeAction(action);
+ this.setSortType(action);
ApplicationSettings.setString("sortType", action);
this.updateSort();
}
@@ -668,6 +701,8 @@ export default {
//FILTER
openFilters() {
+ this.setComponent("EnRecipes");
+ this.filterFavourites = this.filterTrylater = false;
this.showTools = false;
this.releaseBackEvent();
this.$showModal(Filters).then(() => this.hijackBackEvent());
@@ -917,35 +952,27 @@ export default {
let dl1 = difficultyLevel(a.difficulty);
let dl2 = difficultyLevel(b.difficulty);
switch (this.sortType) {
- case "Title":
+ case "title":
return titleOrder > 0 ? 1 : titleOrder < 0 ? -1 : 0;
- break;
case "Quickest first":
return d1 > d2 ? 1 : d1 < d2 ? -1 : 0;
- break;
case "Slowest first":
return d1 > d2 ? -1 : d1 < d2 ? 1 : 0;
- break;
case "Rating":
return r1 > r2 ? -1 : r1 < r2 ? 1 : 0;
- break;
case "Difficulty level":
return dl1 > dl2 ? 1 : dl1 < dl2 ? -1 : 0;
- break;
case "Last updated":
return ld1 < ld2 ? 1 : ld1 > ld2 ? -1 : 0;
- break;
case "Newest first":
return cd1 < cd2 ? 1 : cd1 > cd2 ? -1 : 0;
- break;
case "Oldest first":
return cd1 < cd2 ? -1 : cd1 > cd2 ? 1 : 0;
- break;
}
},
getItemPos(id) {
let length = this.filteredRecipes.length;
- let l2 = this.layout == "grid";
+ let l2 = this.layout == "grid" || this.layout == "photogrid";
let oddOrEven = this.oddOrEven(id);
let itemPos =
id == this.filteredRecipes[0].id ||
@@ -995,7 +1022,7 @@ export default {
args.cancel = true;
this.clearSelection();
} else if (
- ["Favourites", "Try Later", "Filtered recipes"].includes(
+ ["favourites", "trylater", "Filtered recipes"].includes(
this.currentComponent
)
) {
@@ -1019,9 +1046,9 @@ export default {
},
});
} else if (title !== this.currentComponent) {
- this.setComponent(to);
- this.filterFavourites = to == "Favourites";
- this.filterTrylater = to == "Try Later";
+ this.setComponent(title);
+ this.filterFavourites = to == "favourites";
+ this.filterTrylater = to == "trylater";
this.clearFilter();
}
},
@@ -1051,11 +1078,9 @@ export default {
duration: 250,
curve: "easeOut",
},
- // backstackVisible: false,
});
},
viewRandomRecipe() {
- // this.showFAB =
this.showTools = false;
this.$navigateTo(ViewRecipe, {
props: {
@@ -1067,15 +1092,14 @@ export default {
duration: 250,
curve: "easeOut",
},
- backstackVisible: false,
});
},
- touchSelector({ object, action }, comp) {
+ touchSelector({ object, action }, comp, title) {
let selected = this.currentComponent == comp;
object.className = action.match(/down|move/)
? `segment ${selected ? "select" : "fade"}`
: `segment ${selected && "select"}`;
- if (action == "up") this.navigateTo(comp, comp);
+ if (action == "up") this.navigateTo(comp, title);
},
touchTool({ object, action }, comp, value) {
object.className = action.match(/down|move/) ? `tool fade` : `tool`;
@@ -1088,7 +1112,8 @@ export default {
if (!this.recipes.length) this.initRecipes();
this.initListItems();
if (!this.mealPlans.length) this.initMealPlans();
- this.setShakeAction(ApplicationSettings.getBoolean("shakeEnabled", true));
+ this.setShake(ApplicationSettings.getBoolean("shakeEnabled", true));
+ this.setFirstDay(ApplicationSettings.getBoolean("mondayFirst", false));
},
};
diff --git a/app/components/MealPlanner.vue b/app/components/MealPlanner.vue
index 66916744..8a2ecd79 100644
--- a/app/components/MealPlanner.vue
+++ b/app/components/MealPlanner.vue
@@ -30,7 +30,7 @@
class="dayName"
row="1"
:col="i"
- v-for="(d, i) in dNames"
+ v-for="(d, i) in getDayNames"
:key="d"
:text="d | L"
/>
@@ -94,14 +94,14 @@
row="1"
@loaded="onAppBarLoad"
class="appbar"
- v-show="!showUndo"
+ :hidden="showUndo"
columns="auto, *, auto, auto"
>
@@ -115,19 +115,19 @@
-
+
-
+
-
-
\ No newline at end of file
diff --git a/app/components/Settings/Database.vue b/app/components/Settings/Database.vue
index 26132fd5..e74edf19 100644
--- a/app/components/Settings/Database.vue
+++ b/app/components/Settings/Database.vue
@@ -28,7 +28,7 @@
-
+
+
@@ -71,9 +72,6 @@ import {
Observable,
Application,
} from "@nativescript/core";
-import * as Permissions from "@nativescript-community/perms";
-import { Zip } from "@nativescript/zip";
-import { openFilePicker } from "@nativescript-community/ui-document-picker";
import { localize } from "@nativescript/localize";
import ConfirmDialog from "../modal/ConfirmDialog.vue";
import { mapState, mapActions } from "vuex";
@@ -84,7 +82,7 @@ export default {
data() {
return {
backupFolder: null,
- backupProgress: 0,
+ progress: null,
toast: null,
};
},
@@ -118,7 +116,6 @@ export default {
icon: "imp",
title: "impBu",
subTitle: localize("impInfo"),
- // action: this.importCheck,
action: this.openZipFile,
},
{},
@@ -131,43 +128,63 @@ export default {
"importRecipesAction",
"importMealPlansAction",
"unlinkBrokenImages",
+ "clearImportSummary",
]),
onPageLoad(args) {
const page = args.object;
page.bindingContext = new Observable();
- const downloadsFolder = Folder.fromPath(
- android.os.Environment.getExternalStorageDirectory().getAbsolutePath()
- ).getFolder("Download").path;
- this.backupFolder = ApplicationSettings.getString(
- "backupFolder",
- downloadsFolder
- );
+ const ContentResolver = Application.android.nativeApp.getContentResolver();
+ this.backupFolder = ApplicationSettings.getString("backupFolder");
+ if (
+ !this.backupFolder ||
+ ContentResolver.getPersistedUriPermissions().isEmpty()
+ ) {
+ this.backupFolder = null;
+ }
},
// BACKUP FOLDER PICKER
- setBackupFolder() {
- utils.pickFolder().then((res) => {
- if (res != null) {
- this.backupFolder = res;
+ setBackupFolder(startExport) {
+ const ContentResolver = Application.android.nativeApp.getContentResolver();
+ const FLAGS =
+ android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION |
+ android.content.Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
+ utils.getBackupFolder().then((uri) => {
+ if (uri != null) {
+ if (this.backupFolder)
+ ContentResolver.releasePersistableUriPermission(
+ new android.net.Uri.parse(this.backupFolder),
+ FLAGS
+ );
+ this.backupFolder = uri.toString();
ApplicationSettings.setString("backupFolder", this.backupFolder);
+ // PERSIST PERMISSIONS
+ ContentResolver.takePersistableUriPermission(uri, FLAGS);
+ if (startExport && this.backupFolder) {
+ this.exportBackup();
+ }
}
});
},
+
// EXPORT HANDLERS
exportCheck() {
+ const ContentResolver = Application.android.nativeApp.getContentResolver();
if (!this.recipes.length) {
this.toast = localize("aFBu");
utils.timer(5, (val) => {
if (!val) this.toast = val;
});
} else {
- this.permissionCheck(
- this.permissionConfirmation,
- localize("reqAcc"),
- this.exportBackup
- );
+ if (
+ !this.backupFolder ||
+ ContentResolver.getPersistedUriPermissions().isEmpty()
+ ) {
+ this.setBackupFolder(true);
+ } else this.exportBackup();
}
},
exportBackup() {
+ this.progress = localize("expip");
this.exportFiles("create");
let date = new Date();
let formattedDate =
@@ -183,17 +200,11 @@ export default {
let filename = `EnRecipes_${formattedDate}.zip`;
let fromPath = path.join(knownFolders.documents().path, "EnRecipes");
- let sdcard = android.os.Environment.isExternalStorageManager();
- let destPath = path.join(this.backupFolder, filename);
- console.log(sdcard);
- Zip.zip({
- directory: fromPath,
- archive: destPath,
- onProgress: (progress) => (this.backupProgress = progress),
- }).then(() => {
- this.showExportSummary(filename);
- this.exportFiles("delete");
- });
+ utils.Zip.zip(fromPath, this.backupFolder, filename)
+ .then((res) => {
+ if (res) this.showExportSummary(filename);
+ })
+ .catch((err) => console.log("Backup error: ", err));
},
exportFiles(option) {
const folder = path.join(knownFolders.documents().path, "EnRecipes");
@@ -240,80 +251,140 @@ export default {
this.units.length && userUnitsFile.remove();
this.mealPlans.length && mealPlansFile.remove();
break;
- default:
- break;
}
},
writeDataToFile(file, data) {
file.writeText(JSON.stringify(data));
},
- // IMPORT HANDLERS
- importCheck() {
- this.permissionCheck(
- this.permissionConfirmation,
- localize("reqAcc"),
- this.openZipFile
- );
- },
- openZipFile() {
- const ContentResolver = Application.android.nativeApp.getContentResolver();
-
- utils.getBackupFile().then((uri) => {
- console.log(uri);
- const inputStream = ContentResolver.openInputStream(uri);
- console.log(inputStream);
- let newFile = knownFolders.temp().getFile("test.zip");
- console.log(newFile);
- try {
- const input = new java.io.BufferedInputStream(inputStream);
- console.log(input);
- const outputStream = new java.io.BufferedOutputStream(
- new java.io.FileOutputStream(newFile.path)
- );
- console.log(outputStream);
- let size = inputStream.available();
- console.log(size);
- let buffer = Array.create("byte", size);
- input.read(buffer);
- do {
- outputStream.write(buffer);
- } while (input.read(buffer) != -1);
- } catch (e) {
- console.log(e);
- } finally {
- outputStream.flush();
- outputStream.close();
- input.close();
- }
-
- // console.log(zipInputStream);
-
- // console.log(zipInputStream);
- // let extractedFile = new java.io.File(
- // knownFolders.temp().path + "/tmp.zip"
- // );
- // if (!extractedFile.exists()) {
- // extractedFile.mkdirs();
- // }
- // console.log(extractedFile);
- // let outputStream = new java.io.OutputStream(extractedFile);
-
- // android.os.FileUtils.copy(inputStream, outputStream);
- // let outputStream = new java.io.FileOutputStream(extractedFile);
- // console.log(outputStream);
- // while ((readLen = zipInputStream.read(readBuffer)) != -1) {
- // outputStream.write(readBuffer, 0, readLen);
- // }
- // console.log(outputStream, 2);
+ showExportSummary(filename) {
+ this.progress = null;
+ this.$showModal(ConfirmDialog, {
+ props: {
+ title: "expSuc",
+ description: `Backed up to ${filename}`,
+ okButtonText: "OK",
+ },
});
- // openFilePicker({
- // extensions: ["zip"],
- // }).then((res) => this.validateZipContent(res.files[0]));
},
- importDataToDB(data, db, zipPath) {
+
+ // IMPORT HANDLERS
+ openZipFile() {
+ utils.getBackupFile().then((uri) => {
+ let dest = path.join(knownFolders.temp().path, "tempUnZip");
+ utils.Zip.unzip(uri, dest)
+ .then((res) => {
+ if (res) this.validateZipContent(res, uri);
+ })
+ .catch(() => this.failedImport(localize("buInc")));
+ });
+ },
+ validateZipContent(extractedFolderPath, uri) {
+ this.progress = localize("impip");
+ let cacheFolderPath = extractedFolderPath + "/EnRecipes";
+ const EnRecipesFilePath = cacheFolderPath + "/recipes.json";
+ const ImagesFolderPath = cacheFolderPath + "/Images";
+ const userCuisinesFilePath = cacheFolderPath + "/userCuisines.json";
+ const userCategoriesFilePath = cacheFolderPath + "/userCategories.json";
+ const userYieldUnitsFilePath = cacheFolderPath + "/userYieldUnits.json";
+ const userUnitsFilePath = cacheFolderPath + "/userUnits.json";
+ const mealPlansFilePath = cacheFolderPath + "/mealPlans.json";
+ if (Folder.exists(cacheFolderPath)) {
+ this.isFileDataValid([
+ {
+ path: EnRecipesFilePath,
+ db: "EnRecipesDB",
+ file: "recipes.json",
+ },
+ {
+ path: userCuisinesFilePath,
+ db: "userCuisinesDB",
+ file: "userCuisines.json",
+ },
+ {
+ path: userCategoriesFilePath,
+ db: "userCategoriesDB",
+ file: "userCategories.json",
+ },
+ {
+ path: userYieldUnitsFilePath,
+ db: "userYieldUnitsDB",
+ file: "userYieldUnits.json",
+ },
+ {
+ path: userUnitsFilePath,
+ db: "userUnitsDB",
+ file: "userUnits.json",
+ },
+ {
+ path: mealPlansFilePath,
+ db: "mealPlansDB",
+ file: "mealPlans.json",
+ },
+ ]);
+ } else {
+ Folder.fromPath(extractedFolderPath).remove();
+ this.progress = null;
+ this.failedImport(localize("buInc"));
+ }
+ if (Folder.exists(ImagesFolderPath)) {
+ const timer = setInterval(() => {
+ if (this.importSummary.found) {
+ this.importImages(uri, extractedFolderPath);
+ clearInterval(timer);
+ }
+ }, 100);
+ }
+ },
+ isFileDataValid(file) {
+ const files = file.filter((e) => File.exists(e.path));
+ if (files.length) {
+ let isValid = files.map((e) => false);
+ files.forEach((file, i) => {
+ File.fromPath(file.path)
+ .readText()
+ .then((data) => {
+ isValid[i] = this.hasValidJSON(data);
+ if (!isValid[i]) {
+ this.failedImport(
+ `${localize("buMod")}\n\n${localize("invFile")}: ${file.file}`
+ );
+ return 0;
+ }
+ if (isValid.every((e) => e === true)) {
+ files.forEach((file) => {
+ File.fromPath(file.path)
+ .readText()
+ .then((data) => {
+ this.importDataToDB(JSON.parse(data), file.db);
+ });
+ });
+ }
+ });
+ });
+ } else {
+ this.failedImport(localize("buEmp"));
+ }
+ },
+ failedImport(description) {
+ this.$showModal(ConfirmDialog, {
+ props: {
+ title: "impFail",
+ description,
+ okButtonText: "OK",
+ },
+ });
+ },
+ hasValidJSON(data) {
+ try {
+ JSON.parse(data) && Array.isArray(JSON.parse(data));
+ } catch (e) {
+ return false;
+ }
+ return true;
+ },
+ importDataToDB(data, db) {
switch (db) {
case "EnRecipesDB":
- this.importImages(zipPath);
this.importRecipesAction(data);
break;
case "userCuisinesDB":
@@ -343,133 +414,18 @@ export default {
case "mealPlansDB":
this.importMealPlansAction(data);
break;
- default:
- break;
}
},
- hasValidJSON(data) {
- try {
- JSON.parse(data) && Array.isArray(JSON.parse(data));
- } catch (e) {
- return false;
- }
- return true;
- },
- isFileDataValid(file) {
- const files = file.filter((e) => File.exists(e.path));
- if (files.length) {
- let isValid = files.map((e) => false);
- files.forEach((file, i) => {
- File.fromPath(file.path)
- .readText()
- .then((data) => {
- isValid[i] = this.hasValidJSON(data);
- if (!isValid[i]) {
- this.failedImport(
- `${localize("buMod")}\n\n${localize("invFile")}: ${file.file}`
- );
- return 0;
- }
- if (isValid.every((e) => e === true)) {
- files.forEach((file, i) => {
- File.fromPath(file.path)
- .readText()
- .then((data) => {
- this.importDataToDB(
- JSON.parse(data),
- file.db,
- file.zipPath
- );
- });
- });
- }
- });
- });
- } else {
- this.failedImport(localize("buEmp"));
- }
- },
- failedImport(description) {
- this.$showModal(ConfirmDialog, {
- props: {
- title: "impFail",
- description,
- okButtonText: "OK",
- },
- });
- },
- validateZipContent(zipPath) {
- console.log(zipPath);
- Zip.unzip({
- archive: zipPath,
- overwrite: true,
- onProgress: (progress) => (this.backupProgress = progress),
- }).then((extractedFolderPath) => {
- let cacheFolderPath = extractedFolderPath + "/EnRecipes";
- const EnRecipesFilePath = cacheFolderPath + "/recipes.json";
- const userCuisinesFilePath = cacheFolderPath + "/userCuisines.json";
- const userCategoriesFilePath = cacheFolderPath + "/userCategories.json";
- const userYieldUnitsFilePath = cacheFolderPath + "/userYieldUnits.json";
- const userUnitsFilePath = cacheFolderPath + "/userUnits.json";
- const mealPlansFilePath = cacheFolderPath + "/mealPlans.json";
- if (Folder.exists(cacheFolderPath)) {
- this.isFileDataValid([
- {
- zipPath,
- path: EnRecipesFilePath,
- db: "EnRecipesDB",
- file: "recipes.json",
- },
- {
- zipPath,
- path: userCuisinesFilePath,
- db: "userCuisinesDB",
- file: "userCuisines.json",
- },
- {
- zipPath,
- path: userCategoriesFilePath,
- db: "userCategoriesDB",
- file: "userCategories.json",
- },
- {
- zipPath,
- path: userYieldUnitsFilePath,
- db: "userYieldUnitsDB",
- file: "userYieldUnits.json",
- },
- {
- zipPath,
- path: userUnitsFilePath,
- db: "userUnitsDB",
- file: "userUnits.json",
- },
- {
- zipPath,
- path: mealPlansFilePath,
- db: "mealPlansDB",
- file: "mealPlans.json",
- },
- ]);
- } else {
+ importImages(uri, extractedFolderPath) {
+ let destPath = knownFolders.documents().path;
+ Folder.fromPath(destPath);
+ utils.Zip.unzip(uri, destPath).then((res) => {
+ if (res) {
+ this.showImportSummary();
+ this.unlinkBrokenImages();
+ this.exportFiles("delete");
Folder.fromPath(extractedFolderPath).remove();
- this.failedImport(localize("buInc"));
}
- if (Folder.exists(cacheFolderPath + "/Images")) {
- this.importImages(cacheFolderPath + "/Images");
- }
- });
- },
- importImages(sourcePath) {
- let dest = knownFolders.documents().path;
- Zip.unzip({
- archive: sourcePath,
- directory: dest,
- overwrite: true,
- onProgress: (progress) => (this.backupProgress = progress),
- }).then((res) => {
- this.showImportSummary();
- this.unlinkBrokenImages();
});
},
showImportSummary() {
@@ -478,6 +434,7 @@ export default {
let importedNote = `\n${imported} ${localize("recI")}`;
let existsNote = `\n${exists} ${localize("recE")}`;
let updatedNote = `\n${updated} ${localize("recU")}`;
+ this.progress = null;
this.$showModal(ConfirmDialog, {
props: {
title: "impSuc",
@@ -486,51 +443,9 @@ export default {
)}${importedNote}${existsNote}${updatedNote}`,
okButtonText: "OK",
},
- }).then(() => (this.backupProgress = 0));
- },
- showExportSummary(filename) {
- this.$showModal(ConfirmDialog, {
- props: {
- title: "expSuc",
- description: `Backed up to ${filename}`,
- okButtonText: "OK",
- },
- }).then(() => (this.backupProgress = 0));
- },
- // PERMISSIONS HANDLER
- permissionCheck(confirmation, description, action) {
- if (!ApplicationSettings.getBoolean("storagePermissionAsked", false)) {
- confirmation(description).then((e) => {
- if (e) {
- Permissions.request("photo").then((res) => {
- let status = res[Object.keys(res)[0]];
- if (status === "authorized") action();
- if (status !== "denied")
- ApplicationSettings.setBoolean("storagePermissionAsked", true);
- });
- }
- });
- } else {
- Permissions.check("photo").then((res) => {
- let status = res[Object.keys(res)[0]];
- if (status !== "authorized") {
- confirmation(description).then((e) => {
- e && utils.openAppSettingsPage();
- });
- } else action();
- });
- }
- },
- permissionConfirmation(description) {
- return this.$showModal(ConfirmDialog, {
- props: {
- title: "grant",
- description,
- cancelButtonText: "nNBtn",
- okButtonText: "conBtn",
- },
- });
+ }).then(() => this.clearImportSummary());
},
+
// HELPERS
touch({ object, action }, method) {
object.className = action.match(/down|move/) ? "option fade" : "option";
diff --git a/app/components/Settings/Help.vue b/app/components/Settings/Help.vue
index 0d68772c..f9d15120 100644
--- a/app/components/Settings/Help.vue
+++ b/app/components/Settings/Help.vue
@@ -6,7 +6,6 @@
rowSpan="2"
class="options-list"
for="item in items"
- @loaded="listViewLoad"
>
diff --git a/app/components/Settings/Interface.vue b/app/components/Settings/Interface.vue
index eb3b62b5..19d2f0ef 100644
--- a/app/components/Settings/Interface.vue
+++ b/app/components/Settings/Interface.vue
@@ -5,7 +5,6 @@
colSpan="2"
rowSpan="2"
class="options-list"
- @loaded="listViewLoad"
for="item in items"
>
@@ -29,11 +28,7 @@
-
+
@@ -50,6 +45,7 @@ import { localize, overrideLocale } from "@nativescript/localize";
import ActionDialog from "../modal/ActionDialog.vue";
import ConfirmDialog from "../modal/ConfirmDialog.vue";
import { mapState, mapActions } from "vuex";
+import * as utils from "~/shared/utils";
export default {
data() {
@@ -75,7 +71,7 @@ export default {
action: this.selectThemes,
},
{
- icon: "l1",
+ icon: "layout",
title: "listVM",
subTitle: localize(this.layout),
action: this.setLayoutMode,
@@ -142,7 +138,7 @@ export default {
this.$showModal(ActionDialog, {
props: {
title: "List view mode",
- list: ["Detailed", "Grid", "Simple", "Minimal"],
+ list: ["detailed", "grid", "photogrid", "simple", "minimal"],
},
}).then((action) => {
if (action && action !== "Cancel" && this.layoutMode !== action) {
diff --git a/app/components/Settings/Options.vue b/app/components/Settings/Options.vue
index 871c4e3b..9a6d42f4 100644
--- a/app/components/Settings/Options.vue
+++ b/app/components/Settings/Options.vue
@@ -5,7 +5,6 @@
colSpan="2"
rowSpan="2"
class="options-list"
- @loaded="listViewLoad"
for="item in items"
>
@@ -14,15 +13,18 @@
-
+
-
+
@@ -31,12 +33,26 @@
-
-
+
+
+
+
+
+
+
@@ -44,13 +60,17 @@
diff --git a/app/components/modal/Filters.vue b/app/components/modal/Filters.vue
index bcc2cd28..e5759e64 100644
--- a/app/components/modal/Filters.vue
+++ b/app/components/modal/Filters.vue
@@ -20,12 +20,7 @@
-
+
-
+