From 195e255f08447c9c355f70de97fcd26b81007c39 Mon Sep 17 00:00:00 2001 From: Slava Monich Date: Sun, 19 Nov 2023 22:54:50 +0200 Subject: [PATCH] Added UI for configuring session inactivity timeout (#527) --- .../settingsPage/SettingsSession.qml | 251 ++++++++++-------- src/tdlibreceiver.cpp | 3 +- src/tdlibreceiver.h | 2 +- src/tdlibwrapper.cpp | 10 +- src/tdlibwrapper.h | 3 +- 5 files changed, 160 insertions(+), 109 deletions(-) diff --git a/qml/components/settingsPage/SettingsSession.qml b/qml/components/settingsPage/SettingsSession.qml index 9f5a9b6..cb65cf8 100644 --- a/qml/components/settingsPage/SettingsSession.qml +++ b/qml/components/settingsPage/SettingsSession.qml @@ -30,141 +30,182 @@ AccordionItem { Column { id: activeSessionsItem bottomPadding: Theme.paddingMedium - property variant activeSessions; - property bool loaded : false; + property variant activeSessions + property int inactiveSessionsTtlDays Component.onCompleted: { if (!activeSessions) { tdLibWrapper.getActiveSessions(); - } else { - activeSessionsItem.loaded = true; } } Connections { target: tdLibWrapper onSessionsReceived: { - activeSessionsItem.activeSessions = sessions; - activeSessionsItem.loaded = true; + activeSessionsItem.activeSessions = sessions + activeSessionsItem.inactiveSessionsTtlDays = inactive_session_ttl_days } onOkReceived: { if (request === "terminateSession") { appNotification.show(qsTr("Session was terminated")); - activeSessionsItem.loaded = false; tdLibWrapper.getActiveSessions(); } } } Loader { - id: sessionInformationLoader active: tdLibWrapper.authorizationState === TelegramAPI.AuthorizationReady width: parent.width sourceComponent: Component { - SilicaListView { - id: activeSessionsListView - width: parent.width - height: contentHeight - model: activeSessionsItem.activeSessions - headerPositioning: ListView.OverlayHeader - header: Separator { - width: parent.width - color: Theme.primaryColor - horizontalAlignment: Qt.AlignHCenter + Column { + BusyIndicator { + anchors.horizontalCenter: parent.horizontalCenter + running: !activeSessionsListView.count && !activeSessionsItem.inactiveSessionsTtlDays + size: BusyIndicatorSize.Medium + visible: opacity > 0 + height: running ? implicitHeight : 0 } - delegate: ListItem { - id: activeSessionListItem + + SilicaListView { + id: activeSessionsListView width: parent.width - contentHeight: activeSessionColumn.height + ( 2 * Theme.paddingMedium ) - - menu: ContextMenu { - hasContent: !modelData.is_current - onHeightChanged: { - if (parent && flickable) { - // Make sure we are inside the screen area - var bottom = parent.mapToItem(flickable, x, y).y + height - if (bottom > flickable.height) { - flickable.contentY += bottom - flickable.height - } - } - } - MenuItem { - onClicked: { - var sessionId = modelData.id; - Remorse.itemAction(activeSessionListItem, qsTr("Terminating session"), function() { tdLibWrapper.terminateSession(sessionId); }); - } - text: qsTr("Terminate Session") - } - } - - Column { - id: activeSessionColumn - width: parent.width - ( 2 * Theme.horizontalPageMargin ) - spacing: Theme.paddingSmall - anchors.verticalCenter: parent.verticalCenter - anchors.horizontalCenter: parent.horizontalCenter - - Label { - width: parent.width - text: qsTr("This app") - font.pixelSize: Theme.fontSizeMedium - font.bold: true - visible: modelData.is_current - color: Theme.highlightColor - anchors { - horizontalCenter: parent.horizontalCenter - } - } - - Label { - width: parent.width - text: modelData.application_name + " " + modelData.application_version - font.pixelSize: Theme.fontSizeMedium - font.bold: true - color: Theme.primaryColor - maximumLineCount: 1 - elide: Text.ElideRight - anchors { - horizontalCenter: parent.horizontalCenter - } - } - - Label { - width: parent.width - text: modelData.device_model + ", " + (modelData.platform + " " + modelData.system_version).trim() - font.pixelSize: Theme.fontSizeSmall - color: Theme.primaryColor - maximumLineCount: 1 - truncationMode: TruncationMode.Fade - anchors { - horizontalCenter: parent.horizontalCenter - } - } - - Label { - width: parent.width - text: qsTr("Active since: %1, last online: %2").arg(Functions.getDateTimeTimepoint(modelData.log_in_date)).arg(Functions.getDateTimeElapsed(modelData.last_active_date)) - font.pixelSize: Theme.fontSizeExtraSmall - color: Theme.primaryColor - maximumLineCount: 1 - truncationMode: TruncationMode.Fade - anchors { - horizontalCenter: parent.horizontalCenter - } - } - } - - Separator { - id: separator - anchors { - bottom: parent.bottom - } - + height: contentHeight + model: activeSessionsItem.activeSessions + headerPositioning: ListView.OverlayHeader + header: Separator { width: parent.width color: Theme.primaryColor horizontalAlignment: Qt.AlignHCenter + visible: activeSessionsListView.count > 0 + } + delegate: ListItem { + id: activeSessionListItem + width: parent.width + contentHeight: activeSessionColumn.height + ( 2 * Theme.paddingMedium ) + + menu: ContextMenu { + hasContent: !modelData.is_current + onHeightChanged: { + if (parent && flickable) { + // Make sure we are inside the screen area + var bottom = parent.mapToItem(flickable, x, y).y + height + if (bottom > flickable.height) { + flickable.contentY += bottom - flickable.height + } + } + } + MenuItem { + onClicked: { + var sessionId = modelData.id; + Remorse.itemAction(activeSessionListItem, qsTr("Terminating session"), function() { tdLibWrapper.terminateSession(sessionId); }); + } + text: qsTr("Terminate Session") + } + } + + Column { + id: activeSessionColumn + width: parent.width - ( 2 * Theme.horizontalPageMargin ) + spacing: Theme.paddingSmall + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + + Label { + width: parent.width + text: qsTr("This app") + font.pixelSize: Theme.fontSizeMedium + font.bold: true + visible: modelData.is_current + color: Theme.highlightColor + } + + Label { + width: parent.width + text: modelData.application_name + " " + modelData.application_version + font.pixelSize: Theme.fontSizeMedium + font.bold: true + maximumLineCount: 1 + elide: Text.ElideRight + } + + Label { + width: parent.width + text: modelData.device_model + ", " + (modelData.platform + " " + modelData.system_version).trim() + font.pixelSize: Theme.fontSizeSmall + maximumLineCount: 1 + truncationMode: TruncationMode.Fade + } + + Label { + width: parent.width + text: qsTr("Active since: %1, last online: %2").arg(Functions.getDateTimeTimepoint(modelData.log_in_date)).arg(Functions.getDateTimeElapsed(modelData.last_active_date)) + font.pixelSize: Theme.fontSizeExtraSmall + maximumLineCount: 1 + truncationMode: TruncationMode.Fade + } + } + + Separator { + anchors { + bottom: parent.bottom + } + + width: parent.width + color: Theme.primaryColor + horizontalAlignment: Qt.AlignHCenter + } + } + } + + ComboBox { + readonly property int ttl: activeSessionsItem.inactiveSessionsTtlDays + label: qsTr("Terminate old sessions if inactive for") + value: (currentItem && currentItem.text) ? currentItem.text : qsTr("%1 day(s)", "", ttl).arg(ttl) + visible: ttl > 0 + menu: ContextMenu { + id: ttlMenu + MenuItem { + readonly property int days: 7 + text: qsTr("1 week") + onClicked: tdLibWrapper.setInactiveSessionTtl(days) + } + MenuItem { + readonly property int days: 30 + text: qsTr("1 month") + onClicked: tdLibWrapper.setInactiveSessionTtl(days) + } + MenuItem { + readonly property int days: 90 + text: qsTr("3 months") + onClicked: tdLibWrapper.setInactiveSessionTtl(days) + } + MenuItem { + readonly property int days: 180 + text: qsTr("6 months") + onClicked: tdLibWrapper.setInactiveSessionTtl(days) + } + MenuItem { + readonly property int days: 365 + text: qsTr("1 year") + onClicked: tdLibWrapper.setInactiveSessionTtl(days) + } } + Component.onCompleted: updateSelection() + + onTtlChanged: updateSelection() + + function updateSelection() { + var menuItems = ttlMenu.children + var n = menuItems.length + for (var i = 0; i < n; i++) { + if (menuItems[i].days === ttl) { + currentIndex = i + return + } + } + currentIndex = -1 + } } } } diff --git a/src/tdlibreceiver.cpp b/src/tdlibreceiver.cpp index 11a46dc..f14eeeb 100644 --- a/src/tdlibreceiver.cpp +++ b/src/tdlibreceiver.cpp @@ -712,8 +712,9 @@ void TDLibReceiver::processUpdateMessageInteractionInfo(const QVariantMap &recei void TDLibReceiver::processSessions(const QVariantMap &receivedInformation) { + int inactive_session_ttl_days = receivedInformation.value("inactive_session_ttl_days").toInt(); QVariantList sessions = receivedInformation.value("sessions").toList(); - emit sessionsReceived(sessions); + emit sessionsReceived(inactive_session_ttl_days, sessions); } void TDLibReceiver::processAvailableReactions(const QVariantMap &receivedInformation) diff --git a/src/tdlibreceiver.h b/src/tdlibreceiver.h index a13ae04..cf6558c 100644 --- a/src/tdlibreceiver.h +++ b/src/tdlibreceiver.h @@ -101,7 +101,7 @@ signals: void userPrivacySettingRulesUpdated(const QVariantMap &updatedRules); void messageInteractionInfoUpdated(qlonglong chatId, qlonglong messageId, const QVariantMap &updatedInfo); void okReceived(const QString &request); - void sessionsReceived(const QVariantList &sessions); + void sessionsReceived(int inactive_session_ttl_days, const QVariantList &sessions); void availableReactionsReceived(qlonglong messageId, const QStringList &reactions); void chatUnreadMentionCountUpdated(qlonglong chatId, int unreadMentionCount); void chatUnreadReactionCountUpdated(qlonglong chatId, int unreadReactionCount); diff --git a/src/tdlibwrapper.cpp b/src/tdlibwrapper.cpp index ffa902d..f815ccf 100644 --- a/src/tdlibwrapper.cpp +++ b/src/tdlibwrapper.cpp @@ -187,7 +187,7 @@ void TDLibWrapper::initializeTDLibReceiver() { connect(this->tdLibReceiver, SIGNAL(userPrivacySettingRulesUpdated(QVariantMap)), this, SLOT(handleUpdatedUserPrivacySettingRules(QVariantMap))); connect(this->tdLibReceiver, SIGNAL(messageInteractionInfoUpdated(qlonglong, qlonglong, QVariantMap)), this, SIGNAL(messageInteractionInfoUpdated(qlonglong, qlonglong, QVariantMap))); connect(this->tdLibReceiver, SIGNAL(okReceived(QString)), this, SIGNAL(okReceived(QString))); - connect(this->tdLibReceiver, SIGNAL(sessionsReceived(QVariantList)), this, SIGNAL(sessionsReceived(QVariantList))); + connect(this->tdLibReceiver, SIGNAL(sessionsReceived(int, QVariantList)), this, SIGNAL(sessionsReceived(int, QVariantList))); connect(this->tdLibReceiver, SIGNAL(availableReactionsReceived(qlonglong, QStringList)), this, SIGNAL(availableReactionsReceived(qlonglong, QStringList))); connect(this->tdLibReceiver, SIGNAL(chatUnreadMentionCountUpdated(qlonglong, int)), this, SIGNAL(chatUnreadMentionCountUpdated(qlonglong, int))); connect(this->tdLibReceiver, SIGNAL(chatUnreadReactionCountUpdated(qlonglong, int)), this, SIGNAL(chatUnreadReactionCountUpdated(qlonglong, int))); @@ -1520,6 +1520,14 @@ void TDLibWrapper::setNetworkType(NetworkType networkType) this->sendRequest(requestObject); } +void TDLibWrapper::setInactiveSessionTtl(int days) +{ + QVariantMap requestObject; + requestObject.insert(_TYPE, "setInactiveSessionTtl"); + requestObject.insert("inactive_session_ttl_days", days); + this->sendRequest(requestObject); +} + void TDLibWrapper::searchEmoji(const QString &queryString) { LOG("Searching emoji" << queryString); diff --git a/src/tdlibwrapper.h b/src/tdlibwrapper.h index 33e29b4..17a0896 100644 --- a/src/tdlibwrapper.h +++ b/src/tdlibwrapper.h @@ -251,6 +251,7 @@ public: Q_INVOKABLE void getPageSource(const QString &address); Q_INVOKABLE void setMessageReaction(qlonglong chatId, qlonglong messageId, const QString &reaction); Q_INVOKABLE void setNetworkType(NetworkType networkType); + Q_INVOKABLE void setInactiveSessionTtl(int days); // Others (candidates for extraction ;)) Q_INVOKABLE void searchEmoji(const QString &queryString); @@ -331,7 +332,7 @@ signals: void userPrivacySettingUpdated(UserPrivacySetting setting, UserPrivacySettingRule rule); void messageInteractionInfoUpdated(qlonglong chatId, qlonglong messageId, const QVariantMap &updatedInfo); void okReceived(const QString &request); - void sessionsReceived(const QVariantList &sessions); + void sessionsReceived(int inactive_session_ttl_days, const QVariantList &sessions); void openFileExternally(const QString &filePath); void availableReactionsReceived(qlonglong messageId, const QStringList &reactions); void chatUnreadMentionCountUpdated(qlonglong chatId, int unreadMentionCount);