diff --git a/README.md b/README.md index b29fcc19..9c297a2e 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,13 @@ +## :warning: Important Notice :warning: + +To continue receiving updates, please update your EnRecipes to v2.0.0 + +There are some significant changes in this version. So, in order to continue, you must do the following: + +1. Export a full backup. +2. Uninstall EnRecipes. +3. Install v2.0.0 and Import your data. +

A Simple, Offline Recipe Manager

@@ -15,7 +25,7 @@ Donate to Vishnu Raghav


Important Links

-

User Guide - Privacy Policy - Contribution Guide - Roadmap - Telegram Group - Website

+

User Guide · Privacy Policy · Contribution Guide · Roadmap · Telegram Group · Website


## Features @@ -32,7 +42,7 @@ - Create meal plans - Set cooking timers - You can Import or Export your data -- Has Light, Dark and Black themes +- Light, Dark and Black themes ## Highlights @@ -41,10 +51,6 @@ - No special permissions required - No annoying ads or pop-ups -**Languages being translated**: - -[![Translation status](https://hosted.weblate.org/widgets/enrecipes/-/app-translations/multi-auto.svg)](https://hosted.weblate.org/engage/enrecipes/) - Check the [Roadmap](https://github.com/vishnuraghavb/EnRecipes/projects/1) for upcoming features. Please read the [User Guide](https://github.com/vishnuraghavb/EnRecipes/wiki/User-Guide) to get the most out of EnRecipes. @@ -55,11 +61,11 @@ Please read the [User Guide](https://github.com/vishnuraghavb/EnRecipes/wiki/Use | :---------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------: | | **Home - Light theme** | **Home - Dark theme** | | | | -| **Home - Black theme** | **Recipe view** | +| **Recipe view** | **Scale ingredients** | | | | -| **Share menu** | **Scale ingredients** | +| **Share menu** | **Meal Planner** | | | | -| **Meal planner** | **About** | +| **Cooking Timer** | **About** | ## Contribution @@ -75,19 +81,52 @@ You can, - [Join the Telegram group](http://t.me/enrecipes) (quicker replies) - Contact me at apps@vishnuraghav.com -### Looking to translate the app to your own language? +### Looking to translate EnRecipes? EnRecipes is being translated using [Weblate](https://hosted.weblate.org/engage/enrecipes/). See [translation instructions](https://github.com/vishnuraghavb/EnRecipes/wiki/Translation-Instructions) in the wiki for more information. - + + +Translation status ## Credits This app was written in my free time using NativeScript-Vue. I would like to thank all those people who helped me understand the concepts during the process and my special thanks to the NativeScript team and the community. I also would like to thank the members of the [EnRecipes Telegram group](https://t.me/enrecipes) for contributing their ideas for this project. -### Recipes used in the Screenshots +### Translation credits + +| Language | Translator(s) | +| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Arabic | [phwright](https://hosted.weblate.org/user/phwright/) | +| Catalan | J. Lavoie | +| Danish | [mondstern](https://hosted.weblate.org/user/mondstern/), Henrik Dankvardt, J. Lavoie, Allan Nordhøy, Jonas Hansen | +| Dutch | Heimen Stoffels | +| English (India) | Vishnu Raghav B | +| English (United Kingdom) | Vishnu Raghav B | +| English (United States) | Vishnu Raghav B | +| Finnish | J. Lavoie | +| French | J. Lavoie, Swann Fournial, fabeuss, [mondstern](https://hosted.weblate.org/user/mondstern/) | +| French (Canada) | Swann Fournial, J. Lavoie | +| French (Switzerland) | Swann Fournial, J. Lavoie | +| French (Belgium) | Swann Fournial, J. Lavoie | +| German | J. Lavoie, nautilusx, Swann Fournial | +| Hindi | Vishnu Raghav B, V | +| Indonesian | Reza Almanda, [mondstern](https://hosted.weblate.org/user/mondstern/) | +| Italian | J. Lavoie, [mondstern](https://hosted.weblate.org/user/mondstern/), Andrea Ghensi | +| Japanese | Y. Sakamoto, K. Herbert | +| Malayalam | Vishnu Raghav B | +| Norwegian Bokmål | Allan Nordhøy, [mondstern](https://hosted.weblate.org/user/mondstern/), Lars A Reinton | +| Portuguese | Sérgio Morais, [mondstern](https://hosted.weblate.org/user/mondstern/), J. Lavoie | +| Portuguese (Brazil) | [mondstern](https://hosted.weblate.org/user/mondstern/), Sérgio Morais, Wesley, Ricardo Zamarrenho Carvalho Correa, J. Lavoie, Nínive de Jesus Celestino, emmanuel einstein campos vasconcelos, Fabio Oliveira | +| Russian | dm9pZCAq, [mondstern](https://hosted.weblate.org/user/mondstern/), Leca | +| Spanish | taraletti, J. Lavoie, Sansom, [mondstern](https://hosted.weblate.org/user/mondstern/), Diego | +| Spanish (Argentina) | another-sapiens | +| Tamil | Vishnu Raghav B | + +### Screenshot recipe credits - **Meen Pollichathu** by [Bency Veronica](https://www.instagram.com/bencys_lil_kitchen) - **Curd Vada** by P. Shanmugalakshmi diff --git a/app/app.scss b/app/app.scss index ddb33624..7ce68960 100644 --- a/app/app.scss +++ b/app/app.scss @@ -17,7 +17,7 @@ $t1: 25; $t2: 21; $t3: 17; $t4: 14; -$t5: 12; // Base size +$t5: 12; // Base $t6: 10; Page { @@ -25,34 +25,35 @@ Page { font-size: $t4; } .ico { - font-family: 'enrecipes'; - font-size: 24; - vertical-alignment: center; - &.sm { + font-family: 'EnRecipes'; + font-size: 23; + &.s { font-size: $t3; opacity: 0.5; } } +.vc { + vertical-align: center; +} .tb { font-family: 'Inter-Bold', sans-serif; } -.tac { +.tc { text-align: center; } .tw { text-wrap: true; } -.pageTitle { - @extend .tb; - @extend .tw; + +.pTitle { font-size: $t1; padding: 16 16 24; } + .Light { color: $gray9; background: $gray1; Page, - .filters, .sticky { background: $gray1; } @@ -67,8 +68,9 @@ Page { .appbar, .modal { background: $gray0; + box-shadow: 0 2 rgba($gray10, 0.1); } - .fieldLabel, + .fLabel, .sub { color: $gray6; } @@ -76,7 +78,7 @@ Page { color: $gray3; background: $gray2; } - .snackBar { + .snackbar { color: $gray1; background: $gray9; } @@ -88,7 +90,6 @@ Page { color: $gray1; background: $gray9; Page, - .filters, .sticky { background: $gray9; } @@ -105,7 +106,7 @@ Page { color: $gray0; background: $gray8; } - .fieldLabel, + .fLabel, .sub { color: $gray5; } @@ -113,7 +114,7 @@ Page { color: $gray9; background: $gray10; } - .snackBar { + .snackbar { color: $gray9; background: $gray1; } @@ -125,7 +126,6 @@ Page { color: $gray2; background: $gray10; Page, - .filters, .sticky { background: $gray10; } @@ -142,7 +142,7 @@ Page { color: $gray1; background: $gray9; } - .fieldLabel, + .fLabel, .sub { color: $gray6; } @@ -150,7 +150,7 @@ Page { color: $gray10; background: $gray9; } - .snackBar { + .snackbar { color: $gray10; background: $gray2; } @@ -158,8 +158,9 @@ Page { color: $gray10; } } + TextField.combField, -#searchBar { +#search { border-color: transparent; } @@ -167,28 +168,24 @@ TextField.combField, // Elements TextField, TextView { - width: 100%; + // width: 100%; padding: 14 8; border-bottom-width: 1; } TextView { line-height: 4; } -#searchBar { - padding: 13 12; +#search { + padding: 13 8; } -.inputField { +.inputC { margin-bottom: 24; } -.fieldLabel { +.fLabel { font-size: $t5; } -.progressContainer { - width: 100%; -} progress { color: $orange; - width: 100%; height: 2; background-color: $gray5; } @@ -197,12 +194,17 @@ Switch { off-background-color: $gray5; } button { - background-color: transparent; z-index: 0; padding: 8; border-radius: 12; min-width: 0; min-height: 0; + text-transform: none; + background-color: transparent; + &.sst { + width: 48; + height: 48; + } &.ico { width: 48; height: 48; @@ -212,36 +214,28 @@ button { @extend .fade; } } + &.si { + width: 40; + height: 40; + } &.text { - @extend .tb; color: $orange; - &:active { - @extend .fade; - } + } + &.st { + font-size: $t5; + padding: 12; } &.big { margin-top: 8; padding: 16 0; } - &.sm { - font-size: $t5; - padding: 12; - } - &.min { - width: 40; - height: 40; - vertical-alignment: center; - } - &.fb:active { - @extend .fade; - } &.rate { margin: 0 4 0 0; width: 32; height: 32; - &:active { - @extend .fade; - } + } + &.fb:active { + @extend .fade; } } ActivityIndicator { @@ -255,52 +249,40 @@ ActivityIndicator { // Home .segment { border-radius: 12; - margin: 0 4 0 0; - padding: 0 12; - .value { - padding: 0 0 0 8; - vertical-alignment: center; - &.r { - padding: 0 8 0 0; - transform: scaleX(-1); - } + padding: 8; + .v { + padding: 0 4; } } -.select { - color: $orange; - @extend .hl; +.t3 { + font-size: $t3; } -.emptyState { +.empty { padding: 16 16 8; - label { - @extend .tw; - } - .title { - @extend .tb; - font-size: $t3; - } } // ----------------------------- // Recipe Item -.recipeItem { +.recipe { padding: 8 16; - .recipeInfo { - vertical-alignment: center; + .info { padding: 0 8 4; } .title { padding: 0 0 4; } } -.attrs { +.oh { orientation: horizontal; } +.t6 { + font-size: $t6; +} .attr { font-size: $t6; - padding: 1 4; + padding: 0 4 2; } -.simple .recipeInfo { +.simple .info { padding: 8 0; } .minimal .title { @@ -308,7 +290,7 @@ ActivityIndicator { } .grid { padding: 8; - .recipeInfo { + .info { padding: 8 0 4; } &.odd { @@ -318,18 +300,12 @@ ActivityIndicator { padding: 8 16 8 8; } } -.photogrid .recipeInfo { +.photogrid .info { padding: 8 0 0; } .lastItem { margin-bottom: 128; } -.selected { - @extend .hl; -} -.unselected { - background-color: transparent; -} .imgHolder { border-radius: 12; } @@ -351,9 +327,8 @@ ActivityIndicator { // ----------------------------- // Settings -.group-info { +.groupInfo { padding: 16 16 16 72; - line-height: 4; &.r { padding: 16 72 16 16; } @@ -375,14 +350,11 @@ ActivityIndicator { } } } -.listSpace { - height: 72; -} // ----------------------------- // About -.app-info { - .icon { +.appInfo { + .logo { horizontal-alignment: center; } .name { @@ -401,108 +373,62 @@ ActivityIndicator { margin: 24 16 0 0; vertical-align: top; } -.photoviewer { +.imgV { width: 96; height: 96; opacity: 0; background: #000; } -.attribute { +.attrT { margin: 8 16; .sub { font-size: $t5; } - .value { + .v { @extend .tb; @extend .tw; } } -.ingredient { +.check { padding: 0 16; - .value { - @extend .tw; - vertical-align: center; - padding: 14 16; - line-height: 4; - } -} -.instruction { - padding: 0 16; - .count { - @extend .tb; - font-size: $t3; - } - .value { - @extend .tw; + .v { padding: 14 16; line-height: 4; } } .done { opacity: 0.5; - .value { + .v { text-decoration: line-through; } } -.combination { - @extend .tw; - text-align: left; - padding: 16; - line-height: 4; -} .note { - @extend .tw; - line-height: 4; - padding: 16 0; -} -.dateInfo { - padding: 32 16 16; - font-size: $t5; + padding: 16 24; line-height: 4; } // ----------------------------- // AppBar + .appbar { - z-index: 4; - min-height: 56; - margin: 8; - padding: 4; + margin: 0 8 8; border-radius: 16; - .title { - @extend .tb; - @extend .tw; - vertical-align: center; - margin: 0 12; - line-height: 4; + padding: 2; + .ico { + margin: 2; } - .msg { - padding: 14 16; - margin: 0; - } - .fab { - margin-left: 8; - } - &.home { - margin: 8 8 0; - } -} -.sidebar { - margin-bottom: 0; } .toolbar { - z-index: 4; - padding: 4; - margin: 0 0 52; + height: 1; + vertical-align: bottom; + transform: translateY(48); + padding: 4 2; .tool { + orientation: horizontal; padding: 0 8; - label { - vertical-alignment: center; - } - .value, - .ico { - padding: 0 4; - } + } + .v { + padding: 0 4; } } .fab { @@ -512,64 +438,44 @@ ActivityIndicator { // ----------------------------- // EditRecipe -.sectionTitle { - @extend .tb; - @extend .tw; - font-size: $t2; - padding: 0; +.section { + padding: 0 16; margin: 32 0 16; } +.t2 { + font-size: $t2; +} .sticky { width: 100%; padding: 0 16 16; - margin: 0; -} -.countdown { - font-size: $t3; - color: $orange; } // ----------------------------- // MealPlanner -.monthSwitcher { - padding: 0 16; - .month { - vertical-alignment: center; - text-align: center; - font-size: $t3; - } -} .calendar { - padding: 0 16; - .dayName { - vertical-alignment: center; - text-align: center; - font-size: $t5; - } + padding: 0 16 16; .accent.sub { - color: rgba($orange, 0.5); + color: rgba($orange, 0.6); } } .plans { - padding: 8 16 80; - width: 100%; + margin: 0 16; .date { - font-size: $t2; - padding: 16 0; + padding: 16 0 8; + } + .type { + padding: 8 0; } .plan { - padding: 8 0; - } - .meal { - font-size: $t3; - padding: 8 0; - } - .planContent { min-height: 48; - padding: 8; + padding: 4 0; } - .attr { - padding: 0; + .info { + min-height: 40; + padding: 0 8; + } + .note { + padding: 4 0; } } @@ -589,35 +495,16 @@ ActivityIndicator { .input { padding: 0 16 8; } - .description { - line-height: 4; - padding: 0 16 8; - } ListPicker { width: 30%; height: 144; margin: 16 0; } .listItem { - letter-spacing: 0; - text-transform: none; line-height: 4; padding: 13 16; - margin: 0; background-color: transparent; } - .shareItem { - border-radius: 12; - margin: 0 8 8; - text-align: center; - .ico { - padding: 16 0 0; - } - .item { - @extend .tw; - padding: 8 16 16; - } - } .actions { padding: 4; } @@ -626,27 +513,25 @@ ActivityIndicator { margin: 0 0 8; } } -.noResInfo { - @extend .tac; - @extend .tw; - padding: 16; - line-height: 4; -} // ----------------------------- // Transitions -.hl { - animation-name: hl; +.select { + color: $orange; + animation-name: select; animation-duration: 0.2s; animation-fill-mode: forwards; animation-timing-function: ease; } -@keyframes hl { +.deselect { + background-color: transparent; +} +@keyframes select { 0% { background-color: transparent; } 100% { - background-color: rgba($orange, 0.2); + background-color: rgba($orange, 0.1); } } .fade { @@ -660,7 +545,7 @@ ActivityIndicator { opacity: 1; } 100% { - opacity: 0.5; + opacity: 0.75; } } @@ -678,3 +563,18 @@ ActivityIndicator { horizontal-alignment: right; } } +.har { + horizontal-alignment: right; + &.r { + horizontal-alignment: left; + } +} +.edge { + width: 16; +} +.ls { + height: 72; +} +.lh4 { + line-height: 4; +} diff --git a/app/components/CookingTimer.vue b/app/components/CookingTimer.vue index d0e4351f..24eaf053 100644 --- a/app/components/CookingTimer.vue +++ b/app/components/CookingTimer.vue @@ -1,5 +1,5 @@ @@ -58,7 +70,6 @@ import { localize } from "@nativescript/localize"; import { Observable, - CoreTypes, Application, Utils, Device, @@ -104,11 +115,11 @@ export default { ...mapState([ "icon", "recipes", - "timerSound", - "timerVibrate", - "timerPresets", - "activeTimers", - "FGService", + "timerS", + "timerV", + "timerPs", + "activeTs", + "FGS", "RTL", ]), hasBackStack() { @@ -116,24 +127,12 @@ export default { }, }, methods: { - ...mapActions([ - "addActiveTimer", - "removeActiveTimer", - "clearTimerInterval", - "addTimerPreset", - "updateActiveTimer", - "setFGService", - ]), + ...mapActions(["addAT", "removeAT", "clearATIs", "updateAT", "setFgS"]), pgLoad({ object }) { object.bindingContext = new Observable(); - if (this.activeTimers.filter((e: any) => e.done).length) - this.openReminder(); - this.keepScreenOnCountUp(); + if (this.activeTs.filter((e: any) => e.done).length) this.openReminder(); setNumber("isTimer", 1); }, - pgUnload() { - utils.keepScreenOn(0); - }, abLoad({ object }) { this.appbar = object; }, @@ -151,19 +150,8 @@ export default { scrollUp = y < this.scrollPos; this.scrollPos = Math.abs(y); let ab = this.appbar.translateY; - if (!scrollUp && ab == 0) { - this.appbar.animate({ - translate: { x: 0, y: 64 }, - duration: 200, - curve: CoreTypes.AnimationCurve.ease, - }); - } else if (scrollUp && ab == 64) { - this.appbar.animate({ - translate: { x: 0, y: 0 }, - duration: 200, - curve: CoreTypes.AnimationCurve.ease, - }); - } + if (!scrollUp && ab == 0) this.animateBar(this.appbar, 0); + else if (scrollUp && ab == 64) this.animateBar(this.appbar, 1); } }, @@ -192,8 +180,8 @@ export default { // NOTIFICATION HANDLERS timerInfo() { - let activeCount = this.activeTimers.length; - let pausedCount = this.activeTimers.filter((e) => e.isPaused).length; + let activeCount = this.activeTs.length; + let pausedCount = this.activeTs.filter((e) => e.isPaused).length; let ongoingCount = activeCount - pausedCount; this.foregroundService(activeCount); function show() { @@ -208,14 +196,12 @@ export default { title: localize("timer"), }); } - if (this.FGService) - setTimeout(() => this.activeTimers.length && show(), 250); - this.keepScreenOnCountUp(); + if (this.FGS) setTimeout(() => this.activeTs.length && show(), 250); utils.wakeLock(ongoingCount); }, timerAlert() { let title, description, bID; - let firedTimers = this.activeTimers.filter((e) => e.done); + let firedTimers = this.activeTs.filter((e) => e.done); let timer = firedTimers[0]; if (firedTimers.length > 1) { title = localize("texp", firedTimers.length); @@ -240,9 +226,9 @@ export default { multi: firedTimers.length > 1, nID: 7, priority: 1, - sound: this.timerSound.uri, + sound: this.timerS.uri, title, - vibrate: this.timerVibrate, + vibrate: this.timerV, }); if (firedTimers.length == 1) { Application.android.registerBroadcastReceiver(bID, (ctx, intent) => { @@ -260,7 +246,7 @@ export default { } }, openReminder() { - this.clearTimerInterval(); + this.clearATIs(); this.$showModal(TimerReminder, { fullscreen: true, props: { @@ -271,7 +257,7 @@ export default { showToast: this.showToast, }, }).then(() => { - this.clearTimerInterval(); + this.clearATIs(); this.key = Math.floor(Math.random() * 900) + 100; }); }, @@ -281,16 +267,16 @@ export default { ctx, com.tns.ForegroundService.class ); - if (n && !this.FGService) { + if (n && !this.FGS) { parseInt(Device.sdkVersion) < 26 ? ctx.startService(intent) : ctx.startForegroundService(intent); - this.setFGService(1); - setNumber("FGService", 1); - } else if (!this.activeTimers.length) { + this.setFgS(1); + setNumber("FGS", 1); + } else if (!this.activeTs.length) { ctx.stopService(intent); - this.setFGService(0); - setNumber("FGService", 0); + this.setFgS(0); + setNumber("FGS", 0); } }, @@ -299,14 +285,14 @@ export default { this.$showModal(TimePickerHMS, { props: { title: "ntmr", - label: `${localize("tmr", this.activeTimers.length + 1)}`, + label: `${localize("tmr", this.activeTs.length + 1)}`, action: "strtBtn", - showPreset: this.timerPresets.length, + showPreset: this.timerPs.length, }, }).then((res) => { if (res) { if (res == "presets") { - let list = this.timerPresets.map( + let list = this.timerPs.map( (e) => `${e.label} - ${this.formattedTime(e.time)}` ); this.$showModal(Action, { @@ -317,22 +303,22 @@ export default { }).then((preset) => { if (preset) { let timer = JSON.parse( - JSON.stringify(this.timerPresets[list.indexOf(preset)]) + JSON.stringify(this.timerPs[list.indexOf(preset)]) ); timer.id = utils.getRandomID(1); timer.recipeID = this.recipeID; timer.timerInt = timer.isPaused = 0; timer.preset = timer.mode = 1; - this.addActiveTimer({ + this.addAT({ timer, - i: this.activeTimers.length, + i: this.activeTs.length, }); this.timerInfo(); } }); } else { let mode = res.time != "00:00:00" ? 1 : 0; - this.addActiveTimer({ + this.addAT({ timer: { id: utils.getRandomID(1), label: res.label, @@ -344,7 +330,7 @@ export default { done: 0, mode, }, - i: this.activeTimers.length, + i: this.activeTs.length, }); this.timerInfo(); } @@ -352,11 +338,11 @@ export default { }); }, removeTimer(id, noUndo) { - let i = this.activeTimers.findIndex((e) => e.id == id); - let temp = this.activeTimers[i]; + let i = this.activeTs.findIndex((e) => e.id == id); + let temp = this.activeTs[i]; clearInterval(temp.timerInt); temp.timerInt = 0; - this.removeActiveTimer(i); + this.removeAT(i); let secs = [getNumber(`${temp.id}c`, 0), getNumber(`${temp.id}d`, 0)]; function removeSettings() { remove(`${temp.id}c`); @@ -368,7 +354,7 @@ export default { .then(() => { setNumber(`${temp.id}c`, secs[0]), setNumber(`${temp.id}d`, secs[1]), - this.addActiveTimer({ + this.addAT({ timer: temp, i, }); @@ -382,7 +368,7 @@ export default { togglePause(timer, n) { timer.isPaused = typeof n === "number" ? n : (!timer.isPaused as boolean | 0); - this.updateActiveTimer(timer); + this.updateAT(timer); n ? 0 : this.timerInfo(); }, showToast(data) { @@ -390,7 +376,7 @@ export default { this.animateBar(this.appbar, 0).then(() => { this.showUndo = 0; this.toast = localize(data); - this.animateBar(this.toastbar, 1); + this.animateBar(this.toastbar, 1, 1); let a = 5; clearInterval(barTimer); barTimer = setInterval(() => a-- < 1 && this.hideBar(), 1000); @@ -404,7 +390,7 @@ export default { this.showUndo = 1; this.snackMsg = message; this.countdown = 5; - this.animateBar(this.snackbar, 1).then(() => { + this.animateBar(this.snackbar, 1, 1).then(() => { let a = 5; clearInterval(barTimer); barTimer = setInterval(() => { @@ -456,14 +442,9 @@ export default { }, // HELPERS - keepScreenOnCountUp() { - utils.keepScreenOn( - this.activeTimers.filter((e: any) => !e.isPaused).length - ); - }, }, created() { - this.clearTimerInterval(); + this.clearATIs(); this.recipeID && this.addTimer(); }, destroyed() { diff --git a/app/components/EditRecipe.vue b/app/components/EditRecipe.vue index 0a54e8fd..97fc55cf 100644 --- a/app/components/EditRecipe.vue +++ b/app/components/EditRecipe.vue @@ -3,7 +3,11 @@ - + - -