Commit cc082651 authored by Johannes Schwab's avatar Johannes Schwab

client: quick filter for recipes

parent 5aa55027
This diff is collapsed.
......@@ -205,90 +205,127 @@ Page {
MediumLabel {
anchors.centerIn: parent
text: qsTr("Create your first recipe.")
visible: backend.recipesList.length == 0
wrapMode: Text.Wrap
visible: backend.recipesList.length == 0 && filter.text.length == 0
}
ListView {
id: recipesList
MediumLabel {
anchors.centerIn: parent
text: qsTr("No recipe found.")
wrapMode: Text.Wrap
visible: backend.recipesList.length == 0 && filter.text.length != 0
}
ColumnLayout {
anchors.fill: parent
orientation: ListView.Vertical
model: backend.recipesList
ScrollBar.vertical: ScrollBar {}
boundsBehavior: Flickable.StopAtBounds
delegate: Item {
width: parent.width
height: Math.max(name.height, image.height) + 10
RoundedImage {
id: image
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 5
height: Globals.recipesListImageHeight
width: height
fillMode: Image.PreserveAspectCrop
source: modelData.smallImage
RowLayout {
spacing: 0
TextField {
id: filter
Layout.fillWidth: true
Layout.rightMargin: Globals.mobile ? 5 : 0
placeholderText: qsTr("Search recipe…")
text: backend.filter
onTextChanged: backend.filter = text
}
Label {
id: name
anchors.leftMargin: 5
anchors.rightMargin: 5
anchors.left: image.right
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
text: modelData.name
wrapMode: Text.Wrap
Component.onCompleted: {
font.pixelSize = font.pixelSize * 1.2;
}
ToolButton {
icon.name: "edit-clear"
icon.source: "qrc:/img/fallback-icons/edit-clear.svg"
onClicked: filter.text = ""
ToolTip.text: qsTr("Clear filter")
ToolTip.delay: 500
ToolTip.visible: hovered
}
Rectangle {
height: parent.width
width: 1
rotation: 90
anchors.verticalCenter: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
gradient: Gradient {
GradientStop{
position: 0.0
color: "transparent"
}
ListView {
id: recipesList
Layout.fillWidth: true
Layout.fillHeight: true
orientation: ListView.Vertical
model: backend.recipesList
ScrollBar.vertical: ScrollBar {}
boundsBehavior: Flickable.StopAtBounds
clip: true
delegate: Item {
width: parent.width
height: Math.max(name.height, image.height) + 10
RoundedImage {
id: image
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 5
height: Globals.recipesListImageHeight
width: height
fillMode: Image.PreserveAspectCrop
source: modelData.smallImage
}
Label {
id: name
anchors.leftMargin: 5
anchors.rightMargin: 5
anchors.left: image.right
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
text: modelData.name
wrapMode: Text.Wrap
Component.onCompleted: {
font.pixelSize = font.pixelSize * 1.2;
}
GradientStop{
position: 0.5
color: (index == recipesList.count - 1) ? "transparent" : Globals.accentColor
}
Rectangle {
height: parent.width
width: 1
rotation: 90
anchors.verticalCenter: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
gradient: Gradient {
GradientStop{
position: 0.0
color: "transparent"
}
GradientStop{
position: 0.5
color: (index == recipesList.count - 1) ? "transparent" : Globals.accentColor
}
GradientStop{
position: 1.0
color: "transparent"
}
}
GradientStop{
position: 1.0
color: "transparent"
}
MouseArea {
anchors.fill: parent
onClicked: function() {
recipesList.currentIndex = index;
recipesList.select(modelData);
}
}
}
MouseArea {
anchors.fill: parent
onClicked: function() {
recipesList.currentIndex = index;
recipesList.select(modelData);
highlight: Rectangle {
color: Globals.mobile ? "transparent" : Globals.accentColor
}
highlightMoveDuration: 0
highlightResizeDuration: 0
Component.onCompleted: function() {
if (!Globals.mobile && count != 0) mainRowLayout.selectRecipe(model[currentIndex]);
}
function select(recipe) {
if (Globals.mobile) {
stackView.selectRecipe(recipe);
} else {
mainRowLayout.selectRecipe(recipe);
}
}
}
highlight: Rectangle {
color: Globals.mobile ? "transparent" : Globals.accentColor
}
highlightMoveDuration: 0
highlightResizeDuration: 0
Component.onCompleted: function() {
if (!Globals.mobile && count != 0) mainRowLayout.selectRecipe(model[currentIndex]);
}
function select(recipe) {
if (Globals.mobile) {
stackView.selectRecipe(recipe);
} else {
mainRowLayout.selectRecipe(recipe);
onModelChanged: function() {
if(!Globals.mobile && count != 0) mainRowLayout.selectRecipe(model[currentIndex])
}
}
onModelChanged: function() {
if(!Globals.mobile && count != 0) mainRowLayout.selectRecipe(model[currentIndex])
}
}
RoundButton {
......
......@@ -74,18 +74,14 @@ bool Backend::deleteRecipe(Recipe *recipe) {
}
}
/*
void Backend::shareRecipe(Recipe *recipe) {
if (recipeTcpServer) {
qDebug("Allready sharing a recipe...");
return;
}
qDebug() << "Start to share recipe " << recipe->getName();
recipeTcpServer = new RecipeTcpServer(recipe);
recipeTcpServer->setParent(this);
//TODO connect failed signal
QString Backend::getFilter() const {
return filter;
}
void Backend::setFilter(const QString &filter) {
this->filter = filter;
onRecipesListChanged();
}
*/
void Backend::stopSynchronizing() {
assert(synchronizeAsync);
......@@ -225,7 +221,7 @@ void Backend::removeSyncSettings() const {
void Backend::onRecipesListChanged() {
qDebug() << "Backend::onRecipesListChanged()";
QList<Recipe*> newRecipes = SqlBackend::getRecipes();
QList<Recipe*> newRecipes = SqlBackend::getRecipes(filter);
QList<Recipe*> oldRecipes;
oldRecipes.swap(recipes);
for (const auto &o : oldRecipes) {
......
......@@ -43,6 +43,7 @@ class Backend : public QObject {
Q_PROPERTY(int customSyncServerPort READ getCustomSyncServerPort WRITE setCustomSyncServerPort NOTIFY syncSettingsChanged);
Q_PROPERTY(QString customSyncServerKeyHex READ getCustomSyncServerKeyHex WRITE setCustomSyncServerKeyHex NOTIFY syncSettingsChanged);
Q_PROPERTY(bool useCustomSyncServer READ getUseCustomSyncServer WRITE setUseCustomSyncServer NOTIFY syncSettingsChanged);
Q_PROPERTY(QString filter READ getFilter WRITE setFilter NOTIFY filterChanged);
private:
SynchronizeAsync *synchronizeAsync;
......@@ -50,6 +51,7 @@ class Backend : public QObject {
RecvSyncKeyAsync *recvSyncKeyAsync;
std::unique_ptr<SqlTransaction> transaction;
QList<Recipe*> recipes;
QString filter;
void sortRecipes();
......@@ -85,6 +87,8 @@ class Backend : public QObject {
void setCustomSyncServerAddr(const QString &addr) const;
void setCustomSyncServerPort(int port) const;
void setCustomSyncServerKeyHex(const QString &key) const;
QString getFilter() const;
void setFilter(const QString &filter);
Q_INVOKABLE void setupSyncFromKey(const QString &key);
Q_INVOKABLE void setupSync() const;
Q_INVOKABLE void removeSyncSettings() const;
......@@ -118,6 +122,7 @@ class Backend : public QObject {
void recvSyncKeyDone(bool success);
void openImage(const QUrl &src);
void syncSettingsChanged();
void filterChanged();
};
#endif //BACKEND_H
......@@ -271,9 +271,10 @@ void SqlBackend::setOneValueIngredients(const QString &valueName, const T &value
return;
}
QList<Recipe*> SqlBackend::getRecipes() {
QList<Recipe*> SqlBackend::getRecipes(const QString &filter) {
QSqlQuery query = getQuery();
query.prepare("SELECT id FROM recipes ORDER BY name COLLATE NOCASE;");
query.prepare("SELECT id FROM recipes WHERE UPPER(name) LIKE UPPER(:filter) ORDER BY name COLLATE NOCASE;");
query.bindValue(":filter", QString("%%1%").arg(filter));
tryExec(query);
QList<Recipe*> recipes;
......
......@@ -87,7 +87,7 @@ class SqlBackend : public SqlBackendBase {
/**
* Get all recipes.
*/
static QList<Recipe*> getRecipes();
static QList<Recipe*> getRecipes(const QString &filter = "");
static Recipe* getRecipe(const QByteArray &id);
static QList<Ingredient*> getIngredientsForRecipe(const QByteArray &id);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment