import Vue from 'nativescript-vue' import Vuex from 'vuex' Vue.use(Vuex) import { openOrCreate } from '@akylas/nativescript-sqlite' import { getFileAccess, File, Application, knownFolders, path, } from '@nativescript/core' import { getNumber, setNumber, getString, setString, } from '@nativescript/core/application-settings' import * as utils from '~/shared/utils' // OPEN DATABASE FILE const db = openOrCreate( path.join(knownFolders.documents().path, 'EnRecipes.db') ) // CREATE recipes TABLE db.execute( 'CREATE TABLE IF NOT EXISTS recipes (id TEXT PRIMARY KEY, image TEXT, title TEXT, cuisine TEXT, category TEXT, tags TEXT, prepTime TEXT, cookTime TEXT, yieldQuantity TEXT, yieldUnit TEXT, difficulty TEXT, rating INT, ingredients TEXT, instructions TEXT, combinations TEXT, notes TEXT, favorite INT, tried INT, lastTried INT, lastModified INT, created INT)' ) // CREATE lists TABLE db.execute( 'CREATE TABLE IF NOT EXISTS lists (cuisines TEXT, categories TEXT, yieldUnits TEXT, units TEXT)' ) // CREATE mealPlans TABLE db.execute( 'CREATE TABLE IF NOT EXISTS mealPlans (date INT, type TEXT, title TEXT)' ) // CREATE timerPresets TABLE db.execute( 'CREATE TABLE IF NOT EXISTS timerPresets (id INT PRIMARY KEY, label TEXT, time TEXT)' ) const defaultCuisines = [ 'American', 'Brazilian', 'British', 'Chinese', 'Danish', 'Egyptian', 'Filipino', 'French', 'German', 'Greek', 'Indian', 'Irish', 'Italian', 'Jamaican', 'Japanese', 'Jewish', 'Kenyan', 'Korean', 'Mexican', 'Nigerian', 'Portuguese', 'Russian', 'Scottish', 'Spanish', 'Sri Lankan', 'Swedish', 'Thai', 'Turkish', 'Vietnamese', ] const defaultCategories = [ 'Appetizers', 'Barbecue', 'Beverages', 'Breads', 'breakfast', 'Desserts', 'dinner', 'Healthy', 'lunch', 'Main dishes', 'Meat', 'Noodles', 'Pasta', 'Poultry', 'Rice', 'Salads', 'Sauces', 'Seafood', 'Side dishes', 'snacks', 'Soups', 'Undefined', 'Vegan', 'Vegetarian', ] const defaultYieldUnits = [ 'Serving', 'Piece', 'Teaspoon', 'Tablespoon', 'Fluid Ounce', 'Ounce', 'Pound', 'Gram', 'Kilogram', 'Cup', 'Gallon', 'Millilitre', 'Litre', 'Roll', 'Patty', 'Loaf', ] const defaultUnits = [ 'unit', 'tsp', 'dsp', 'tbsp', 'fl oz', 'cup', 'pt', 'qt', 'gal', 'ml', 'l', 'oz', 'lb', 'mg', 'g', 'kg', 'cm', 'in', 'leaf', 'clove', 'piece', 'pinch', 'drop', 'dozen', 'stick', 'small', 'medium', 'large', ] const listItems = { cuisines: { sort: 1, defaultItems: defaultCuisines, }, categories: { sort: 1, defaultItems: defaultCategories, }, yieldUnits: { sort: 0, defaultItems: defaultYieldUnits, }, units: { sort: 0, defaultItems: defaultUnits, }, } export default new Vuex.Store({ state: { recipes: [], cuisines: [], categories: [], yieldUnits: [], units: [], mealPlans: [], icon: { cog: '\ue900', home: '\ue901', try: '\ue902', tried: '\ue903', fav: '\ue904', faved: '\ue905', menu: '\ue906', cuisine: '\ue907', category: '\ue908', tag: '\ue909', star: '\ue90a', starred: '\ue90b', time: '\ue90c', diff: '\ue90d', bag: '\ue90e', bagged: '\ue90f', price: '\ue910', sear: '\ue911', sort: '\ue912', filter: '\ue913', plus: '\ue914', done: '\ue915', back: '\ue916', x: '\ue917', del: '\ue918', save: '\ue919', undo: '\ue91a', edit: '\ue91b', cal: '\ue91c', tod: '\ue91d', left: '\ue91e', right: '\ue91f', img: '\ue920', uncheck: '\ue921', check: '\ue922', share: '\ue923', timer: '\ue924', start: '\ue925', pause: '\ue926', addTo: '\ue927', sound: '\ue928', vibrate: '\ue929', interface: '\ue92a', opts: '\ue92b', db: '\ue92c', reset: '\ue92d', info: '\ue92e', lang: '\ue92f', theme: '\ue930', layout: '\ue931', shuf: '\ue932', week: '\ue933', folder: '\ue934', exp: '\ue935', imp: '\ue936', gh: '\ue937', tg: '\ue938', help: '\ue939', priv: '\ue93a', don: '\ue93b', trans: '\ue93c', delay: '\ue93d', ring: '\ue93e', print: '\ue93f', }, currentComponent: 'EnRecipes', sortType: 'random', language: [ { locale: 'ar', title: 'العربية', }, { locale: 'da', title: 'Dansk', }, { locale: 'de', title: 'Deutsch', }, { locale: 'en-IN', title: 'English (IN)', }, { locale: 'en-GB', title: 'English (UK)', }, { locale: 'en-US', title: 'English (US)', }, { locale: 'es', title: 'Español', }, { locale: 'fr', title: 'Français', }, { locale: 'fr-BE', title: 'Français (BE)', }, { locale: 'fr-CA', title: 'Français (CA)', }, { locale: 'fr-CH', title: 'Français (CH)', }, { locale: 'hi', title: 'हिंदी', }, { locale: 'id', title: 'Indonesia', }, { locale: 'it', title: 'Italiano', }, { locale: 'ja', title: '日本語', }, { locale: 'ml', title: 'മലയാളം', }, { locale: 'nb-NO', title: 'Norsk bokmål', }, { locale: 'nl', title: 'Nederlands', }, { locale: 'pt', title: 'Português', }, { locale: 'pt-BR', title: 'Português (BR)', }, { locale: 'ru', title: 'Русский', }, { locale: 'ta', title: 'தமிழ்', }, { locale: 'te', title: 'తెలుగు', }, ], shakeEnabled: getNumber('shakeEnabled', 1), importSummary: { found: 0, imported: 0, updated: 0, }, layout: getString('layout', 'detailed'), selectedCuisine: null, selectedCategory: null, selectedTag: null, appTheme: 'sysDef', mondayFirst: getNumber('mondayFirst', 0), timerDelay: getString('timerDelay', '1 minute'), timerSound: {}, timerVibrate: getNumber('timerVibrate', 0), timerPresets: [], activeTimers: [], FGService: 0, RTL: 0, }, mutations: { setRTL(state) { state.RTL = utils.RTL() as any | 0 }, setFGService(state, val) { state.FGService = val }, addTimerPreset(state, timer) { let i = state.timerPresets.findIndex((e) => e.id == timer.id) if (state.timerPresets.some((e) => e.id == timer.id)) { state.timerPresets.splice(i, 1, timer) } else state.timerPresets.push(timer) db.execute( `REPLACE INTO timerPresets (id, label, time) VALUES (?, ?, ?)`, [timer.id, timer.label, timer.time] ) }, deleteTimerPreset(state, i) { let id = state.timerPresets[i] state.timerPresets.splice(i, 1) db.execute(`DELETE FROM timerPresets WHERE id = ${id}`) }, initTimerPresets(state) { if (!state.timerPresets.length) db.select(`SELECT * FROM timerPresets`).then((res) => { res.forEach((t) => { t.recipeID = 0 t.timerInt = 0 t.isPaused = 0 t.preset = 1 t.done = 0 state.timerPresets.push(t) }) }) }, importTimerPresets(state, timers) { let newPresets = timers.filter( (e) => !state.timerPresets.some((f) => f.id === e.id) ) newPresets.forEach((t) => { db.execute( `INSERT INTO timerPresets (id, label, time) VALUES (?, ?, ?)`, [t.id, t.label, t.time] ) state.timerPresets.push(t) }) }, clearTimerInterval(state) { state.activeTimers.forEach((e) => { clearInterval(e.timerInt) e.timerInt = 0 }) }, addActiveTimer(state, { timer, i }) { state.activeTimers.splice(i, 0, timer) }, sortActiveTimers(state) { let a = state.activeTimers.reduce((acc, e) => { ;(acc[e.recipeID] = acc[e.recipeID] || []).push(e) return acc }, {}) state.activeTimers = [...(Object).values(a).flat(2)] }, updateActiveTimer(state, timer) { let i = state.activeTimers.findIndex((e) => e.id == timer.id) state.activeTimers.splice(i, 1, timer) }, removeActiveTimer(state, i) { state.activeTimers.splice(i, 1) }, setTimerDelay(state, delay) { state.timerDelay = delay setString('timerDelay', delay) }, setTimerSound(state, sound) { state.timerSound = sound setString('timerSound', JSON.stringify(sound)) }, setTimerVibrate(state, n) { state.timerVibrate = n setNumber('timerVibrate', n) }, clearImportSummary(state) { for (const key in state.importSummary) state.importSummary[key] = 0 }, setFirstDay(state, n) { state.mondayFirst = n | 0 setNumber('mondayFirst', n | 0) }, setTheme(state, theme) { switch (theme) { case 'sysDef': state.appTheme = Application.systemAppearance() == 'dark' ? 'Dark' : 'Light' break case 'sysDefB': state.appTheme = Application.systemAppearance() == 'dark' ? 'Black' : 'Light' break default: state.appTheme = theme break } setString('appTheme', theme) }, clearFilter(state) { state.selectedCuisine = state.selectedCategory = state.selectedTag = null }, setLayout(state, type) { state.layout = type }, setSortType(state, sortType) { state.sortType = sortType }, initRecipes(state) { db.select('SELECT * FROM recipes').then((res) => { res.forEach((e) => { Object.keys(e).forEach( (f) => f.match(/tags|ingredients|instructions|combinations|notes/) && (e[f] = JSON.parse(e[f])) ) state.recipes.push(e) }) }) state.shakeEnabled = getNumber('shakeEnabled', 1) state.sortType = getString('sortType', 'random') }, importRecipesFromJSON(state, recipes) { let localRecipesIDs, partition let imported = 0 let updated = 0 function getUpdatedData(data) { return data.map((recipe) => { let r = Object.assign({}, recipe) if (r.timeRequired) { r.prepTime = '00:00' r.cookTime = r.timeRequired delete r.timeRequired } if (r.imageSrc) { r.image = r.imageSrc.replace('enrecipes', 'EnRecipes') delete r.imageSrc } if (!r.hasOwnProperty('cuisine')) r.cuisine = 'Undefined' if (!r.hasOwnProperty('tags')) r.tags = [] if (!r.hasOwnProperty('difficulty')) r.difficulty = 'Easy' if (!r.hasOwnProperty('rating')) r.rating = 0 if (!r.hasOwnProperty('created')) r.created = r.lastModified r.yieldQuantity = r.yield.quantity r.yieldUnit = r.yield.unit delete r.yield function getTime(d) { return new Date(d).getTime() } r.lastTried = getTime(r.lastTried) r.lastModified = getTime(r.lastModified) r.created = getTime(r.created) return r }) } function createDocuments(data) { data = getUpdatedData(data) state.recipes = [...state.recipes, ...data] data.forEach((r) => { imported++ db.execute( `INSERT INTO recipes (id, image, title, cuisine, category, tags, prepTime, cookTime, yieldQuantity, yieldUnit, difficulty, rating, ingredients, instructions, combinations, notes, favorite, tried, lastTried, lastModified, created) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [ r.id, r.image, r.title, r.cuisine, r.category, JSON.stringify(r.tags), r.prepTime, r.cookTime, r.yieldQuantity, r.yieldUnit, r.difficulty, r.rating, JSON.stringify(r.ingredients), JSON.stringify(r.instructions), JSON.stringify(r.combinations), JSON.stringify(r.notes), r.favorite ? 1 : 0, r.tried ? 1 : 0, r.lastTried, r.lastModified, r.created, ] ) }) } function updateDocuments(data) { data = getUpdatedData(data) data.forEach((r) => { let recipeIndex = state.recipes .map((e, i) => { let d1 = new Date(e.lastModified).getTime() let d2 = new Date(r.lastModified).getTime() return e.id === r.id && d1 < d2 ? i : -1 }) .filter((e) => e >= 0)[0] if (recipeIndex >= 0) { updated++ Object.assign(state.recipes[recipeIndex], r) db.execute( `REPLACE INTO recipes (id, image, title, cuisine, category, tags, prepTime, cookTime, yieldQuantity, yieldUnit, difficulty, rating, ingredients, instructions, combinations, notes, favorite, tried, lastTried, lastModified, created) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [ r.id, r.image, r.title, r.cuisine, r.category, JSON.stringify(r.tags), r.prepTime, r.cookTime, r.yieldQuantity, r.yieldUnit, r.difficulty, r.rating, JSON.stringify(r.ingredients), JSON.stringify(r.instructions), JSON.stringify(r.combinations), JSON.stringify(r.notes), r.favorite ? 1 : 0, r.tried ? 1 : 0, r.lastTried, r.lastModified, r.created, ] ) } }) } if (state.recipes.length) { localRecipesIDs = state.recipes.map((e) => e.id) partition = recipes.reduce( (result, recipe) => { localRecipesIDs.indexOf(recipe.id) < 0 ? result[0].push(recipe) // create candidates : result[1].push(recipe) // update candidates return result }, [[], []] ) if (partition[0].length) createDocuments(partition[0]) if (partition[1].length) updateDocuments(partition[1]) } else { createDocuments(recipes) } state.importSummary.found = recipes.length state.importSummary.imported = imported state.importSummary.updated = updated }, importRecipesFromDB(state, recipes) { let localRecipesIDs: string[], partition: any[] let imported = 0 let updated = 0 function createDocuments(data: any[]) { data.forEach((r) => { const cols = Object.keys(r).join(', ') const placeholder = Object.keys(r) .fill('?') .join(', ') imported++ db.execute( `REPLACE INTO recipes (${cols}) VALUES (${placeholder})`, Object.values(r) ) Object.keys(r).forEach( (f) => f.match(/tags|ingredients|instructions|combinations|notes/) && (r[f] = JSON.parse(r[f])) ) state.recipes.push(r) }) } function updateDocuments(data: any[]) { data.forEach((r) => { let recipeIndex = state.recipes .map((e, i) => { let d1 = new Date(e.lastModified).getTime() let d2 = new Date(r.lastModified).getTime() return e.id === r.id && d1 < d2 ? i : -1 }) .filter((e) => e >= 0)[0] if (recipeIndex >= 0) { updated++ const cols = Object.keys(r).join(', ') const placeholder = Object.keys(r) .fill('?') .join(', ') db.execute( `REPLACE INTO recipes (${cols}) VALUES (${placeholder})`, Object.values(r) ) Object.keys(r).forEach( (f) => f.match(/tags|ingredients|instructions|combinations|notes/) && (r[f] = JSON.parse(r[f])) ) Object.assign(state.recipes[recipeIndex], r) } }) } if (state.recipes.length) { localRecipesIDs = state.recipes.map((e) => e.id) partition = recipes.reduce( (result, recipe) => { localRecipesIDs.indexOf(recipe.id) < 0 ? result[0].push(recipe) // create candidates : result[1].push(recipe) // update candidates return result }, [[], []] ) if (partition[0].length) createDocuments(partition[0]) if (partition[1].length) updateDocuments(partition[1]) } else createDocuments(recipes) state.importSummary.found = recipes.length state.importSummary.imported = imported state.importSummary.updated = updated }, addRecipe(state, recipe) { let r = JSON.parse(JSON.stringify(recipe)) Object.keys(recipe).forEach((e) => { if (e.match(/tags|ingredients|instructions|combinations|notes/)) r[e] = JSON.stringify(r[e]) if (e.match(/favorite|tried/)) r[e] = r[e] ? 1 : 0 }) const cols = Object.keys(recipe).join(', ') const placeholder = Object.keys(recipe) .fill('?') .join(', ') db.execute( `REPLACE INTO recipes (${cols}) VALUES (${placeholder})`, Object.values(r) ) let i: number function exist({ id }, index: number) { if (id === recipe.id) { i = index return 1 } return 0 } state.recipes.some(exist) ? Object.assign(state.recipes[i], recipe) : state.recipes.push(recipe) }, deleteRecipes(state, ids) { ids.forEach((id: string) => { let i = state.recipes.findIndex((e) => e.id === id) getFileAccess().deleteFile(state.recipes[i].image) state.recipes.splice(i, 1) db.execute(`DELETE FROM recipes WHERE id = '${id}'`) state.recipes.forEach((e, i) => { if (e.combinations.includes(id)) { state.recipes[i].combinations.splice(e.combinations.indexOf(id), 1) db.execute( `UPDATE recipes SET combinations = '${JSON.stringify( state.recipes[i].combinations )}' WHERE id = '${id}'` ) } }) }) }, initListItems(state) { if (!state.cuisines.length) { db.select(`SELECT * FROM lists`).then((res) => { if (!res.length) { db.execute( `INSERT INTO lists (cuisines, categories, yieldUnits, units) VALUES (?, ?, ?, ?)`, [null, null, null, null] ) } db.select(`SELECT * FROM lists`).then((res) => { Object.keys(res[0]).forEach((list) => { let userItems: string[] let defaultItems = listItems[list].defaultItems if (res[0][list]) { userItems = JSON.parse(res[0][list]) state[list] = userItems.some((e: string) => defaultItems.includes(e) ) ? userItems : [...defaultItems, ...userItems] } else { state[list] = defaultItems listItems[list].sort && state[list].sort() } }) }) }) } }, importListItems(state, { data, listName }) { state[listName] = [...new Set([...state[listName], ...data])] if (listItems[listName].sort) state[listName].sort() db.execute( `UPDATE lists SET ${listName} = '${JSON.stringify(state[listName])}'` ) }, addListItem(state, { item, listName }) { let lowercase = state[listName].map((e: string) => e.toLowerCase()) if (lowercase.indexOf(item.toLowerCase()) == -1) { state[listName].push(item) if (listItems[listName].sort) state[listName].sort((a: string, b: string) => a.toLowerCase().localeCompare(b.toLowerCase()) ) db.execute( `UPDATE lists SET ${listName} = '${JSON.stringify(state[listName])}'` ) } }, removeListItem(state, { item, listName }) { state[listName].splice(state[listName].indexOf(item), 1) db.execute( `UPDATE lists SET ${listName} = '${JSON.stringify(state[listName])}'` ) }, resetListItems(state, listName) { let defaultItems = listItems[listName].defaultItems state[listName] = [...defaultItems] if (listItems[listName].sort) state[listName].sort((a: string, b: string) => a.toLowerCase().localeCompare(b.toLowerCase()) ) db.execute( `UPDATE lists SET ${listName} = '${JSON.stringify(state[listName])}'` ) }, initMealPlans(state) { if (!state.mealPlans.length) db.select(`SELECT * FROM mealPlans`).then((res) => res.forEach((m: {}) => state.mealPlans.push(m)) ) }, importMealPlansFromJSON(state, mealPlans) { let newMealPlans = mealPlans.filter((e) => { if (e.hasOwnProperty('eventColor')) { return !state.mealPlans.some((f) => { let d = new Date(e.startDate) let date = new Date( d.getFullYear(), d.getMonth(), d.getDate(), 0 ).getTime() let type switch (d.getHours()) { case 0: type = 'breakfast' break case 5: type = 'lunch' break case 10: type = 'dinner' break case 15: type = 'snacks' break } return f.title == e.title && f.date == date && f.type == type }) } else { return !state.mealPlans.some( (f) => f.title == e.title && f.date == e.date && f.type == e.type ) } }) let updatedMealPlans = [] if (newMealPlans[0].hasOwnProperty('eventColor')) { newMealPlans.forEach((p) => { let d = new Date(p.startDate) p.date = new Date( d.getFullYear(), d.getMonth(), d.getDate(), 0 ).getTime() switch (d.getHours()) { case 0: p.type = 'breakfast' break case 5: p.type = 'lunch' break case 10: p.type = 'dinner' break case 15: p.type = 'snacks' break } delete p.startDate delete p.endDate delete p.eventColor updatedMealPlans.push(p) }) } state.mealPlans = [...state.mealPlans, ...updatedMealPlans] updatedMealPlans.forEach((m) => { db.execute( `INSERT INTO mealPlans (date, type, title) VALUES (?, ?, ?)`, [m.date, m.type, m.title] ) }) }, importMealPlansFromDB(state, mealPlans) { let newMealPlans = mealPlans.filter( (e) => !state.mealPlans.some((f) => Object.keys(f).every((key) => f[key] == e[key]) ) ) state.mealPlans = [...state.mealPlans, ...newMealPlans] newMealPlans.forEach((m) => { db.execute( `INSERT INTO mealPlans (date, type, title) VALUES (?, ?, ?)`, [m.date, m.type, m.title] ) }) }, addMealPlan(state, { date, type, title, index, inDB }) { let mealPlan = { date, type, title, } if (inDB) { const cols = Object.keys(mealPlan).join(', ') const placeholder = Object.keys(mealPlan) .fill('?') .join(', ') db.execute( `INSERT INTO mealPlans (${cols}) VALUES (${placeholder})`, Object.values(mealPlan) ) if (index === null) state.mealPlans.push(mealPlan) } else { state.mealPlans.splice(index, 0, mealPlan) } }, deleteMealPlan(state, { date, type, title, index, inDB }) { if (inDB) { db.execute( `DELETE FROM mealPlans WHERE date = ${date} AND type = '${type}' AND title = '${title}'` ) } else { state.mealPlans.splice(index, 1) state.mealPlans = [...state.mealPlans] } }, toggleState(state, { id, key, setDate }) { let i = state.recipes.findIndex((e) => e.id == id) state.recipes[i][key] = state.recipes[i][key] ? 0 : 1 db.execute( `UPDATE recipes SET ${key} = ${state.recipes[i][key]} WHERE id = '${id}'` ) if (setDate) { state.recipes[i].lastTried = new Date().getTime() db.execute( `UPDATE recipes SET lastTried = ${state.recipes[i].lastTried} WHERE id = '${id}'` ) } }, unSyncCombinations(state, { id, combinations }) { state.recipes.forEach((e, i) => { if (combinations.includes(e.id)) { state.recipes[i].combinations.splice(e.combinations.indexOf(id), 1) db.execute( `UPDATE recipes SET combinations = '${JSON.stringify( state.recipes[i].combinations )}' WHERE id = '${id}'` ) } }) }, setShake(state, shake) { state.shakeEnabled = shake | 0 setNumber('shakeEnabled', shake | 0) }, setRating(state, { id, rating }) { let i = state.recipes.findIndex((e) => e.id == id) state.recipes[i].rating = rating db.execute(`UPDATE recipes SET rating = ${rating} WHERE id = '${id}'`) }, toggleCart(state, { id }) { let i = state.recipes.indexOf(state.recipes.filter((e) => e.id === id)[0]) state.recipes[i].inBag = !state.recipes[i].inBag }, unlinkBrokenImages(state) { state.recipes.forEach((r, i) => { if (r.image && !File.exists(r.image)) { r.image = null Object.assign(state.recipes[i], r) db.execute(`UPDATE recipes SET image = null WHERE id = '${r.id}'`) } }) }, setCuisine(state, value) { state.selectedCuisine = value }, setCategory(state, value) { state.selectedCategory = value }, setTag(state, value) { state.selectedTag = value }, }, actions: { setRTL({ commit }) { commit('setRTL') }, sortActiveTimers({ commit }) { commit('sortActiveTimers') }, setFGService({ commit }, val) { commit('setFGService', val) }, addTimerPreset({ commit }, timer) { commit('addTimerPreset', timer) }, deleteTimerPreset({ commit }, timer) { commit('deleteTimerPreset', timer) }, initTimerPresets({ commit }) { commit('initTimerPresets') }, importTimerPresets({ commit }, timers) { commit('importTimerPresets', timers) }, clearTimerInterval({ commit }) { commit('clearTimerInterval') }, addActiveTimer({ commit }, timer) { commit('addActiveTimer', timer) }, updateActiveTimer({ commit }, timer) { commit('updateActiveTimer', timer) }, removeActiveTimer({ commit }, i) { commit('removeActiveTimer', i) }, setTimerDelay({ commit }, delay) { commit('setTimerDelay', delay) }, setTimerSound({ commit }, sound) { commit('setTimerSound', sound) }, setTimerVibrate({ commit }, n) { commit('setTimerVibrate', n) }, clearImportSummary({ commit }) { commit('clearImportSummary') }, setFirstDay({ commit }, n) { commit('setFirstDay', n) }, setTheme({ commit }, theme) { commit('setTheme', theme) }, clearFilter({ commit }) { commit('clearFilter') }, setLayout({ commit }, type) { commit('setLayout', type) }, setSortType({ commit }, sortType) { commit('setSortType', sortType) }, initRecipes({ commit }) { commit('initRecipes') }, importRecipesFromJSON({ commit }, recipes) { commit('importRecipesFromJSON', recipes) }, importRecipesFromDB({ commit }, recipes) { commit('importRecipesFromDB', recipes) }, addRecipeAction({ commit }, recipe) { commit('addRecipe', recipe) }, deleteRecipes({ commit }, ids) { commit('deleteRecipes', ids) }, initListItems({ commit }) { commit('initListItems') }, importListItems({ commit }, data) { commit('importListItems', data) }, addListItemAction({ commit }, item) { commit('addListItem', item) }, removeListItemAction({ commit }, item) { commit('removeListItem', item) }, resetListItemsAction({ commit }, listName) { commit('resetListItems', listName) }, initMealPlans({ commit }) { commit('initMealPlans') }, importMealPlansFromJSON({ commit }, mealPlans) { commit('importMealPlansFromJSON', mealPlans) }, importMealPlansFromDB({ commit }, mealPlans) { commit('importMealPlansFromDB', mealPlans) }, addMealPlanAction({ commit }, mealPlan) { commit('addMealPlan', mealPlan) }, deleteMealPlanAction({ commit }, mealPlan) { commit('deleteMealPlan', mealPlan) }, toggleStateAction({ commit }, toggledRecipe) { commit('toggleState', toggledRecipe) }, unSyncCombinationsAction({ commit }, combinations) { commit('unSyncCombinations', combinations) }, setShake({ commit }, shake) { commit('setShake', shake) }, setRatingAction({ commit }, rating) { commit('setRating', rating) }, toggleCartAction({ commit }, recipe) { commit('toggleCart', recipe) }, unlinkBrokenImages({ commit }) { commit('unlinkBrokenImages') }, setCuisine({ commit }, value) { commit('setCuisine', value) }, setCategory({ commit }, value) { commit('setCategory', value) }, setTag({ commit }, value) { commit('setTag', value) }, }, })