From bd695d1a9152cc649d63b8dd5d232d1d6ce41823 Mon Sep 17 00:00:00 2001 From: Slava Monich Date: Sat, 5 Dec 2020 19:31:34 +0200 Subject: [PATCH] Fix occasional crashes on long-tapping poll items The crash was happening when Repeater was adding context menu items instantiated by PollPreview to context menu owned by MessageListViewItem. It's fixed by instantiating those extra menu items inside context menu itself. Generic ListElement couldn't be used because it doesn't like functions as property values, hence this NamedAction thing. --- harbour-fernschreiber.pro | 2 + qml/components/MessageListViewItem.qml | 10 ++-- qml/components/PollPreview.qml | 46 ++++++------------ src/harbour-fernschreiber.cpp | 3 ++ src/namedaction.cpp | 65 ++++++++++++++++++++++++++ src/namedaction.h | 54 +++++++++++++++++++++ 6 files changed, 145 insertions(+), 35 deletions(-) create mode 100644 src/namedaction.cpp create mode 100644 src/namedaction.h diff --git a/harbour-fernschreiber.pro b/harbour-fernschreiber.pro index c7b972e..ac8118d 100644 --- a/harbour-fernschreiber.pro +++ b/harbour-fernschreiber.pro @@ -31,6 +31,7 @@ SOURCES += src/harbour-fernschreiber.cpp \ src/fernschreiberutils.cpp \ src/knownusersmodel.cpp \ src/mceinterface.cpp \ + src/namedaction.cpp \ src/notificationmanager.cpp \ src/processlauncher.cpp \ src/stickermanager.cpp \ @@ -159,6 +160,7 @@ HEADERS += \ src/fernschreiberutils.h \ src/knownusersmodel.h \ src/mceinterface.h \ + src/namedaction.h \ src/notificationmanager.h \ src/processlauncher.h \ src/stickermanager.h \ diff --git a/qml/components/MessageListViewItem.qml b/qml/components/MessageListViewItem.qml index 96b358c..403182f 100644 --- a/qml/components/MessageListViewItem.qml +++ b/qml/components/MessageListViewItem.qml @@ -20,7 +20,6 @@ import QtQuick 2.6 import Sailfish.Silica 1.0 import "../js/twemoji.js" as Emoji import "../js/functions.js" as Functions -import QtQml.Models 2.3 import "../js/debug.js" as Debug ListItem { @@ -40,7 +39,6 @@ ListItem { && typeof chatView.contentComponentNames[myMessage.content['@type']] !== "undefined" ? chatView.contentComponentNames[myMessage.content['@type']] : "" - readonly property ObjectModel additionalContextItems: ObjectModel {} highlighted: (down || isSelected) && !menuOpen openMenuOnPressAndHold: !messageListItem.precalculatedValues.pageIsSelecting @@ -80,7 +78,13 @@ ListItem { sourceComponent: Component { ContextMenu { Repeater { - model: messageListItem.additionalContextItems + model: (extraContentLoader.item && ("extraContextMenuItems" in extraContentLoader.item)) ? + extraContentLoader.item.extraContextMenuItems : 0 + delegate: MenuItem { + visible: modelData.visible + text: modelData.name + onClicked: modelData.action() + } } MenuItem { diff --git a/qml/components/PollPreview.qml b/qml/components/PollPreview.qml index 49e6001..62e0971 100644 --- a/qml/components/PollPreview.qml +++ b/qml/components/PollPreview.qml @@ -19,6 +19,7 @@ import QtQuick 2.6 import Sailfish.Silica 1.0 +import WerkWolf.Fernschreiber 1.0 import "../js/functions.js" as Functions import "../js/twemoji.js" as Emoji @@ -46,8 +47,19 @@ Item { property bool highlighted width: parent.width height: pollColumn.height - opacity: 0 - Behavior on opacity { FadeAnimation {} } + property list extraContextMenuItems: [ + NamedAction { + visible: !pollData.is_closed && pollMessageComponent.canEdit + name: qsTr("Close Poll") + action: function () { tdLibWrapper.stopPoll(pollMessageComponent.chatId, pollMessageComponent.messageId) } + }, + NamedAction { + visible: !pollData.is_closed && !pollMessageComponent.isQuiz && pollMessageComponent.hasAnswered + name: qsTr("Reset Answer") + action: function () { pollMessageComponent.resetChosen() } + } + ] + function handleChoose(index) { if(!pollData.type.allow_multiple_answers) { chosenIndexes = [index]; @@ -282,34 +294,4 @@ Item { } } } - - Component { - id: closePollMenuItemComponent - MenuItem { - visible: !pollData.is_closed && pollMessageComponent.canEdit - text: qsTr("Close Poll") - onClicked: { - tdLibWrapper.stopPoll(pollMessageComponent.chatId, pollMessageComponent.messageId); - } - } - } - - Component { - id: resetAnswerMenuItemComponent - MenuItem { - visible: !pollData.is_closed && !pollMessageComponent.isQuiz && pollMessageComponent.hasAnswered - text: qsTr("Reset Answer") - onClicked: { - pollMessageComponent.resetChosen() - } - } - } - - Component.onCompleted: { - opacity = 1; - if(messageListItem && messageListItem.additionalContextItems ) { - messageListItem.additionalContextItems.append(closePollMenuItemComponent.createObject()); - messageListItem.additionalContextItems.append(resetAnswerMenuItemComponent.createObject()); - } - } } diff --git a/src/harbour-fernschreiber.cpp b/src/harbour-fernschreiber.cpp index 611fd15..a2efd4f 100644 --- a/src/harbour-fernschreiber.cpp +++ b/src/harbour-fernschreiber.cpp @@ -29,12 +29,14 @@ #include #include #include + #include "appsettings.h" #include "debuglogjs.h" #include "tdlibfile.h" #include "tdlibwrapper.h" #include "chatlistmodel.h" #include "chatmodel.h" +#include "namedaction.h" #include "notificationmanager.h" #include "mceinterface.h" #include "dbusadaptor.h" @@ -66,6 +68,7 @@ int main(int argc, char *argv[]) const char *uri = "WerkWolf.Fernschreiber"; qmlRegisterType(uri, 1, 0, "TDLibFile"); + qmlRegisterType(uri, 1, 0, "NamedAction"); qmlRegisterSingletonType(uri, 1, 0, "DebugLog", DebugLogJS::createSingleton); AppSettings *appSettings = new AppSettings(view.data()); diff --git a/src/namedaction.cpp b/src/namedaction.cpp new file mode 100644 index 0000000..0abb5d5 --- /dev/null +++ b/src/namedaction.cpp @@ -0,0 +1,65 @@ +/* + This file is part of Fernschreiber. + + Fernschreiber 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. + + Fernschreiber 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 Fernschreiber. If not, see . +*/ + +#include "namedaction.h" + +// A workaroud for +// ListElement: cannot use script for property value + +NamedAction::NamedAction(QObject *parent) : + QObject(parent), + visible(true), + action(QJSValue::UndefinedValue) +{ +} + +bool NamedAction::getVisible() const +{ + return visible; +} + +void NamedAction::setVisible(bool newVisible) +{ + if (visible != newVisible) { + visible = newVisible; + emit visibleChanged(); + } +} + +QString NamedAction::getName() const +{ + return name; +} + +void NamedAction::setName(QString newName) +{ + if (name != newName) { + name = newName; + emit nameChanged(); + } +} + +QJSValue NamedAction::getAction() const +{ + return action; +} + +void NamedAction::setAction(QJSValue newAction) +{ + action = newAction; + emit actionChanged(); +} diff --git a/src/namedaction.h b/src/namedaction.h new file mode 100644 index 0000000..b8cdb82 --- /dev/null +++ b/src/namedaction.h @@ -0,0 +1,54 @@ +/* + This file is part of Fernschreiber. + + Fernschreiber 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. + + Fernschreiber 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 Fernschreiber. If not, see . +*/ + +#ifndef NAMEDACTION_H +#define NAMEDACTION_H + +#include +#include +#include + +class NamedAction : public QObject { + Q_OBJECT + Q_PROPERTY(bool visible READ getVisible WRITE setVisible NOTIFY visibleChanged) + Q_PROPERTY(QString name READ getName WRITE setName NOTIFY nameChanged) + Q_PROPERTY(QJSValue action READ getAction WRITE setAction NOTIFY actionChanged) + +public: + NamedAction(QObject *parent = Q_NULLPTR); + + bool getVisible() const; + void setVisible(bool newVisible); + + QString getName() const; + void setName(QString newName); + + QJSValue getAction() const; + void setAction(QJSValue newAction); + +signals: + void visibleChanged(); + void nameChanged(); + void actionChanged(); + +private: + bool visible; + QString name; + QJSValue action; +}; + +#endif // NAMEDACTION_H