From d2aeea319ac70c881bb7cd34626b5ef848a8cd2a Mon Sep 17 00:00:00 2001 From: Aditya Mehra Date: Thu, 9 Mar 2023 15:59:05 +1030 Subject: [PATCH] Port to Qt6 UI and move Qt5 UI to UI5 --- ui/+mediacenter/Banner.qml | 11 +- ui/+mediacenter/FoodWizardHome.qml | 22 +- ui/+mediacenter/RecipeDetail.qml | 32 +- ui/+mediacenter/SearchRecipe.qml | 18 +- ui/Banner.qml | 10 +- ui/FoodWizardHome.qml | 20 +- ui/RecipeDetail.qml | 12 +- ui/SearchRecipe.qml | 12 +- ui/translations/FoodWizardHome_de.ts | 22 + ui/translations/FoodWizardHome_es.ts | 22 + ui/translations/FoodWizardHome_fr.ts | 22 + ui/translations/FoodWizardHome_it.ts | 22 + ui/translations/FoodWizardHome_nl.ts | 22 + ui/translations/FoodWizardHome_pt.ts | 22 + ui/translations/RecipeDetail_de.ts | 57 ++ ui/translations/RecipeDetail_es.ts | 57 ++ ui/translations/RecipeDetail_fr.ts | 57 ++ ui/translations/RecipeDetail_it.ts | 57 ++ ui/translations/RecipeDetail_nl.ts | 57 ++ ui/translations/RecipeDetail_pt.ts | 57 ++ ui/translations/SearchRecipe_de.ts | 12 + ui/translations/SearchRecipe_es.ts | 12 + ui/translations/SearchRecipe_fr.ts | 12 + ui/translations/SearchRecipe_it.ts | 12 + ui/translations/SearchRecipe_nl.ts | 12 + ui/translations/SearchRecipe_pt.ts | 12 + .../skill-ovos-food-wizard.openvoiceos_de.qm | Bin 0 -> 1192 bytes .../skill-ovos-food-wizard.openvoiceos_es.qm | Bin 0 -> 1274 bytes .../skill-ovos-food-wizard.openvoiceos_fr.qm | Bin 0 -> 1284 bytes .../skill-ovos-food-wizard.openvoiceos_it.qm | Bin 0 -> 1238 bytes .../skill-ovos-food-wizard.openvoiceos_nl.qm | Bin 0 -> 1204 bytes .../skill-ovos-food-wizard.openvoiceos_pt.qm | Bin 0 -> 1262 bytes ui5/+mediacenter/Banner.qml | 74 +++ ui5/+mediacenter/FoodWizardHome.qml | 216 +++++++ ui5/+mediacenter/RecipeDetail.qml | 550 ++++++++++++++++++ ui5/+mediacenter/SearchRecipe.qml | 166 ++++++ ui5/Banner.qml | 74 +++ ui5/FoodWizardHome.qml | 216 +++++++ ui5/RecipeDetail.qml | 532 +++++++++++++++++ {ui => ui5}/RecipeDetailTopArea.qml | 0 ui5/SearchRecipe.qml | 166 ++++++ ui5/code/helper.js | 27 + ui5/images/edamam-dark-vertical.svg | 170 ++++++ ui5/images/edamam-dark.svg | 168 ++++++ ui5/images/edamam-light-vertical.svg | 170 ++++++ ui5/images/edamam-light.svg | 168 ++++++ ui5/images/foodwizz.png | Bin 0 -> 17557 bytes ui5/qmldir | 3 + ui5/sound/clicked.wav | Bin 0 -> 15240 bytes 49 files changed, 3322 insertions(+), 61 deletions(-) create mode 100644 ui/translations/FoodWizardHome_de.ts create mode 100644 ui/translations/FoodWizardHome_es.ts create mode 100644 ui/translations/FoodWizardHome_fr.ts create mode 100644 ui/translations/FoodWizardHome_it.ts create mode 100644 ui/translations/FoodWizardHome_nl.ts create mode 100644 ui/translations/FoodWizardHome_pt.ts create mode 100644 ui/translations/RecipeDetail_de.ts create mode 100644 ui/translations/RecipeDetail_es.ts create mode 100644 ui/translations/RecipeDetail_fr.ts create mode 100644 ui/translations/RecipeDetail_it.ts create mode 100644 ui/translations/RecipeDetail_nl.ts create mode 100644 ui/translations/RecipeDetail_pt.ts create mode 100644 ui/translations/SearchRecipe_de.ts create mode 100644 ui/translations/SearchRecipe_es.ts create mode 100644 ui/translations/SearchRecipe_fr.ts create mode 100644 ui/translations/SearchRecipe_it.ts create mode 100644 ui/translations/SearchRecipe_nl.ts create mode 100644 ui/translations/SearchRecipe_pt.ts create mode 100644 ui/translations/skill-ovos-food-wizard.openvoiceos_de.qm create mode 100644 ui/translations/skill-ovos-food-wizard.openvoiceos_es.qm create mode 100644 ui/translations/skill-ovos-food-wizard.openvoiceos_fr.qm create mode 100644 ui/translations/skill-ovos-food-wizard.openvoiceos_it.qm create mode 100644 ui/translations/skill-ovos-food-wizard.openvoiceos_nl.qm create mode 100644 ui/translations/skill-ovos-food-wizard.openvoiceos_pt.qm create mode 100644 ui5/+mediacenter/Banner.qml create mode 100644 ui5/+mediacenter/FoodWizardHome.qml create mode 100755 ui5/+mediacenter/RecipeDetail.qml create mode 100755 ui5/+mediacenter/SearchRecipe.qml create mode 100644 ui5/Banner.qml create mode 100644 ui5/FoodWizardHome.qml create mode 100755 ui5/RecipeDetail.qml rename {ui => ui5}/RecipeDetailTopArea.qml (100%) create mode 100755 ui5/SearchRecipe.qml create mode 100644 ui5/code/helper.js create mode 100644 ui5/images/edamam-dark-vertical.svg create mode 100644 ui5/images/edamam-dark.svg create mode 100644 ui5/images/edamam-light-vertical.svg create mode 100644 ui5/images/edamam-light.svg create mode 100644 ui5/images/foodwizz.png create mode 100644 ui5/qmldir create mode 100644 ui5/sound/clicked.wav diff --git a/ui/+mediacenter/Banner.qml b/ui/+mediacenter/Banner.qml index 09acb68..cba6632 100644 --- a/ui/+mediacenter/Banner.qml +++ b/ui/+mediacenter/Banner.qml @@ -2,13 +2,12 @@ * Copyright 2018 by Aditya Mehra */ -import QtQuick.Layouts 1.4 -import QtQuick 2.12 -import QtQuick.Controls 2.12 -import org.kde.kirigami 2.11 as Kirigami +import QtQuick.Layouts 1.15 +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import org.kde.kirigami 2.19 as Kirigami import Mycroft 1.0 as Mycroft -import QtGraphicalEffects 1.0 - +import Qt5Compat.GraphicalEffects import "code/helper.js" as HelperJS Item { diff --git a/ui/+mediacenter/FoodWizardHome.qml b/ui/+mediacenter/FoodWizardHome.qml index 2ab8822..545ea54 100644 --- a/ui/+mediacenter/FoodWizardHome.qml +++ b/ui/+mediacenter/FoodWizardHome.qml @@ -16,12 +16,12 @@ * along with this program. If not, see . */ -import QtQuick.Layouts 1.4 -import QtQuick 2.8 -import QtQuick.Controls 2.2 -import org.kde.kirigami 2.10 as Kirigami +import QtQuick.Layouts 1.15 +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import org.kde.kirigami 2.15 as Kirigami import Mycroft 1.0 as Mycroft -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import "code/helper.js" as HelperJS Mycroft.Delegate { @@ -76,7 +76,7 @@ Mycroft.Delegate { Label { horizontalAlignment: Text.AlignLeft verticalAlignment: Text.AlignVCenter - text: "Find Something To Cook With Custom Ingredients" + text: qsTr("Find Something To Cook With Custom Ingredients") anchors.left: headsImage.right anchors.top: parent.top anchors.bottom: parent.bottom @@ -122,7 +122,7 @@ Mycroft.Delegate { } } - Keys.onReturnPressed: { + Keys.onReturnPressed: (event)=> { Mycroft.SoundEffects.playClickedSound(Qt.resolvedUrl("sound/clicked.wav")) triggerGuiEvent("foodwizard.close", {}) } @@ -149,7 +149,7 @@ Mycroft.Delegate { KeyNavigation.up: closeBtn focus: true - Keys.onReturnPressed: { + Keys.onReturnPressed: (event)=> { txtFldInternal.forceActiveFocus() } @@ -159,13 +159,13 @@ Mycroft.Delegate { anchors.margins: Kirigami.Units.largeSpacing KeyNavigation.down: answerButton font.pixelSize: txtFld.height * 0.25 - placeholderText: "Add a list of ingredients e.g., orange, cheese, chicken, lime" + placeholderText: qsTr("Add a list of ingredients e.g., orange, cheese, chicken, lime") onAccepted: { Mycroft.SoundEffects.playClickedSound(Qt.resolvedUrl("sound/clicked.wav")) triggerGuiEvent("foodwizard.searchrecipe", {"query": txtFldInternal.text}) } - Keys.onReturnPressed: { + Keys.onReturnPressed: (event)=> { Mycroft.SoundEffects.playClickedSound(Qt.resolvedUrl("sound/clicked.wav")) triggerGuiEvent("foodwizard.searchrecipe", {"query": txtFldInternal.text}) } @@ -207,7 +207,7 @@ Mycroft.Delegate { answerButton.opacity = 1 } - Keys.onReturnPressed: { + Keys.onReturnPressed: (event)=> { clicked() } } diff --git a/ui/+mediacenter/RecipeDetail.qml b/ui/+mediacenter/RecipeDetail.qml index 94cdd8d..02eecc0 100755 --- a/ui/+mediacenter/RecipeDetail.qml +++ b/ui/+mediacenter/RecipeDetail.qml @@ -16,12 +16,12 @@ * along with this program. If not, see . */ -import QtQuick 2.12 -import QtQuick.Layouts 1.4 -import QtQuick.Controls 2.12 -import org.kde.kirigami 2.11 as Kirigami -import QtGraphicalEffects 1.0 +import QtQuick 2.15 +import QtQuick.Layouts 1.15 +import QtQuick.Controls 2.15 +import org.kde.kirigami 2.19 as Kirigami import Mycroft 1.0 as Mycroft +import Qt5Compat.GraphicalEffects import "code/helper.js" as HelperJS Mycroft.Delegate { @@ -30,16 +30,16 @@ Mycroft.Delegate { property bool horizontalMode: width > height ? 1 : 0 fillWidth: true - Keys.onBackPressed: { + Keys.onBackPressed: (event)=> { parent.parent.parent.currentIndex-- parent.parent.parent.currentItem.contentItem.forceActiveFocus() } - Keys.onUpPressed: { + Keys.onUpPressed: (event)=> { backButton.forceActiveFocus() } - Keys.onDownPressed: { + Keys.onDownPressed: (event)=> { readRecipeButton.forceActiveFocus() } @@ -76,6 +76,10 @@ Mycroft.Delegate { } } + Keys.onReturnPressed: (event)=> { + clicked() + } + onClicked: { root.parent.parent.parent.currentIndex-- root.parent.parent.parent.currentItem.contentItem.forceActiveFocus() @@ -409,6 +413,10 @@ Mycroft.Delegate { } } + Keys.onReturnPressed: (event)=> { + clicked() + } + onClicked: { if (ingredientsLabel.visible) { triggerGuiEvent("foodwizard.readrecipe.ingredients", {}) @@ -520,6 +528,10 @@ Mycroft.Delegate { color: Kirigami.Theme.textColor } } + + Keys.onReturnPressed: (event)=> { + clicked() + } } TabButton { @@ -544,6 +556,10 @@ Mycroft.Delegate { color: Kirigami.Theme.textColor } } + + Keys.onReturnPressed: (event)=> { + clicked() + } } } } diff --git a/ui/+mediacenter/SearchRecipe.qml b/ui/+mediacenter/SearchRecipe.qml index 2361450..46b65f1 100755 --- a/ui/+mediacenter/SearchRecipe.qml +++ b/ui/+mediacenter/SearchRecipe.qml @@ -16,12 +16,12 @@ * along with this program. If not, see . */ -import QtQuick.Layouts 1.4 -import QtQuick 2.8 -import QtQuick.Controls 2.2 -import org.kde.kirigami 2.11 as Kirigami +import QtQuick.Layouts 1.15 +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import org.kde.kirigami 2.19 as Kirigami import Mycroft 1.0 as Mycroft -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import "code/helper.js" as HelperJS @@ -50,7 +50,7 @@ Mycroft.Delegate { uiGridView.forceActiveFocus() } - Keys.onBackPressed: { + Keys.onBackPressed: (event)=> { parent.parent.parent.currentIndex-- parent.parent.parent.currentItem.contentItem.forceActiveFocus() } @@ -140,7 +140,7 @@ Mycroft.Delegate { triggerGuiEvent("foodwizard.showrecipe", {"recipe": RecipeUrl}); } - Keys.onReturnPressed: { + Keys.onReturnPressed: (event)=> { clicked() } @@ -151,14 +151,14 @@ Mycroft.Delegate { } } - Keys.onReturnPressed: { + Keys.onReturnPressed: (event)=> { card.clicked() } } } Kirigami.Heading { - text: "No recipes found" + text: qsTr("No recipes found") parent: root anchors.centerIn: parent visible: uiGridView.count == 0 diff --git a/ui/Banner.qml b/ui/Banner.qml index 09acb68..53f9bc4 100644 --- a/ui/Banner.qml +++ b/ui/Banner.qml @@ -2,12 +2,12 @@ * Copyright 2018 by Aditya Mehra */ -import QtQuick.Layouts 1.4 -import QtQuick 2.12 -import QtQuick.Controls 2.12 -import org.kde.kirigami 2.11 as Kirigami +import QtQuick.Layouts 1.15 +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import org.kde.kirigami 2.19 as Kirigami import Mycroft 1.0 as Mycroft -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import "code/helper.js" as HelperJS diff --git a/ui/FoodWizardHome.qml b/ui/FoodWizardHome.qml index 2ab8822..ca8e3c2 100644 --- a/ui/FoodWizardHome.qml +++ b/ui/FoodWizardHome.qml @@ -16,12 +16,12 @@ * along with this program. If not, see . */ -import QtQuick.Layouts 1.4 -import QtQuick 2.8 -import QtQuick.Controls 2.2 -import org.kde.kirigami 2.10 as Kirigami +import QtQuick.Layouts 1.15 +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import org.kde.kirigami 2.19 as Kirigami import Mycroft 1.0 as Mycroft -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import "code/helper.js" as HelperJS Mycroft.Delegate { @@ -76,7 +76,7 @@ Mycroft.Delegate { Label { horizontalAlignment: Text.AlignLeft verticalAlignment: Text.AlignVCenter - text: "Find Something To Cook With Custom Ingredients" + text: qsTr("Find Something To Cook With Custom Ingredients") anchors.left: headsImage.right anchors.top: parent.top anchors.bottom: parent.bottom @@ -122,7 +122,7 @@ Mycroft.Delegate { } } - Keys.onReturnPressed: { + Keys.onReturnPressed: (event)=> { Mycroft.SoundEffects.playClickedSound(Qt.resolvedUrl("sound/clicked.wav")) triggerGuiEvent("foodwizard.close", {}) } @@ -149,7 +149,7 @@ Mycroft.Delegate { KeyNavigation.up: closeBtn focus: true - Keys.onReturnPressed: { + Keys.onReturnPressed: (event)=> { txtFldInternal.forceActiveFocus() } @@ -159,13 +159,13 @@ Mycroft.Delegate { anchors.margins: Kirigami.Units.largeSpacing KeyNavigation.down: answerButton font.pixelSize: txtFld.height * 0.25 - placeholderText: "Add a list of ingredients e.g., orange, cheese, chicken, lime" + placeholderText: qsTr("Add a list of ingredients e.g., orange, cheese, chicken, lime") onAccepted: { Mycroft.SoundEffects.playClickedSound(Qt.resolvedUrl("sound/clicked.wav")) triggerGuiEvent("foodwizard.searchrecipe", {"query": txtFldInternal.text}) } - Keys.onReturnPressed: { + Keys.onReturnPressed: (event)=> { Mycroft.SoundEffects.playClickedSound(Qt.resolvedUrl("sound/clicked.wav")) triggerGuiEvent("foodwizard.searchrecipe", {"query": txtFldInternal.text}) } diff --git a/ui/RecipeDetail.qml b/ui/RecipeDetail.qml index 944b3aa..b5a19b0 100755 --- a/ui/RecipeDetail.qml +++ b/ui/RecipeDetail.qml @@ -16,12 +16,12 @@ * along with this program. If not, see . */ -import QtQuick 2.12 -import QtQuick.Layouts 1.4 -import QtQuick.Controls 2.12 -import org.kde.kirigami 2.11 as Kirigami -import QtGraphicalEffects 1.0 +import QtQuick 2.15 +import QtQuick.Layouts 1.15 +import QtQuick.Controls 2.15 +import org.kde.kirigami 2.19 as Kirigami import Mycroft 1.0 as Mycroft +import Qt5Compat.GraphicalEffects import "code/helper.js" as HelperJS Mycroft.Delegate { @@ -30,7 +30,7 @@ Mycroft.Delegate { property bool horizontalMode: width > height ? 1 : 0 fillWidth: true - Keys.onBackPressed: { + Keys.onBackPressed: (event)=> { parent.parent.parent.currentIndex-- parent.parent.parent.currentItem.contentItem.forceActiveFocus() } diff --git a/ui/SearchRecipe.qml b/ui/SearchRecipe.qml index cb23db2..b1ed24c 100755 --- a/ui/SearchRecipe.qml +++ b/ui/SearchRecipe.qml @@ -16,12 +16,12 @@ * along with this program. If not, see . */ -import QtQuick.Layouts 1.4 -import QtQuick 2.8 -import QtQuick.Controls 2.2 -import org.kde.kirigami 2.11 as Kirigami +import QtQuick.Layouts 1.15 +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import org.kde.kirigami 2.19 as Kirigami import Mycroft 1.0 as Mycroft -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import "code/helper.js" as HelperJS @@ -158,7 +158,7 @@ Mycroft.Delegate { } Kirigami.Heading { - text: "No recipes found" + text: qsTr("No recipes found") parent: root anchors.centerIn: parent visible: uiGridView.count == 0 diff --git a/ui/translations/FoodWizardHome_de.ts b/ui/translations/FoodWizardHome_de.ts new file mode 100644 index 0000000..a8340f0 --- /dev/null +++ b/ui/translations/FoodWizardHome_de.ts @@ -0,0 +1,22 @@ + + + + + FoodWizardHome + + + Find Something To Cook With Custom Ingredients + Finden Sie etwas zum Kochen mit benutzerdefinierten Zutaten + + + + Add a list of ingredients e.g., orange, cheese, chicken, lime + Fügen Sie eine Zutatenliste hinz + + + + Find Recipes + Rezepte finden + + + diff --git a/ui/translations/FoodWizardHome_es.ts b/ui/translations/FoodWizardHome_es.ts new file mode 100644 index 0000000..9569549 --- /dev/null +++ b/ui/translations/FoodWizardHome_es.ts @@ -0,0 +1,22 @@ + + + + + FoodWizardHome + + + Find Something To Cook With Custom Ingredients + Encuentra algo para cocinar con ingredientes personalizados + + + + Add a list of ingredients e.g., orange, cheese, chicken, lime + Agregue una lista de ingrediente + + + + Find Recipes + Encuentra Recetas + + + diff --git a/ui/translations/FoodWizardHome_fr.ts b/ui/translations/FoodWizardHome_fr.ts new file mode 100644 index 0000000..5e4cf4e --- /dev/null +++ b/ui/translations/FoodWizardHome_fr.ts @@ -0,0 +1,22 @@ + + + + + FoodWizardHome + + + Find Something To Cook With Custom Ingredients + Trouvez quelque chose à cuisiner avec des ingrédients personnalisés + + + + Add a list of ingredients e.g., orange, cheese, chicken, lime + Ajouter une liste d'ingrédient + + + + Find Recipes + Trouver des recettes + + + diff --git a/ui/translations/FoodWizardHome_it.ts b/ui/translations/FoodWizardHome_it.ts new file mode 100644 index 0000000..6678ae6 --- /dev/null +++ b/ui/translations/FoodWizardHome_it.ts @@ -0,0 +1,22 @@ + + + + + FoodWizardHome + + + Find Something To Cook With Custom Ingredients + Trova qualcosa da cucinare con ingredienti personalizzati + + + + Add a list of ingredients e.g., orange, cheese, chicken, lime + Aggiungi un elenco di ingredient + + + + Find Recipes + Trova ricette + + + diff --git a/ui/translations/FoodWizardHome_nl.ts b/ui/translations/FoodWizardHome_nl.ts new file mode 100644 index 0000000..aa1f2af --- /dev/null +++ b/ui/translations/FoodWizardHome_nl.ts @@ -0,0 +1,22 @@ + + + + + FoodWizardHome + + + Find Something To Cook With Custom Ingredients + Zoek iets om te koken met aangepaste ingrediënten + + + + Add a list of ingredients e.g., orange, cheese, chicken, lime + Voeg een lijst met ingrediënten to + + + + Find Recipes + Vind Recepten + + + diff --git a/ui/translations/FoodWizardHome_pt.ts b/ui/translations/FoodWizardHome_pt.ts new file mode 100644 index 0000000..17fba2e --- /dev/null +++ b/ui/translations/FoodWizardHome_pt.ts @@ -0,0 +1,22 @@ + + + + + FoodWizardHome + + + Find Something To Cook With Custom Ingredients + Encontre algo para cozinhar com ingredientes personalizados + + + + Add a list of ingredients e.g., orange, cheese, chicken, lime + Adicione uma lista de ingrediente + + + + Find Recipes + Encontrar receitas + + + diff --git a/ui/translations/RecipeDetail_de.ts b/ui/translations/RecipeDetail_de.ts new file mode 100644 index 0000000..a84d66a --- /dev/null +++ b/ui/translations/RecipeDetail_de.ts @@ -0,0 +1,57 @@ + + + + + RecipeDetail + + + Source + Quelle + + + + Calories + Kalorien + + + + Diet Type + Diät-Typ + + + + Health Tags + Gesundheits-Tags + + + + Recipe Ingredients + Rezeptzutaten + + + + Recipe Instructions + Rezeptanleitung + + + + Read Instructions + + + + + Read Ingredients + + + + + Ingredients + Zutaten + + + + Instructions + Anweisungen + + + diff --git a/ui/translations/RecipeDetail_es.ts b/ui/translations/RecipeDetail_es.ts new file mode 100644 index 0000000..d6330f9 --- /dev/null +++ b/ui/translations/RecipeDetail_es.ts @@ -0,0 +1,57 @@ + + + + + RecipeDetail + + + Source + Fuente + + + + Calories + calorías + + + + Diet Type + Tipo de dieta + + + + Health Tags + Etiquetas de salud + + + + Recipe Ingredients + Ingredientes de la receta + + + + Recipe Instructions + Instrucciones de recetas + + + + Read Instructions + + + + + Read Ingredients + + + + + Ingredients + Ingredientes + + + + Instructions + Instrucciones + + + diff --git a/ui/translations/RecipeDetail_fr.ts b/ui/translations/RecipeDetail_fr.ts new file mode 100644 index 0000000..837cc17 --- /dev/null +++ b/ui/translations/RecipeDetail_fr.ts @@ -0,0 +1,57 @@ + + + + + RecipeDetail + + + Source + Source + + + + Calories + Calories + + + + Diet Type + Type de régime + + + + Health Tags + Étiquettes de santé + + + + Recipe Ingredients + Ingrédients de la recette + + + + Recipe Instructions + Instructions de recette + + + + Read Instructions + + + + + Read Ingredients + + + + + Ingredients + Ingrédients + + + + Instructions + Instructions + + + diff --git a/ui/translations/RecipeDetail_it.ts b/ui/translations/RecipeDetail_it.ts new file mode 100644 index 0000000..d84a160 --- /dev/null +++ b/ui/translations/RecipeDetail_it.ts @@ -0,0 +1,57 @@ + + + + + RecipeDetail + + + Source + Fonte + + + + Calories + Calorie + + + + Diet Type + Tipo di dieta + + + + Health Tags + Tag di salute + + + + Recipe Ingredients + Ingredienti della ricetta + + + + Recipe Instructions + Istruzioni per la ricetta + + + + Read Instructions + + + + + Read Ingredients + + + + + Ingredients + ingredienti + + + + Instructions + Istruzioni + + + diff --git a/ui/translations/RecipeDetail_nl.ts b/ui/translations/RecipeDetail_nl.ts new file mode 100644 index 0000000..12b49ea --- /dev/null +++ b/ui/translations/RecipeDetail_nl.ts @@ -0,0 +1,57 @@ + + + + + RecipeDetail + + + Source + Bron + + + + Calories + Calorieën + + + + Diet Type + Soort dieet + + + + Health Tags + Gezondheidstags + + + + Recipe Ingredients + Recept Ingrediënten + + + + Recipe Instructions + Recept instructies + + + + Read Instructions + + + + + Read Ingredients + + + + + Ingredients + Ingrediënten + + + + Instructions + Instructies + + + diff --git a/ui/translations/RecipeDetail_pt.ts b/ui/translations/RecipeDetail_pt.ts new file mode 100644 index 0000000..e81212b --- /dev/null +++ b/ui/translations/RecipeDetail_pt.ts @@ -0,0 +1,57 @@ + + + + + RecipeDetail + + + Source + Fonte + + + + Calories + calorias + + + + Diet Type + Tipo de Dieta + + + + Health Tags + Etiquetas de Saúde + + + + Recipe Ingredients + Ingredientes da receita + + + + Recipe Instructions + Instruções da receita + + + + Read Instructions + + + + + Read Ingredients + + + + + Ingredients + Ingredientes + + + + Instructions + Instruções + + + diff --git a/ui/translations/SearchRecipe_de.ts b/ui/translations/SearchRecipe_de.ts new file mode 100644 index 0000000..d3970f2 --- /dev/null +++ b/ui/translations/SearchRecipe_de.ts @@ -0,0 +1,12 @@ + + + + + SearchRecipe + + + No recipes found + Keine Rezepte gefunden + + + diff --git a/ui/translations/SearchRecipe_es.ts b/ui/translations/SearchRecipe_es.ts new file mode 100644 index 0000000..be504fb --- /dev/null +++ b/ui/translations/SearchRecipe_es.ts @@ -0,0 +1,12 @@ + + + + + SearchRecipe + + + No recipes found + No se encontraron recetas + + + diff --git a/ui/translations/SearchRecipe_fr.ts b/ui/translations/SearchRecipe_fr.ts new file mode 100644 index 0000000..447f564 --- /dev/null +++ b/ui/translations/SearchRecipe_fr.ts @@ -0,0 +1,12 @@ + + + + + SearchRecipe + + + No recipes found + Aucune recette trouvée + + + diff --git a/ui/translations/SearchRecipe_it.ts b/ui/translations/SearchRecipe_it.ts new file mode 100644 index 0000000..c384a2f --- /dev/null +++ b/ui/translations/SearchRecipe_it.ts @@ -0,0 +1,12 @@ + + + + + SearchRecipe + + + No recipes found + Nessuna ricetta trovata + + + diff --git a/ui/translations/SearchRecipe_nl.ts b/ui/translations/SearchRecipe_nl.ts new file mode 100644 index 0000000..7417f91 --- /dev/null +++ b/ui/translations/SearchRecipe_nl.ts @@ -0,0 +1,12 @@ + + + + + SearchRecipe + + + No recipes found + Geen recepten gevonden + + + diff --git a/ui/translations/SearchRecipe_pt.ts b/ui/translations/SearchRecipe_pt.ts new file mode 100644 index 0000000..a628793 --- /dev/null +++ b/ui/translations/SearchRecipe_pt.ts @@ -0,0 +1,12 @@ + + + + + SearchRecipe + + + No recipes found + Nenhuma receita encontrada + + + diff --git a/ui/translations/skill-ovos-food-wizard.openvoiceos_de.qm b/ui/translations/skill-ovos-food-wizard.openvoiceos_de.qm new file mode 100644 index 0000000000000000000000000000000000000000..2913cd605151d0e5b60bec7a67efde67eb44f2a5 GIT binary patch literal 1192 zcmah|zl#$=82$Fn+~txr1O*W}bu8>+8o@>n?o5n#3WArwfsHrrPBwGd?8M!T$Hjj@ z5V4T!EVR+WLa?$C1rbEB(b`J8fHvA$_-6Lln1pb}Fh9Td-uJ$5F1&V+e){!z_w%X6 zx0_Gje0xqr8CTq_Ub=|YruE@&1~X-zecUCQeK7w=e#d-1d+vUn$a=M~)y6#YGxzXH z1|E};-y~q6vNp#@&EN+&mMt{j8 zK>;zUlf;T)NbL3M2K6W=j-g-pIFHPlQOmsPX8}TU7)vXz%Q*986f@OiGVns-N)f~n z6J@VlVk+c;CrZp|2@#oDI&Be@5YiFzKq%CdayMk3hwiHC2utf*q;)X&F}i!aO~dPI zJt?r8=?h; z1}TxFZ3~S+ZR3b(smQVsSx07Z3+}LnVil#@Y(vH^R_R5t>aew;YtzywLL5gW6bLo# z(1mP;`zn-)19sv@Rm5ES#>yg95%2>l&rpMQsGBNVs7evD#!lCiVKS1@We`R1M!Tn7 z(SAe*hogC-6e+(dxQ}!i+%t8U#41d2CqI_@WaJTA0sppPPqdh}O}Xv0Ad17D6H66L zAwM?KO}f}=Z>KPa663~8F{$Uo2pBitBXLIioL}1d8jENaN?~suwy_ wN>f5N41eqRU(p6N_saHvrxdR#7AC)iHB~Qgb+g%Z!9%B&sI~6lWX7`o0R_YiqW}N^ literal 0 HcmV?d00001 diff --git a/ui/translations/skill-ovos-food-wizard.openvoiceos_es.qm b/ui/translations/skill-ovos-food-wizard.openvoiceos_es.qm new file mode 100644 index 0000000000000000000000000000000000000000..0f3c345836f273a12310a619f25ee4e3334d0be7 GIT binary patch literal 1274 zcmah|F>KR76#Z^Un-` zGrS}65C^QeX+L%slnrKXg@o;dVWuq}t&G5jvm7V7wxo2jQPpIub<@fdbG zW8gML6tG?HixJm(fcItsdXO8EgzOO@(;`0BK7<-O6f$NVA(i zrfzKV*b@V5=n8efYlMRg%uK`6X2QzM$i+>;W7fGpvTd2hxB?Gjpxm`>u}#R(w563$ zkfBw!xi^5gju+alOyez63(iiB)`Y0aDNCj?RxE}YSOr$T?VRZspFnY2k&ad3$3jLq zR95q-WC8~e$WSDkz)a}5)a=vko922opKDfTqQHcL^I3`i32~{JU7GPFoo~xT`8jP} yr5!sK+Kz>}-|5Jww@x8v#(y@k>W*Y8y?LxFlPEBQ>$bV4{9el0d4xZ6j`I(07#i^a literal 0 HcmV?d00001 diff --git a/ui/translations/skill-ovos-food-wizard.openvoiceos_fr.qm b/ui/translations/skill-ovos-food-wizard.openvoiceos_fr.qm new file mode 100644 index 0000000000000000000000000000000000000000..a7c2a6313b14cda83a61bd73b3c62a3abea4b7ba GIT binary patch literal 1284 zcmah}J%|%Q6n;s}T`pOVLqV zyD#4zy(Xe;Q{Ag>-^Oe=_3>dAma?xt?Gt69#lPYQ?Bm?cr*)##;Zmmyo4K5ScBg`C zzw2F@09wFU-*8=KGfxB|lT9Z4mg279ei$%b zZk0<+D%)@I5_8&|2gVAg%l#5udVCQG%T+1e9kFLCcT4toN^`qL4aC#j9*nrTumQL! zSO+6C{DOpsRTaL=wz(tvJeUXjXaaT*aQ6{{BjMOGK(`S#z#gOT7!J<07+Qi@B->DO zaCS`T6nPBQzVQfv=i{?SvPLu}T{fia$U1C8Io6P@B4wBDh_KBngCLYWRvRliFRc}- z7iO3fl(pc;IpTJA(zg(*>H5mpU?ZeoQB zI)fQ&RfjB>oF^IZ)1=l9upq(6Sx>5hf^rn3gquozV%%mAjIu_yw}29QdwoSgX!$ P<+NkAsVCS;XHx$FyLci7 literal 0 HcmV?d00001 diff --git a/ui/translations/skill-ovos-food-wizard.openvoiceos_it.qm b/ui/translations/skill-ovos-food-wizard.openvoiceos_it.qm new file mode 100644 index 0000000000000000000000000000000000000000..6a86e9a92cc01c6bf666234c67f47da0f1252656 GIT binary patch literal 1238 zcmah|zl#$=6n=YW?sCZ*L`6gd$I2$8P`Jv2J9C7K!WCxaN^jVmBy-v9#MxQF^B)i_ zEaW;1ZL|@t6+|pV5Wz-ktE)so3+?@O7B?|_QHI&KyEF6N_v6jw7s2WG-yiLLIDhu_ z_LEnipAk_>nwxF!3f{Jzw|7g3RC@Yuk7)ko;xBoCc%!_0zeD6aU)mWU&i$x7xZ1?F zFO{$7KH>X-&=E$hCQ_tkN3wFeD`u z*~si0BS9f%L_R5E6krF#O!sK~PruVuQ$`Y6z+71i0>)V=W5ZOJ$*8AAAVp+iCK|m) zohi+uo~SdwFGOsk^amoUaawOteiS%EIZh<5R!IWHVQwR3x>QL zw2Q$3Q04#|7GMXQOdq;1PqC&_1GXhipEZ-%s3B{Q^_oSYMon8nSsljw%S|3CEi>+J zro*~0T!y)X5;(^;X66~1~4+jnC`Q& zNXIj2r>!cYOp6py=DouHS>!}sP0+=AfgvNiYJd%yy)F;X5&U1Ll3)eW@p~_zVCZ)&%W>%-~G71{o(kL zSDTMsetAkng*dvlc6k}AP3O(60wNWjyxk_6d@%h>enq@cJaeZ(|TV6v<$WIKlf>>q56q8reS5fsa4Od3;E27G5JggHruU8K`h^c(`(akb` z8)d(r|4g)W)ur5J#0PFOi#liI9$bHn{IipvHh<#(-}#s79r8m-bizv^Q=%>MNs@=9 zC?G+M2Gk>t*u_~y+U|Xuk@%xUA@-(5;7gOp0EU*aHn)7Aan_ZQW~#|#&-;;+t^tV+{IELXxx`95PWv9`bV=>FY z0|ROKMF|JDDg&SG3QzV$vT&A-9DljQX~PF~BrEM2mphf7_aq9x`){fLW$m zfLvth8cYcU4!abMNfs^1IuzY#%@%E=CW%oJxdJ~^ijyb%&4#6TNo=7BUdX@Xx6yfw-+;uVXj4^>Ndv3 zR$BEjS{-D58RP^lw=H-V;u^eVZ)Fy5ooe%jYeH0R%92@(GZw>)YzS80Xar_sQ`}k* z>2Tm_se%P0ii=2Cqs&N{*-z#!k#{P#c>2<28D5&l@EGvZ3HWjJvsATnH~A=+>uL~s z3oh{r?Ldzi?|*OpKYbu(vXgJmpBRy~9mT@ + */ + +import QtQuick.Layouts 1.4 +import QtQuick 2.12 +import QtQuick.Controls 2.12 +import org.kde.kirigami 2.11 as Kirigami +import Mycroft 1.0 as Mycroft +import QtGraphicalEffects 1.0 + +import "code/helper.js" as HelperJS + +Item { + id: bannerRoot + property alias title: bannerTitle.text + property alias source: bannerImage.source + property alias titleWrapMode: bannerTitle.wrapMode + property alias titleLevel: bannerTitle.level + property alias radius: imgRoot.radius + + Rectangle { + id: imgRoot + color: "transparent" + clip: true + anchors.fill: parent + anchors.topMargin: 1 + anchors.leftMargin: 1 + anchors.rightMargin: 1 + anchors.bottomMargin: 0 + radius: bannerRoot.radius + + layer.enabled: true + layer.effect: OpacityMask { + maskSource: Rectangle { + x: imgRoot.x; y: imgRoot.y + width: imgRoot.width + height: imgRoot.height + radius: imgRoot.radius + } + } + + Image { + id: bannerImage + width: parent.width + height: parent.height + y: -12 + opacity: 1 + fillMode: Image.PreserveAspectCrop + + Rectangle { + id: bannerOverlay + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + height: parent.height * 0.3 + color: Kirigami.Theme.backgroundColor + opacity: 0.8 + + Kirigami.Heading { + id: bannerTitle + anchors.fill: parent + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + wrapMode: Text.WordWrap + elide: Text.ElideRight + level: 2 + maximumLineCount: 2 + color: Kirigami.Theme.textColor + } + } + } + } +} \ No newline at end of file diff --git a/ui5/+mediacenter/FoodWizardHome.qml b/ui5/+mediacenter/FoodWizardHome.qml new file mode 100644 index 0000000..2ab8822 --- /dev/null +++ b/ui5/+mediacenter/FoodWizardHome.qml @@ -0,0 +1,216 @@ +/* + * Copyright 2018 by Aditya Mehra + * Copyright 2018 Marco Martin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import QtQuick.Layouts 1.4 +import QtQuick 2.8 +import QtQuick.Controls 2.2 +import org.kde.kirigami 2.10 as Kirigami +import Mycroft 1.0 as Mycroft +import QtGraphicalEffects 1.0 +import "code/helper.js" as HelperJS + +Mycroft.Delegate { + id: root + skillBackgroundSource: "https://source.unsplash.com/1920x1080/?+food" + property bool compactMode: parent.height >= 550 ? 0 : 1 + property bool horizontalMode: width > height ? 1 : 0 + fillWidth: true + + Kirigami.Icon { + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + width: 150 + height: 60 + opacity: 0.7 + source: HelperJS.isLight(Kirigami.Theme.backgroundColor) ? Qt.resolvedUrl("images/edamam-dark.svg") : Qt.resolvedUrl("images/edamam-light.svg") + } + + Component.onCompleted: { + txtFld.forceActiveFocus() + } + + Item { + anchors.fill: parent + + ColumnLayout { + width: parent.width + height: parent.height / 2 + anchors.verticalCenter: compactMode ? undefined : parent.verticalCenter + anchors.top: compactMode ? parent.top : undefined + spacing: Kirigami.Units.largeSpacing + + Rectangle { + id: heads + Layout.fillWidth: true + Layout.fillHeight: true + Layout.maximumHeight: Mycroft.Units.gridUnit * 6 + Layout.minimumHeight: Mycroft.Units.gridUnit * 4 + radius: 10 + color: Qt.rgba(Kirigami.Theme.backgroundColor.r, Kirigami.Theme.backgroundColor.g, Kirigami.Theme.backgroundColor.b, 0.9) + + Image { + id: headsImage + anchors.left: parent.left + anchors.leftMargin: Mycroft.Units.gridUnit / 2 + anchors.verticalCenter: parent.verticalCenter + width: Mycroft.Units.gridUnit * 2 + height: Mycroft.Units.gridUnit * 2 + source: Qt.resolvedUrl("images/foodwizz.png") + } + + Label { + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + text: "Find Something To Cook With Custom Ingredients" + anchors.left: headsImage.right + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: closeBtn.left + anchors.margins: Mycroft.Units.gridUnit / 2 + wrapMode: Text.WordWrap + fontSizeMode: Text.Fit + font.pixelSize: heads.height * 0.25 + minimumPixelSize: 10 + color: Kirigami.Theme.textColor + } + + Button { + id: closeBtn + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.margins: 4 + width: height + KeyNavigation.up: answerButton + KeyNavigation.down: txtFld + + background: Rectangle { + color: "transparent" + border.color: closeBtn.activeFocus ? Kirigami.Theme.linkColor : "transparent" + border.width: 2 + radius: 3 + } + + contentItem: Item { + Kirigami.Icon { + anchors.centerIn: parent + width: parent.width * 0.9 + height: parent.height * 0.9 + source: "window-close" + color: Kirigami.Theme.textColor + + ColorOverlay { + anchors.fill: parent + source: parent + color: closeBtn.activeFocus ? Kirigami.Theme.linkColor : Kirigami.Theme.textColor + } + } + } + + Keys.onReturnPressed: { + Mycroft.SoundEffects.playClickedSound(Qt.resolvedUrl("sound/clicked.wav")) + triggerGuiEvent("foodwizard.close", {}) + } + + onClicked: { + Mycroft.SoundEffects.playClickedSound(Qt.resolvedUrl("sound/clicked.wav")) + triggerGuiEvent("foodwizard.close", {}) + } + } + } + + Rectangle { + id: txtFld + anchors.top: sep.bottom + Layout.fillWidth: true + Layout.fillHeight: true + Layout.maximumHeight: Mycroft.Units.gridUnit * 8 + Layout.minimumHeight: Mycroft.Units.gridUnit * 5 + color: "transparent" + border.width: 2 + radius: Kirigami.Units.smallSpacing + border.color: txtFld.activeFocus ? Kirigami.Theme.linkColor : "transparent" + KeyNavigation.down: answerButton + KeyNavigation.up: closeBtn + focus: true + + Keys.onReturnPressed: { + txtFldInternal.forceActiveFocus() + } + + TextField { + id: txtFldInternal + anchors.fill: parent + anchors.margins: Kirigami.Units.largeSpacing + KeyNavigation.down: answerButton + font.pixelSize: txtFld.height * 0.25 + placeholderText: "Add a list of ingredients e.g., orange, cheese, chicken, lime" + + onAccepted: { + Mycroft.SoundEffects.playClickedSound(Qt.resolvedUrl("sound/clicked.wav")) + triggerGuiEvent("foodwizard.searchrecipe", {"query": txtFldInternal.text}) + } + Keys.onReturnPressed: { + Mycroft.SoundEffects.playClickedSound(Qt.resolvedUrl("sound/clicked.wav")) + triggerGuiEvent("foodwizard.searchrecipe", {"query": txtFldInternal.text}) + } + } + } + + Button { + id: answerButton + Layout.fillWidth: true + Layout.fillHeight: true + Layout.maximumHeight: Mycroft.Units.gridUnit * 6 + Layout.minimumHeight: Mycroft.Units.gridUnit * 4 + Layout.margins: Kirigami.Units.gridUnit + KeyNavigation.up: txtFld + + background: Rectangle { + color: answerButton.activeFocus ? "#4169E1" : "#4124AA" + radius: Kirigami.Units.gridUnit + } + + contentItem: Item { + Kirigami.Heading { + anchors.centerIn: parent + text: qsTr("Find Recipes") + level: compactMode ? 3 : 1 + } + } + + onClicked: { + Mycroft.SoundEffects.playClickedSound(Qt.resolvedUrl("sound/clicked.wav")) + triggerGuiEvent("foodwizard.searchrecipe", {"query": txtFldInternal.text}) + } + + onPressed: { + answerButton.opacity = 0.5 + } + + onReleased: { + answerButton.opacity = 1 + } + + Keys.onReturnPressed: { + clicked() + } + } + } + } +} diff --git a/ui5/+mediacenter/RecipeDetail.qml b/ui5/+mediacenter/RecipeDetail.qml new file mode 100755 index 0000000..94cdd8d --- /dev/null +++ b/ui5/+mediacenter/RecipeDetail.qml @@ -0,0 +1,550 @@ +/* + * Copyright 2018 by Aditya Mehra + * Copyright 2018 Marco Martin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import QtQuick 2.12 +import QtQuick.Layouts 1.4 +import QtQuick.Controls 2.12 +import org.kde.kirigami 2.11 as Kirigami +import QtGraphicalEffects 1.0 +import Mycroft 1.0 as Mycroft +import "code/helper.js" as HelperJS + +Mycroft.Delegate { + id: root + skillBackgroundSource: img.source + property bool horizontalMode: width > height ? 1 : 0 + fillWidth: true + + Keys.onBackPressed: { + parent.parent.parent.currentIndex-- + parent.parent.parent.currentItem.contentItem.forceActiveFocus() + } + + Keys.onUpPressed: { + backButton.forceActiveFocus() + } + + Keys.onDownPressed: { + readRecipeButton.forceActiveFocus() + } + + Item { + id: topAreaHeaderBackground + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + height: Mycroft.Units.gridUnit * 3 + + Button { + id: backButton + anchors.left: parent.left + anchors.leftMargin: Mycroft.Units.gridUnit + anchors.verticalCenter: parent.verticalCenter + width: Mycroft.Units.gridUnit * 3 + height: Mycroft.Units.gridUnit * 3 + + background: Rectangle { + color: Kirigami.Theme.backgroundColor + radius: 10 + } + + contentItem: Kirigami.Icon { + source: "arrow-left" + width: Mycroft.Units.gridUnit * 2 + height: Mycroft.Units.gridUnit * 2 + color: Kirigami.Theme.textColor + + ColorOverlay { + anchors.fill: parent + source: parent + color: Kirigami.Theme.textColor + } + } + + onClicked: { + root.parent.parent.parent.currentIndex-- + root.parent.parent.parent.currentItem.contentItem.forceActiveFocus() + } + + onPressed: { + backButton.opacity = 0.5 + } + + onReleased: { + backButton.opacity = 1.0 + } + } + + Rectangle { + color: Kirigami.Theme.backgroundColor + anchors.left: backButton.right + anchors.leftMargin: Mycroft.Units.gridUnit + anchors.right: parent.right + anchors.rightMargin: Mycroft.Units.gridUnit + height: parent.height + radius: 10 + + Kirigami.Heading { + id: title + anchors.top: parent.top + anchors.left: parent.left + anchors.right: poweredBy.left + anchors.bottom: parent.bottom + fontSizeMode: Text.Fit + minimumPixelSize: 16 + font.pixelSize: Mycroft.Units.gridUnit * 2 + anchors.margins: Mycroft.Units.gridUnit + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignLeft + level: 1 + wrapMode: Text.WordWrap + text: sessionData.recipeTitle + color: Kirigami.Theme.textColor + } + + Kirigami.Icon { + id: poweredBy + anchors.right: parent.right + anchors.rightMargin: Mycroft.Units.gridUnit / 2 + anchors.verticalCenter: parent.verticalCenter + width: height * 2 + height: parent.height + source: HelperJS.isLight(Kirigami.Theme.backgroundColor) ? Qt.resolvedUrl("images/edamam-dark.svg") : Qt.resolvedUrl("images/edamam-light.svg") + } + } + } + + Flickable { + id: flickContainer + anchors.top: topAreaHeaderBackground.bottom + anchors.topMargin: Mycroft.Units.gridUnit + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: bottomBarArea.top + anchors.bottomMargin: Mycroft.Units.gridUnit + 10 + contentWidth: parent.width + contentHeight: ingdLay.implicitHeight + ScrollBar.vertical: ScrollBar { + active: true + } + + clip: true + + ColumnLayout { + id: ingdLay + width: parent.width + + RowLayout { + Layout.fillWidth: true + Layout.preferredHeight: Kirigami.Units.gridUnit * 10 + + Item { + Layout.preferredWidth: root.width < 500 ? Kirigami.Units.gridUnit * 5 : Kirigami.Units.gridUnit * 10 + Layout.fillHeight: true + + Image { + id: img + fillMode: Image.PreserveAspectCrop + width: root.width < 500 ? Kirigami.Units.gridUnit * 5 : Kirigami.Units.gridUnit * 10 + height: root.width < 500 ? Kirigami.Units.gridUnit * 5 : Kirigami.Units.gridUnit * 10 + source: sessionData.recipeImage + + Rectangle { + id: formSourceRect + anchors.top: parent.top + anchors.right: parent.right + anchors.left: parent.left + anchors.margins: Mycroft.Units.gridUnit / 2 + height: formSourceRow.implicitHeight + Kirigami.Units.gridUnit + color: Qt.rgba(Kirigami.Theme.backgroundColor.r, Kirigami.Theme.backgroundColor.g, Kirigami.Theme.backgroundColor.b, 0.5) + radius: Kirigami.Units.smallSpacing + + Label { + id: formSourceRow + width: parent.width + height: parent.height + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + wrapMode: Text.WordWrap + elide: Text.ElideRight + text: qsTr("Source") + ": " + sessionData.recipeSource + color: Kirigami.Theme.textColor + } + } + } + } + + Item { + Layout.fillWidth: true + Layout.fillHeight: true + + Rectangle { + id: formCalorieRect + anchors.top: parent.top + anchors.left: parent.left + anchors.topMargin: Kirigami.Units.smallSpacing + width: formCalorieRow.implicitWidth + Kirigami.Units.gridUnit + height: formCalorieRow.implicitHeight + Kirigami.Units.gridUnit + color: Kirigami.Theme.backgroundColor + radius: Kirigami.Units.smallSpacing + + RowLayout { + id: formCalorieRow + anchors.centerIn: parent + + Label { + Layout.fillWidth: true + Layout.fillHeight: true + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + wrapMode: Text.WordWrap + elide: Text.ElideRight + text: qsTr("Calories") + ": " + color: Kirigami.Theme.textColor + } + + Label { + Layout.fillWidth: true + Layout.fillHeight: true + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + wrapMode: Text.WordWrap + elide: Text.ElideRight + text: Math.round(sessionData.recipeCalories) + color: Kirigami.Theme.textColor + } + } + } + + Rectangle { + id: formDietTypeRect + anchors.top: formCalorieRect.bottom + anchors.topMargin: Kirigami.Units.smallSpacing + width: formDietTypeTagsRow.implicitWidth + Kirigami.Units.gridUnit + height: formDietTypeTagsRow.implicitHeight + Kirigami.Units.gridUnit + color: Kirigami.Theme.backgroundColor + radius: Kirigami.Units.smallSpacing + + RowLayout { + id: formDietTypeTagsRow + anchors.centerIn: parent + + Label { + Layout.fillWidth: true + Layout.fillHeight: true + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + wrapMode: Text.WordWrap + elide: Text.ElideRight + text: qsTr("Diet Type") + ": " + color: Kirigami.Theme.textColor + } + + ColumnLayout { + id: formDietTypeCol + + Repeater { + model: sessionData.recipeDietType.dietTags + delegate: Label { + text: modelData + //Layout.fillWidth: true + wrapMode: Text.WordWrap + elide: Text.ElideRight + color: Kirigami.Theme.textColor + } + } + } + } + } + + Rectangle { + id: formHealthTypeRect + anchors.top: formDietTypeRect.bottom + anchors.topMargin: Kirigami.Units.smallSpacing + width: formHealthTagsRow.implicitWidth + Kirigami.Units.gridUnit + height: formHealthTagsRow.implicitHeight + Kirigami.Units.gridUnit + color: Kirigami.Theme.backgroundColor + radius: Kirigami.Units.smallSpacing + + RowLayout { + id: formHealthTagsRow + anchors.centerIn: parent + + Label { + Layout.fillWidth: true + Layout.fillHeight: true + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + wrapMode: Text.WordWrap + elide: Text.ElideRight + text: qsTr("Health Tags") + ": " + color: Kirigami.Theme.textColor + } + + ColumnLayout { + id: formHealthTagsCol + + Repeater { + property var limitedTags: sessionData.recipeHealthTag.slice(0, 3) + model: limitedTags + delegate: Label { + text: modelData + wrapMode: Text.WordWrap + elide: Text.ElideRight + color: Kirigami.Theme.textColor + } + } + } + } + } + } + } + + Rectangle { + Layout.fillWidth: true + Layout.preferredHeight: Mycroft.Units.gridUnit * 3 + radius: 10 + color: Kirigami.Theme.backgroundColor + + Rectangle { + anchors.left: parent.left + anchors.top: parent.top + anchors.bottom: parent.bottom + width: Mycroft.Units.gridUnit / 2 + radius: 10 + color: Kirigami.Theme.highlightColor + } + + Item { + anchors.left: parent.left + anchors.leftMargin: Mycroft.Units.gridUnit + anchors.right: readButtonItems.left + height: parent.height + + Kirigami.Heading { + id: ingredientsLabel + level: 1 + width: parent.width + height: parent.height + elide: Text.ElideRight + visible: tabbar.currentIndex == 0 + enabled: tabbar.currentIndex == 0 + wrapMode: Text.WordWrap + color: Kirigami.Theme.textColor + text: qsTr("Recipe Ingredients") + } + + Kirigami.Heading { + id: instructionsLabel + level: 1 + width: parent.width + height: parent.height + elide: Text.ElideRight + visible: tabbar.currentIndex == 1 + enabled: tabbar.currentIndex == 1 + wrapMode: Text.WordWrap + color: Kirigami.Theme.textColor + text: qsTr("Recipe Instructions") + } + } + + Item { + id: readButtonItems + anchors.right: parent.right + anchors.rightMargin: Mycroft.Units.gridUnit / 2 + width: Mycroft.Units.gridUnit * 20 + height: parent.height + + Button { + id: readRecipeButton + anchors.fill: parent + anchors.margins: Mycroft.Units.gridUnit / 2 + KeyNavigation.down: ingredientsTabButton + KeyNavigation.up: backButton + + background: Rectangle { + color: Kirigami.Theme.highlightColor + radius: 10 + } + contentItem: Item { + RowLayout { + anchors.centerIn: parent + + Kirigami.Icon { + id: readRecipeIcon + Layout.alignment: Qt.AlignLeft + Layout.fillHeight: true + Layout.preferredWidth: Mycroft.Units.gridUnit * 2 + source: "speaker" + color: Kirigami.Theme.textColor + + ColorOverlay { + anchors.fill: parent + source: parent + color: Kirigami.Theme.textColor + } + } + + Label { + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + text: instructionsLabel.visible ? qsTr("Read Instructions") : qsTr("Read Ingredients") + color: Kirigami.Theme.textColor + } + } + } + + onClicked: { + if (ingredientsLabel.visible) { + triggerGuiEvent("foodwizard.readrecipe.ingredients", {}) + } + if (instructionsLabel.visible) { + triggerGuiEvent("foodwizard.readrecipe.instructions", {}) + } + } + + onPressed: { + readRecipeButton.opacity = 0.5 + } + + onReleased: { + readRecipeButton.opacity = 1.0 + } + } + } + } + + Repeater { + id: ingredientsOrInstructionsList + model: tabbar.currentIndex == 0 ? sessionData.recipeIngredients : sessionData.recipeInstructions + + delegate: Kirigami.AbstractListItem { + Layout.fillWidth: true + Layout.preferredHeight: Kirigami.Units.gridUnit * 3 + + background: Rectangle { + color: Kirigami.Theme.backgroundColor + radius: 10 + } + + RowLayout { + id: ingdRow + anchors.left: parent.left + anchors.right: parent.right + anchors.leftMargin: Kirigami.Units.smallSpacing + anchors.rightMargin: Kirigami.Units.smallSpacing + spacing: Kirigami.Units.smallSpacing + + Image { + id: ingredientImage + Layout.preferredWidth: Kirigami.Units.gridUnit * 2 + Layout.preferredHeight: Kirigami.Units.gridUnit * 2 + Layout.topMargin: Kirigami.Units.smallSpacing + Layout.bottomMargin: Kirigami.Units.smallSpacing + fillMode: Image.PreserveAspectFit + visible: tabbar.currentIndex == 0 ? 1 : 0 + enabled: tabbar.currentIndex == 0 ? 1 : 0 + source: model.image + } + + Label { + id: ingredientName + Layout.fillWidth: true + Layout.fillHeight: true + color: Kirigami.Theme.textColor + wrapMode: Text.WordWrap + elide: Text.ElideRight + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + text: tabbar.currentIndex == 0 ? model.name : (index + 1) + ". " + model.step + } + } + } + } + } + } + + GridLayout { + id: bottomBarArea + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + height: Mycroft.Units.gridUnit * 3 + columns: root.horizontalMode ? 2 : 1 + + TabBar { + id: tabbar + Layout.fillWidth: true + Layout.preferredHeight: Kirigami.Units.gridUnit * 3 + currentIndex: 0 + spacing: Kirigami.Units.smallSpacing + + background: Rectangle { + color: "transparent" + } + + TabButton { + id: ingredientsTabButton + onClicked: tabbar.currentIndex = 0 + enabled: true + visible: true + height: Kirigami.Units.gridUnit * 1.5 + KeyNavigation.up: readRecipeButton + KeyNavigation.right: instructionsTabButton + KeyNavigation.down: backButton + + background: Rectangle { + color: ingredientsLabel.visible ? Kirigami.Theme.highlightColor : Kirigami.Theme.backgroundColor + radius: 10 + } + + contentItem: Item { + Label { + anchors.centerIn: parent + text: qsTr("Ingredients") + color: Kirigami.Theme.textColor + } + } + } + + TabButton { + id: instructionsTabButton + onClicked: tabbar.currentIndex = 1 + enabled: sessionData.hasInstructions + visible: sessionData.hasInstructions + height: Kirigami.Units.gridUnit * 1.5 + KeyNavigation.up: readRecipeButton + KeyNavigation.left: ingredientsTabButton + KeyNavigation.down: backButton + + background: Rectangle { + color: instructionsLabel.visible ? Kirigami.Theme.highlightColor : Kirigami.Theme.backgroundColor + radius: 10 + } + + contentItem: Item { + Label { + anchors.centerIn: parent + text: qsTr("Instructions") + color: Kirigami.Theme.textColor + } + } + } + } + } +} \ No newline at end of file diff --git a/ui5/+mediacenter/SearchRecipe.qml b/ui5/+mediacenter/SearchRecipe.qml new file mode 100755 index 0000000..2361450 --- /dev/null +++ b/ui5/+mediacenter/SearchRecipe.qml @@ -0,0 +1,166 @@ +/* + * Copyright 2018 by Aditya Mehra + * Copyright 2018 Marco Martin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import QtQuick.Layouts 1.4 +import QtQuick 2.8 +import QtQuick.Controls 2.2 +import org.kde.kirigami 2.11 as Kirigami +import Mycroft 1.0 as Mycroft +import QtGraphicalEffects 1.0 + +import "code/helper.js" as HelperJS + +Mycroft.Delegate { + id: root + skillBackgroundSource: "https://source.unsplash.com/1920x1080/?+food" + property bool compactMode: parent.height >= 550 ? 0 : 1 + fillWidth: true + + background: Item { + anchors.fill: parent + z: -1 + + Kirigami.Icon { + anchors.bottom: parent.bottom + anchors.bottomMargin: 16 + anchors.right: parent.right + width: 60 + height: 150 + opacity: 0.85 + source: HelperJS.isLight(Kirigami.Theme.backgroundColor) ? Qt.resolvedUrl("images/edamam-dark-vertical.svg") : Qt.resolvedUrl("images/edamam-light-vertical.svg") + } + } + + Component.onCompleted: { + uiGridView.forceActiveFocus() + } + + Keys.onBackPressed: { + parent.parent.parent.currentIndex-- + parent.parent.parent.currentItem.contentItem.forceActiveFocus() + } + + GridView { + id: uiGridView + anchors.fill: parent + cacheBuffer: width + property int columns: { + var width = parent.width + if (width >= 1920) { + return 4 + } else if (width >= 1366) { + return 3 + } else if (width >= 1024) { + return 2 + } else { + return 1 + } + } + cellWidth: parent.width / columns + cellHeight: Kirigami.Units.gridUnit * 12 + model: sessionData.recipeBlob.hits + keyNavigationEnabled: true + highlightFollowsCurrentItem: true + ScrollBar.vertical: ScrollBar {} + + delegate: Item { + id: cardRoot + width: uiGridView.cellWidth + height: uiGridView.cellHeight + + ItemDelegate { + id: card + width: uiGridView.cellHeight + Kirigami.Units.gridUnit + height: uiGridView.cellHeight - Kirigami.Units.gridUnit + anchors.centerIn: parent + + background: Rectangle { + id: cardBackground + color: Kirigami.Theme.backgroundColor + radius: Kirigami.Units.largeSpacing / 2 + border.color: Qt.rgba(Kirigami.Theme.backgroundColor.r, Kirigami.Theme.backgroundColor.g, Kirigami.Theme.backgroundColor.b, 0.5) + border.width: 1 + layer.enabled: true + layer.effect: DropShadow { + horizontalOffset: 0 + verticalOffset: 0 + radius: 10 + samples: 16 + color: Qt.rgba(0, 0, 0, 0.5) + } + } + + ColumnLayout { + anchors.fill: parent + + Banner { + id: bannerImage + title: modelData.recipe.label + source: modelData.recipe.image + titleWrapMode: Text.WordWrap + Layout.fillWidth: true + Layout.fillHeight: true + radius: cardBackground.radius + } + + Label { + wrapMode: Text.WordWrap + Layout.fillWidth: true + Layout.preferredHeight: Mycroft.Units.gridUnit * 2 + Layout.leftMargin: Mycroft.Units.gridUnit / 2 + Layout.rightMargin: Mycroft.Units.gridUnit / 2 + Layout.bottomMargin: Mycroft.Units.gridUnit / 2 + Layout.topMargin: -Mycroft.Units.gridUnit / 2 + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + text: modelData.recipe.source + font.pixelSize: parent.width * 0.07 + color: Kirigami.Theme.textColor + } + } + + onClicked: { + var RecipeUrl = modelData.recipe.url; + Mycroft.SoundEffects.playClickedSound(Qt.resolvedUrl("../sound/clicked.wav")) + triggerGuiEvent("foodwizard.showrecipe", {"recipe": RecipeUrl}); + } + + Keys.onReturnPressed: { + clicked() + } + + Rectangle { + anchors.fill: parent + visible: cardRoot.activeFocus ? 1 : 0 + color: Qt.rgba(0, 0, 3, 0.2) + } + } + + Keys.onReturnPressed: { + card.clicked() + } + } + } + + Kirigami.Heading { + text: "No recipes found" + parent: root + anchors.centerIn: parent + visible: uiGridView.count == 0 + } +} diff --git a/ui5/Banner.qml b/ui5/Banner.qml new file mode 100644 index 0000000..09acb68 --- /dev/null +++ b/ui5/Banner.qml @@ -0,0 +1,74 @@ +/* + * Copyright 2018 by Aditya Mehra + */ + +import QtQuick.Layouts 1.4 +import QtQuick 2.12 +import QtQuick.Controls 2.12 +import org.kde.kirigami 2.11 as Kirigami +import Mycroft 1.0 as Mycroft +import QtGraphicalEffects 1.0 + +import "code/helper.js" as HelperJS + +Item { + id: bannerRoot + property alias title: bannerTitle.text + property alias source: bannerImage.source + property alias titleWrapMode: bannerTitle.wrapMode + property alias titleLevel: bannerTitle.level + property alias radius: imgRoot.radius + + Rectangle { + id: imgRoot + color: "transparent" + clip: true + anchors.fill: parent + anchors.topMargin: 1 + anchors.leftMargin: 1 + anchors.rightMargin: 1 + anchors.bottomMargin: 0 + radius: bannerRoot.radius + + layer.enabled: true + layer.effect: OpacityMask { + maskSource: Rectangle { + x: imgRoot.x; y: imgRoot.y + width: imgRoot.width + height: imgRoot.height + radius: imgRoot.radius + } + } + + Image { + id: bannerImage + width: parent.width + height: parent.height + y: -12 + opacity: 1 + fillMode: Image.PreserveAspectCrop + + Rectangle { + id: bannerOverlay + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + height: parent.height * 0.3 + color: Kirigami.Theme.backgroundColor + opacity: 0.8 + + Kirigami.Heading { + id: bannerTitle + anchors.fill: parent + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + wrapMode: Text.WordWrap + elide: Text.ElideRight + level: 2 + maximumLineCount: 2 + color: Kirigami.Theme.textColor + } + } + } + } +} \ No newline at end of file diff --git a/ui5/FoodWizardHome.qml b/ui5/FoodWizardHome.qml new file mode 100644 index 0000000..2ab8822 --- /dev/null +++ b/ui5/FoodWizardHome.qml @@ -0,0 +1,216 @@ +/* + * Copyright 2018 by Aditya Mehra + * Copyright 2018 Marco Martin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import QtQuick.Layouts 1.4 +import QtQuick 2.8 +import QtQuick.Controls 2.2 +import org.kde.kirigami 2.10 as Kirigami +import Mycroft 1.0 as Mycroft +import QtGraphicalEffects 1.0 +import "code/helper.js" as HelperJS + +Mycroft.Delegate { + id: root + skillBackgroundSource: "https://source.unsplash.com/1920x1080/?+food" + property bool compactMode: parent.height >= 550 ? 0 : 1 + property bool horizontalMode: width > height ? 1 : 0 + fillWidth: true + + Kirigami.Icon { + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + width: 150 + height: 60 + opacity: 0.7 + source: HelperJS.isLight(Kirigami.Theme.backgroundColor) ? Qt.resolvedUrl("images/edamam-dark.svg") : Qt.resolvedUrl("images/edamam-light.svg") + } + + Component.onCompleted: { + txtFld.forceActiveFocus() + } + + Item { + anchors.fill: parent + + ColumnLayout { + width: parent.width + height: parent.height / 2 + anchors.verticalCenter: compactMode ? undefined : parent.verticalCenter + anchors.top: compactMode ? parent.top : undefined + spacing: Kirigami.Units.largeSpacing + + Rectangle { + id: heads + Layout.fillWidth: true + Layout.fillHeight: true + Layout.maximumHeight: Mycroft.Units.gridUnit * 6 + Layout.minimumHeight: Mycroft.Units.gridUnit * 4 + radius: 10 + color: Qt.rgba(Kirigami.Theme.backgroundColor.r, Kirigami.Theme.backgroundColor.g, Kirigami.Theme.backgroundColor.b, 0.9) + + Image { + id: headsImage + anchors.left: parent.left + anchors.leftMargin: Mycroft.Units.gridUnit / 2 + anchors.verticalCenter: parent.verticalCenter + width: Mycroft.Units.gridUnit * 2 + height: Mycroft.Units.gridUnit * 2 + source: Qt.resolvedUrl("images/foodwizz.png") + } + + Label { + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + text: "Find Something To Cook With Custom Ingredients" + anchors.left: headsImage.right + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: closeBtn.left + anchors.margins: Mycroft.Units.gridUnit / 2 + wrapMode: Text.WordWrap + fontSizeMode: Text.Fit + font.pixelSize: heads.height * 0.25 + minimumPixelSize: 10 + color: Kirigami.Theme.textColor + } + + Button { + id: closeBtn + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.margins: 4 + width: height + KeyNavigation.up: answerButton + KeyNavigation.down: txtFld + + background: Rectangle { + color: "transparent" + border.color: closeBtn.activeFocus ? Kirigami.Theme.linkColor : "transparent" + border.width: 2 + radius: 3 + } + + contentItem: Item { + Kirigami.Icon { + anchors.centerIn: parent + width: parent.width * 0.9 + height: parent.height * 0.9 + source: "window-close" + color: Kirigami.Theme.textColor + + ColorOverlay { + anchors.fill: parent + source: parent + color: closeBtn.activeFocus ? Kirigami.Theme.linkColor : Kirigami.Theme.textColor + } + } + } + + Keys.onReturnPressed: { + Mycroft.SoundEffects.playClickedSound(Qt.resolvedUrl("sound/clicked.wav")) + triggerGuiEvent("foodwizard.close", {}) + } + + onClicked: { + Mycroft.SoundEffects.playClickedSound(Qt.resolvedUrl("sound/clicked.wav")) + triggerGuiEvent("foodwizard.close", {}) + } + } + } + + Rectangle { + id: txtFld + anchors.top: sep.bottom + Layout.fillWidth: true + Layout.fillHeight: true + Layout.maximumHeight: Mycroft.Units.gridUnit * 8 + Layout.minimumHeight: Mycroft.Units.gridUnit * 5 + color: "transparent" + border.width: 2 + radius: Kirigami.Units.smallSpacing + border.color: txtFld.activeFocus ? Kirigami.Theme.linkColor : "transparent" + KeyNavigation.down: answerButton + KeyNavigation.up: closeBtn + focus: true + + Keys.onReturnPressed: { + txtFldInternal.forceActiveFocus() + } + + TextField { + id: txtFldInternal + anchors.fill: parent + anchors.margins: Kirigami.Units.largeSpacing + KeyNavigation.down: answerButton + font.pixelSize: txtFld.height * 0.25 + placeholderText: "Add a list of ingredients e.g., orange, cheese, chicken, lime" + + onAccepted: { + Mycroft.SoundEffects.playClickedSound(Qt.resolvedUrl("sound/clicked.wav")) + triggerGuiEvent("foodwizard.searchrecipe", {"query": txtFldInternal.text}) + } + Keys.onReturnPressed: { + Mycroft.SoundEffects.playClickedSound(Qt.resolvedUrl("sound/clicked.wav")) + triggerGuiEvent("foodwizard.searchrecipe", {"query": txtFldInternal.text}) + } + } + } + + Button { + id: answerButton + Layout.fillWidth: true + Layout.fillHeight: true + Layout.maximumHeight: Mycroft.Units.gridUnit * 6 + Layout.minimumHeight: Mycroft.Units.gridUnit * 4 + Layout.margins: Kirigami.Units.gridUnit + KeyNavigation.up: txtFld + + background: Rectangle { + color: answerButton.activeFocus ? "#4169E1" : "#4124AA" + radius: Kirigami.Units.gridUnit + } + + contentItem: Item { + Kirigami.Heading { + anchors.centerIn: parent + text: qsTr("Find Recipes") + level: compactMode ? 3 : 1 + } + } + + onClicked: { + Mycroft.SoundEffects.playClickedSound(Qt.resolvedUrl("sound/clicked.wav")) + triggerGuiEvent("foodwizard.searchrecipe", {"query": txtFldInternal.text}) + } + + onPressed: { + answerButton.opacity = 0.5 + } + + onReleased: { + answerButton.opacity = 1 + } + + Keys.onReturnPressed: { + clicked() + } + } + } + } +} diff --git a/ui5/RecipeDetail.qml b/ui5/RecipeDetail.qml new file mode 100755 index 0000000..944b3aa --- /dev/null +++ b/ui5/RecipeDetail.qml @@ -0,0 +1,532 @@ +/* + * Copyright 2018 by Aditya Mehra + * Copyright 2018 Marco Martin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import QtQuick 2.12 +import QtQuick.Layouts 1.4 +import QtQuick.Controls 2.12 +import org.kde.kirigami 2.11 as Kirigami +import QtGraphicalEffects 1.0 +import Mycroft 1.0 as Mycroft +import "code/helper.js" as HelperJS + +Mycroft.Delegate { + id: root + skillBackgroundSource: img.source + property bool horizontalMode: width > height ? 1 : 0 + fillWidth: true + + Keys.onBackPressed: { + parent.parent.parent.currentIndex-- + parent.parent.parent.currentItem.contentItem.forceActiveFocus() + } + + Item { + id: topAreaHeaderBackground + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + height: Mycroft.Units.gridUnit * 3 + + Button { + id: backButton + anchors.left: parent.left + anchors.leftMargin: Mycroft.Units.gridUnit + anchors.verticalCenter: parent.verticalCenter + width: Mycroft.Units.gridUnit * 3 + height: Mycroft.Units.gridUnit * 3 + + background: Rectangle { + color: Kirigami.Theme.backgroundColor + radius: 10 + } + + contentItem: Kirigami.Icon { + source: "arrow-left" + width: Mycroft.Units.gridUnit * 2 + height: Mycroft.Units.gridUnit * 2 + color: Kirigami.Theme.textColor + + ColorOverlay { + anchors.fill: parent + source: parent + color: Kirigami.Theme.textColor + } + } + + onClicked: { + root.parent.parent.parent.currentIndex-- + root.parent.parent.parent.currentItem.contentItem.forceActiveFocus() + } + + onPressed: { + backButton.opacity = 0.5 + } + + onReleased: { + backButton.opacity = 1.0 + } + } + + Rectangle { + color: Kirigami.Theme.backgroundColor + anchors.left: backButton.right + anchors.leftMargin: Mycroft.Units.gridUnit + anchors.right: parent.right + anchors.rightMargin: Mycroft.Units.gridUnit + height: parent.height + radius: 10 + + Kirigami.Heading { + id: title + anchors.top: parent.top + anchors.left: parent.left + anchors.right: poweredBy.left + anchors.bottom: parent.bottom + fontSizeMode: Text.Fit + minimumPixelSize: 16 + font.pixelSize: Mycroft.Units.gridUnit * 2 + anchors.margins: Mycroft.Units.gridUnit + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignLeft + level: 1 + wrapMode: Text.WordWrap + text: sessionData.recipeTitle + color: Kirigami.Theme.textColor + } + + Kirigami.Icon { + id: poweredBy + anchors.right: parent.right + anchors.rightMargin: Mycroft.Units.gridUnit / 2 + anchors.verticalCenter: parent.verticalCenter + width: height * 2 + height: parent.height + source: HelperJS.isLight(Kirigami.Theme.backgroundColor) ? Qt.resolvedUrl("images/edamam-dark.svg") : Qt.resolvedUrl("images/edamam-light.svg") + } + } + } + + Flickable { + id: flickContainer + anchors.top: topAreaHeaderBackground.bottom + anchors.topMargin: Mycroft.Units.gridUnit + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: bottomBarArea.top + anchors.bottomMargin: Mycroft.Units.gridUnit + 10 + contentWidth: parent.width + contentHeight: ingdLay.implicitHeight + ScrollBar.vertical: ScrollBar { + active: true + } + + clip: true + + ColumnLayout { + id: ingdLay + width: parent.width + + RowLayout { + Layout.fillWidth: true + Layout.preferredHeight: Kirigami.Units.gridUnit * 10 + + Item { + Layout.preferredWidth: root.width < 500 ? Kirigami.Units.gridUnit * 5 : Kirigami.Units.gridUnit * 10 + Layout.fillHeight: true + + Image { + id: img + fillMode: Image.PreserveAspectCrop + width: root.width < 500 ? Kirigami.Units.gridUnit * 5 : Kirigami.Units.gridUnit * 10 + height: root.width < 500 ? Kirigami.Units.gridUnit * 5 : Kirigami.Units.gridUnit * 10 + source: sessionData.recipeImage + + Rectangle { + id: formSourceRect + anchors.top: parent.top + anchors.right: parent.right + anchors.left: parent.left + anchors.margins: Mycroft.Units.gridUnit / 2 + height: formSourceRow.implicitHeight + Kirigami.Units.gridUnit + color: Qt.rgba(Kirigami.Theme.backgroundColor.r, Kirigami.Theme.backgroundColor.g, Kirigami.Theme.backgroundColor.b, 0.5) + radius: Kirigami.Units.smallSpacing + + Label { + id: formSourceRow + width: parent.width + height: parent.height + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + wrapMode: Text.WordWrap + elide: Text.ElideRight + text: qsTr("Source") + ": " + sessionData.recipeSource + color: Kirigami.Theme.textColor + } + } + } + } + + Item { + Layout.fillWidth: true + Layout.fillHeight: true + + Rectangle { + id: formCalorieRect + anchors.top: parent.top + anchors.left: parent.left + anchors.topMargin: Kirigami.Units.smallSpacing + width: formCalorieRow.implicitWidth + Kirigami.Units.gridUnit + height: formCalorieRow.implicitHeight + Kirigami.Units.gridUnit + color: Kirigami.Theme.backgroundColor + radius: Kirigami.Units.smallSpacing + + RowLayout { + id: formCalorieRow + anchors.centerIn: parent + + Label { + Layout.fillWidth: true + Layout.fillHeight: true + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + wrapMode: Text.WordWrap + elide: Text.ElideRight + text: qsTr("Calories") + ": " + color: Kirigami.Theme.textColor + } + + Label { + Layout.fillWidth: true + Layout.fillHeight: true + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + wrapMode: Text.WordWrap + elide: Text.ElideRight + text: Math.round(sessionData.recipeCalories) + color: Kirigami.Theme.textColor + } + } + } + + Rectangle { + id: formDietTypeRect + anchors.top: formCalorieRect.bottom + anchors.topMargin: Kirigami.Units.smallSpacing + width: formDietTypeTagsRow.implicitWidth + Kirigami.Units.gridUnit + height: formDietTypeTagsRow.implicitHeight + Kirigami.Units.gridUnit + color: Kirigami.Theme.backgroundColor + radius: Kirigami.Units.smallSpacing + + RowLayout { + id: formDietTypeTagsRow + anchors.centerIn: parent + + Label { + Layout.fillWidth: true + Layout.fillHeight: true + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + wrapMode: Text.WordWrap + elide: Text.ElideRight + text: qsTr("Diet Type") + ": " + color: Kirigami.Theme.textColor + } + + ColumnLayout { + id: formDietTypeCol + + Repeater { + model: sessionData.recipeDietType.dietTags + delegate: Label { + text: modelData + //Layout.fillWidth: true + wrapMode: Text.WordWrap + elide: Text.ElideRight + color: Kirigami.Theme.textColor + } + } + } + } + } + + Rectangle { + id: formHealthTypeRect + anchors.top: formDietTypeRect.bottom + anchors.topMargin: Kirigami.Units.smallSpacing + width: formHealthTagsRow.implicitWidth + Kirigami.Units.gridUnit + height: formHealthTagsRow.implicitHeight + Kirigami.Units.gridUnit + color: Kirigami.Theme.backgroundColor + radius: Kirigami.Units.smallSpacing + + RowLayout { + id: formHealthTagsRow + anchors.centerIn: parent + + Label { + Layout.fillWidth: true + Layout.fillHeight: true + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + wrapMode: Text.WordWrap + elide: Text.ElideRight + text: qsTr("Health Tags") + ": " + color: Kirigami.Theme.textColor + } + + ColumnLayout { + id: formHealthTagsCol + + Repeater { + property var limitedTags: sessionData.recipeHealthTag.slice(0, 3) + model: limitedTags + delegate: Label { + text: modelData + wrapMode: Text.WordWrap + elide: Text.ElideRight + color: Kirigami.Theme.textColor + } + } + } + } + } + } + } + + Rectangle { + Layout.fillWidth: true + Layout.preferredHeight: Mycroft.Units.gridUnit * 3 + radius: 10 + color: Kirigami.Theme.backgroundColor + + Rectangle { + anchors.left: parent.left + anchors.top: parent.top + anchors.bottom: parent.bottom + width: Mycroft.Units.gridUnit / 2 + radius: 10 + color: Kirigami.Theme.highlightColor + } + + Item { + anchors.left: parent.left + anchors.leftMargin: Mycroft.Units.gridUnit + anchors.right: readButtonItems.left + height: parent.height + + Kirigami.Heading { + id: ingredientsLabel + level: 1 + width: parent.width + height: parent.height + elide: Text.ElideRight + visible: tabbar.currentIndex == 0 + enabled: tabbar.currentIndex == 0 + wrapMode: Text.WordWrap + color: Kirigami.Theme.textColor + text: qsTr("Recipe Ingredients") + } + + Kirigami.Heading { + id: instructionsLabel + level: 1 + width: parent.width + height: parent.height + elide: Text.ElideRight + visible: tabbar.currentIndex == 1 + enabled: tabbar.currentIndex == 1 + wrapMode: Text.WordWrap + color: Kirigami.Theme.textColor + text: qsTr("Recipe Instructions") + } + } + + Item { + id: readButtonItems + anchors.right: parent.right + anchors.rightMargin: Mycroft.Units.gridUnit / 2 + width: Mycroft.Units.gridUnit * 20 + height: parent.height + + Button { + id: readRecipeButton + anchors.fill: parent + anchors.margins: Mycroft.Units.gridUnit / 2 + + background: Rectangle { + color: Kirigami.Theme.highlightColor + radius: 10 + } + contentItem: Item { + RowLayout { + anchors.centerIn: parent + + Kirigami.Icon { + id: readRecipeIcon + Layout.alignment: Qt.AlignLeft + Layout.fillHeight: true + Layout.preferredWidth: Mycroft.Units.gridUnit * 2 + source: "speaker" + color: Kirigami.Theme.textColor + + ColorOverlay { + anchors.fill: parent + source: parent + color: Kirigami.Theme.textColor + } + } + + Label { + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + text: instructionsLabel.visible ? qsTr("Read Instructions") : qsTr("Read Ingredients") + color: Kirigami.Theme.textColor + } + } + } + + onClicked: { + if (ingredientsLabel.visible) { + triggerGuiEvent("foodwizard.readrecipe.ingredients", {}) + } + if (instructionsLabel.visible) { + triggerGuiEvent("foodwizard.readrecipe.instructions", {}) + } + } + + onPressed: { + readRecipeButton.opacity = 0.5 + } + + onReleased: { + readRecipeButton.opacity = 1.0 + } + } + } + } + + Repeater { + id: ingredientsOrInstructionsList + model: tabbar.currentIndex == 0 ? sessionData.recipeIngredients : sessionData.recipeInstructions + + delegate: Kirigami.AbstractListItem { + Layout.fillWidth: true + Layout.preferredHeight: Kirigami.Units.gridUnit * 3 + + background: Rectangle { + color: Kirigami.Theme.backgroundColor + radius: 10 + } + + RowLayout { + id: ingdRow + anchors.left: parent.left + anchors.right: parent.right + anchors.leftMargin: Kirigami.Units.smallSpacing + anchors.rightMargin: Kirigami.Units.smallSpacing + spacing: Kirigami.Units.smallSpacing + + Image { + id: ingredientImage + Layout.preferredWidth: Kirigami.Units.gridUnit * 2 + Layout.preferredHeight: Kirigami.Units.gridUnit * 2 + Layout.topMargin: Kirigami.Units.smallSpacing + Layout.bottomMargin: Kirigami.Units.smallSpacing + fillMode: Image.PreserveAspectFit + visible: tabbar.currentIndex == 0 ? 1 : 0 + enabled: tabbar.currentIndex == 0 ? 1 : 0 + source: model.image + } + + Label { + id: ingredientName + Layout.fillWidth: true + Layout.fillHeight: true + color: Kirigami.Theme.textColor + wrapMode: Text.WordWrap + elide: Text.ElideRight + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + text: tabbar.currentIndex == 0 ? model.name : (index + 1) + ". " + model.step + } + } + } + } + } + } + + GridLayout { + id: bottomBarArea + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + height: Mycroft.Units.gridUnit * 3 + columns: root.horizontalMode ? 2 : 1 + + TabBar { + id: tabbar + Layout.fillWidth: true + Layout.preferredHeight: Kirigami.Units.gridUnit * 3 + currentIndex: 0 + spacing: Kirigami.Units.smallSpacing + + background: Rectangle { + color: "transparent" + } + + TabButton { + onClicked: tabbar.currentIndex = 0 + enabled: true + visible: true + height: Kirigami.Units.gridUnit * 1.5 + + background: Rectangle { + color: ingredientsLabel.visible ? Kirigami.Theme.highlightColor : Kirigami.Theme.backgroundColor + radius: 10 + } + + contentItem: Item { + Label { + anchors.centerIn: parent + text: qsTr("Ingredients") + color: Kirigami.Theme.textColor + } + } + } + + TabButton { + onClicked: tabbar.currentIndex = 1 + enabled: sessionData.hasInstructions + visible: sessionData.hasInstructions + height: Kirigami.Units.gridUnit * 1.5 + + background: Rectangle { + color: instructionsLabel.visible ? Kirigami.Theme.highlightColor : Kirigami.Theme.backgroundColor + radius: 10 + } + + contentItem: Item { + Label { + anchors.centerIn: parent + text: qsTr("Instructions") + color: Kirigami.Theme.textColor + } + } + } + } + } +} diff --git a/ui/RecipeDetailTopArea.qml b/ui5/RecipeDetailTopArea.qml similarity index 100% rename from ui/RecipeDetailTopArea.qml rename to ui5/RecipeDetailTopArea.qml diff --git a/ui5/SearchRecipe.qml b/ui5/SearchRecipe.qml new file mode 100755 index 0000000..cb23db2 --- /dev/null +++ b/ui5/SearchRecipe.qml @@ -0,0 +1,166 @@ +/* + * Copyright 2018 by Aditya Mehra + * Copyright 2018 Marco Martin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import QtQuick.Layouts 1.4 +import QtQuick 2.8 +import QtQuick.Controls 2.2 +import org.kde.kirigami 2.11 as Kirigami +import Mycroft 1.0 as Mycroft +import QtGraphicalEffects 1.0 + +import "code/helper.js" as HelperJS + +Mycroft.Delegate { + id: root + skillBackgroundSource: "https://source.unsplash.com/1920x1080/?+food" + property bool compactMode: parent.height >= 550 ? 0 : 1 + fillWidth: true + + background: Item { + anchors.fill: parent + z: -1 + + Kirigami.Icon { + anchors.bottom: parent.bottom + anchors.bottomMargin: 16 + anchors.right: parent.right + width: 60 + height: 150 + opacity: 0.85 + source: HelperJS.isLight(Kirigami.Theme.backgroundColor) ? Qt.resolvedUrl("images/edamam-dark-vertical.svg") : Qt.resolvedUrl("images/edamam-light-vertical.svg") + } + } + + Component.onCompleted: { + uiGridView.forceActiveFocus() + } + + Keys.onBackPressed: { + parent.parent.parent.currentIndex-- + parent.parent.parent.currentItem.contentItem.forceActiveFocus() + } + + GridView { + id: uiGridView + anchors.fill: parent + cacheBuffer: width + property int columns: { + var width = parent.width + if (width >= 1920) { + return 4 + } else if (width >= 1366) { + return 3 + } else if (width >= 1024) { + return 2 + } else { + return 1 + } + } + cellWidth: parent.width / columns + cellHeight: Kirigami.Units.gridUnit * 12 + model: sessionData.recipeBlob.hits + keyNavigationEnabled: true + highlightFollowsCurrentItem: true + ScrollBar.vertical: ScrollBar {} + + delegate: Item { + id: cardRoot + width: uiGridView.cellWidth + height: uiGridView.cellHeight + + ItemDelegate { + id: card + width: uiGridView.cellHeight + Kirigami.Units.gridUnit + height: uiGridView.cellHeight - Kirigami.Units.gridUnit + anchors.centerIn: parent + + background: Rectangle { + id: cardBackground + color: Kirigami.Theme.backgroundColor + radius: Kirigami.Units.largeSpacing / 2 + border.color: Qt.rgba(Kirigami.Theme.backgroundColor.r, Kirigami.Theme.backgroundColor.g, Kirigami.Theme.backgroundColor.b, 0.5) + border.width: 1 + layer.enabled: true + layer.effect: DropShadow { + horizontalOffset: 0 + verticalOffset: 0 + radius: 10 + samples: 16 + color: Qt.rgba(0, 0, 0, 0.5) + } + } + + ColumnLayout { + anchors.fill: parent + + Banner { + id: bannerImage + title: modelData.recipe.label + source: modelData.recipe.image + titleWrapMode: Text.WordWrap + Layout.fillWidth: true + Layout.fillHeight: true + radius: cardBackground.radius + } + + Label { + wrapMode: Text.WordWrap + Layout.fillWidth: true + Layout.preferredHeight: Mycroft.Units.gridUnit * 2 + Layout.leftMargin: Mycroft.Units.gridUnit / 2 + Layout.rightMargin: Mycroft.Units.gridUnit / 2 + Layout.bottomMargin: Mycroft.Units.gridUnit / 2 + Layout.topMargin: -Mycroft.Units.gridUnit / 2 + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + text: modelData.recipe.source + font.pixelSize: parent.width * 0.07 + color: Kirigami.Theme.textColor + } + } + + onClicked: { + var RecipeUrl = modelData.recipe.url; + Mycroft.SoundEffects.playClickedSound(Qt.resolvedUrl("sound/clicked.wav")) + triggerGuiEvent("foodwizard.showrecipe", {"recipe": RecipeUrl}); + } + + Keys.onReturnPressed: { + clicked() + } + + Rectangle { + anchors.fill: parent + visible: cardRoot.activeFocus ? 1 : 0 + color: Qt.rgba(0, 0, 3, 0.2) + } + } + + Keys.onReturnPressed: { + card.clicked() + } + } + } + + Kirigami.Heading { + text: "No recipes found" + parent: root + anchors.centerIn: parent + visible: uiGridView.count == 0 + } +} diff --git a/ui5/code/helper.js b/ui5/code/helper.js new file mode 100644 index 0000000..45b7ed3 --- /dev/null +++ b/ui5/code/helper.js @@ -0,0 +1,27 @@ +function isLight(color) { + // Convert color to string + color = color.toString(); + + var color_r = color.slice(1,3); + var color_g = color.slice(3,5); + var color_b = color.slice(5,7); + + var r = parseInt(color_r, 16); + var g = parseInt(color_g, 16); + var b = parseInt(color_b, 16); + + var hsp = Math.sqrt( + 0.299 * (r * r) + + 0.587 * (g * g) + + 0.114 * (b * b) + ); + + if (hsp>127.5) { + + return true; + } + else { + + return false; + } +} \ No newline at end of file diff --git a/ui5/images/edamam-dark-vertical.svg b/ui5/images/edamam-dark-vertical.svg new file mode 100644 index 0000000..31a4ccc --- /dev/null +++ b/ui5/images/edamam-dark-vertical.svg @@ -0,0 +1,170 @@ + + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ui5/images/edamam-dark.svg b/ui5/images/edamam-dark.svg new file mode 100644 index 0000000..b15ec27 --- /dev/null +++ b/ui5/images/edamam-dark.svg @@ -0,0 +1,168 @@ + + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ui5/images/edamam-light-vertical.svg b/ui5/images/edamam-light-vertical.svg new file mode 100644 index 0000000..f5a68ba --- /dev/null +++ b/ui5/images/edamam-light-vertical.svg @@ -0,0 +1,170 @@ + + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ui5/images/edamam-light.svg b/ui5/images/edamam-light.svg new file mode 100644 index 0000000..449d438 --- /dev/null +++ b/ui5/images/edamam-light.svg @@ -0,0 +1,168 @@ + + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ui5/images/foodwizz.png b/ui5/images/foodwizz.png new file mode 100644 index 0000000000000000000000000000000000000000..1d02661d286df4a6f035b6a43400c95bd185863a GIT binary patch literal 17557 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 S-hAM3BMhFdelF{r5}E*^o<>Xn literal 0 HcmV?d00001 diff --git a/ui5/qmldir b/ui5/qmldir new file mode 100644 index 0000000..ddfd4fb --- /dev/null +++ b/ui5/qmldir @@ -0,0 +1,3 @@ +FoodWizardHome 1.0 FoodWizardHome.qml +RecipeDetail 1.0 RecipeDetail.qml +SearchRecipe 1.0 SearchRecipe.qml \ No newline at end of file diff --git a/ui5/sound/clicked.wav b/ui5/sound/clicked.wav new file mode 100644 index 0000000000000000000000000000000000000000..91b55f6214c575c9796a890d10fa7a96586c5723 GIT binary patch literal 15240 zcmXY&2Y6J)7RP7qZW2f#3894Es~}AQL8Xdh=TMc zNRD;zWn{iE*>fWN;O9O_CEFY(o z(#lb-S1T2_!BJinr~367+2?KMh;&uC(oH4HtLnCNQTOC6l_H(hLut$RhU%J>QU6F) zb(HV-qj2m^+9y{Ztx!Go_F6a4$*?N5&Dz{4sL|BjYEkp!!NBs?Sx7>d*R) zDggh0d<4(o&>XGun3E#|kh!b639sAekS4v*BM+9=JZ#0ko7wEZ*twnws(=u+F4_h zpo~M;8OSghokoP_r9eLeKKAz$nT{NbvDF-GHlAygid5sU+c&BZm!rmW?=uyyhA}=8 z`wqbeL;3xcDypV1ZxVL>kahjx^9izl9P*JtXCHRTvD9p?5?5$Xe# z0KF(R2z@$Yo9_6%FW-kS|0C}ALg!bo<;&^pT+OH(f}L2giT(-p7p_7 zO?6o+gSVQDcLAxRka0LVzOF7xEAGDv?e5rQ0D28Vwl>i0sEVO$Gc`vwP@f^oi;Oo? zMN~UgNA*!<)vL^J3_Yc0$O@S*+vKwNWVbw##d1>C$#t0|SL9ncBgYs&DiLa?+>n`! zEfcRgB~K$$1MuGvzjadi_%93p`S5E7I$V_6>bN`wR+=KqAbd0q|MXW!u+I(R$Pd0s zB43PpTOF1fYPVEk-iz3;3+ta@ZWVP2`ZtjI3i@5b_h-=YFg81e-pTSIxEh4+?bJc| zESJ)1sZ>+vnDZDcUWQK!YXltF_HB(hp8&nImLse6A;r~83Xbaw2fww03 zsunhX78=dq@jTaS$l6DhBF;*yG5BaCG`=Q2K7&Uuc)Wz}9iTIiShR866JLM8@6WLF zP*n?`#Hw!m?g>uD^Lv(xCx&y7rvSW*Kr>2B$4C3r>*|auujV7?N8B6EnhD&Wsmd@` zM$HRhwg}%VtEC|sE)x?skReCDLcX=Ci8`R_qE|rXp~F~gK8Ly6!NG6pybM%ZvHLY_ zR!l7h7kkw+YBMs=N7u3VYYuwsLH;$^aD+My-F*2Dx*Hh#89o04{wJdMkJ#i#wGUga z2me=yeOLZq&Svf}gVq9aV}E!x0^41%*F@x-r2fWdKS*QsCz$>hzwBV`4RVx`-|%Z+ zwG$kr5Ci4aGH|h!@wxb7D%cv0{k~yrt}3BcsdC6&NnON;kBEV5#NB1S?_u2v?6raK zM?m^b^}IU4ynnIBRrQoQPRuM(g`wM6?ZPkH_`V6co1wc?6<2>_yYuP|*40;ARG6B9 z?mvL%)!1?;HabeY9ERU~urLk(e#f;K-8W;a6=3yee6|RDtW%9xUmZV`SEpHb3_d6D z_d$I3H!=Pfbhn|?4&r7NG&T~0yZPLtuFCKDW(hvq3;%=o_b+U)iF>=qfjfzfovhh` zt@q)R3+Q$W`bqGK(WO+Zj#78Yk6W;A$AJFxEoL=Y ze!Rw<16+TT%Z`&zPNL5i;^}vFQnn(`QEYISc?Y0z3|W%NlV!D$M*6lC)BEMV+Qiy_ zu)zc5PLhMrxB<3a*FUIlb#qlhZ^mBJ$-Aqt*A`h$KG@B?GhkyIe9s|EqE1u^I+u0V zMPB_xoUSv&_au^Vv_n!rd5a11|f zMb_iYJI3!t>JTxo2VVcM_89W)B~Dk6TlRqOo7npv`XwV{3cgLi|K(LO;~T*GT>P<= z{beJ$==)Gy7FLJ&y$4LJK*r6CZ2%iT!TVQo)=GT81>Bre_0)CndJb9#vDI#_3*-dr z|1;!-)8vl*VCy7vui@kE$gmOqC)i{D0b85!^ETvPhg>VTERObse2^kX7(Wgk_P}=| zak`p#*nxj9;OEQmze{XAgvL!``UL9^K=&{>IfT4BiS-?PT8tjTcK6WZ3G^Nz!!@wH z9$)?podw`$F_>7u+C|XWfNneCbpXGvzz=iq)vwT51HCoSSkL^WjD3S#OPIGEEN>wf zZ6wC5FScX9?a̮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 literal 0 HcmV?d00001