From d5f8c1af0aaba15ed806e629d30d60b8a6e22dd8 Mon Sep 17 00:00:00 2001 From: Julien Wadel Date: Thu, 9 Jan 2025 09:29:20 +0100 Subject: [PATCH] Feature: custom shortcuts on main page. #LINQT-1506 --- Linphone/core/setting/SettingsCore.cpp | 11 +++- Linphone/core/setting/SettingsCore.hpp | 7 +-- Linphone/model/setting/SettingsModel.cpp | 50 +++++++++++++++++++ Linphone/model/setting/SettingsModel.hpp | 4 +- .../view/Control/Container/VerticalTabBar.qml | 15 ++++-- Linphone/view/Control/Display/EffectImage.qml | 2 + Linphone/view/Page/Layout/Main/MainLayout.qml | 24 +++++++-- 7 files changed, 100 insertions(+), 13 deletions(-) diff --git a/Linphone/core/setting/SettingsCore.cpp b/Linphone/core/setting/SettingsCore.cpp index 547302974..8f3bb7805 100644 --- a/Linphone/core/setting/SettingsCore.cpp +++ b/Linphone/core/setting/SettingsCore.cpp @@ -110,6 +110,9 @@ SettingsCore::SettingsCore(QObject *parent) : QObject(parent) { INIT_CORE_MEMBER(Ipv6Enabled, settingsModel) INIT_CORE_MEMBER(ConfigLocale, settingsModel) INIT_CORE_MEMBER(DownloadFolder, settingsModel) + + INIT_CORE_MEMBER(ShortcutCount, settingsModel) + INIT_CORE_MEMBER(Shortcuts, settingsModel) } SettingsCore::SettingsCore(const SettingsCore &settingsCore) { @@ -178,6 +181,8 @@ SettingsCore::SettingsCore(const SettingsCore &settingsCore) { mIpv6Enabled = settingsCore.mIpv6Enabled; mConfigLocale = settingsCore.mConfigLocale; mDownloadFolder = settingsCore.mDownloadFolder; + mShortcutCount = settingsCore.mShortcutCount; + mShortcuts = settingsCore.mShortcuts; } SettingsCore::~SettingsCore() { @@ -339,6 +344,10 @@ void SettingsCore::setSelf(QSharedPointer me) { configLocale, ConfigLocale) DEFINE_CORE_GETSET_CONNECT(mSettingsModelConnection, SettingsCore, SettingsModel, settingsModel, QString, downloadFolder, DownloadFolder) + DEFINE_CORE_GET_CONNECT(mSettingsModelConnection, SettingsCore, SettingsModel, settingsModel, int, shortcutCount, + ShortcutCount) + DEFINE_CORE_GET_CONNECT(mSettingsModelConnection, SettingsCore, SettingsModel, settingsModel, QVariantList, + shortcuts, Shortcuts) auto coreModelConnection = QSharedPointer>( new SafeConnection(me, CoreModel::getInstance()), &QObject::deleteLater); @@ -936,4 +945,4 @@ void SettingsCore::undo() { }); }); } -} \ No newline at end of file +} diff --git a/Linphone/core/setting/SettingsCore.hpp b/Linphone/core/setting/SettingsCore.hpp index fb262aebf..ad7313b0c 100644 --- a/Linphone/core/setting/SettingsCore.hpp +++ b/Linphone/core/setting/SettingsCore.hpp @@ -212,10 +212,11 @@ public: DECLARE_CORE_GETSET(bool, exitOnClose, ExitOnClose) DECLARE_CORE_GETSET(bool, syncLdapContacts, SyncLdapContacts) DECLARE_CORE_GETSET_MEMBER(bool, ipv6Enabled, Ipv6Enabled) - DECLARE_CORE_GETSET_MEMBER(QVariantList, audioCodecs, AudioCodecs) - DECLARE_CORE_GETSET_MEMBER(QVariantList, videoCodecs, VideoCodecs) DECLARE_CORE_GETSET(QString, configLocale, ConfigLocale) DECLARE_CORE_GETSET(QString, downloadFolder, DownloadFolder) + // Read-only + DECLARE_CORE_MEMBER(int, shortcutCount, ShortcutCount) + DECLARE_CORE_MEMBER(QVariantList, shortcuts, Shortcuts) signals: @@ -306,7 +307,7 @@ private: QVariantList mConferenceLayouts; QVariantMap mConferenceLayout; - + // Video QStringList mVideoDevices; QString mVideoDevice; diff --git a/Linphone/model/setting/SettingsModel.cpp b/Linphone/model/setting/SettingsModel.cpp index 5e50e72f4..5cd936b6e 100644 --- a/Linphone/model/setting/SettingsModel.cpp +++ b/Linphone/model/setting/SettingsModel.cpp @@ -620,6 +620,47 @@ bool SettingsModel::getShowChats() const { return mConfig->getBool(UiSection, "disable_chat_feature", false); }*/ +QVariantList SettingsModel::getShortcuts() const { + mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); + QVariantList shortcuts; + auto sections = mConfig->getSectionsNamesList(); + for (auto section : sections) { + auto sectionTokens = Utils::coreStringToAppString(section).split('_'); + if (sectionTokens.size() > 1 && sectionTokens[0].compare("shortcut", Qt::CaseInsensitive) == 0) { + QVariantMap shortcut; + shortcut["id"] = sectionTokens[1].toInt(); + shortcut["name"] = Utils::coreStringToAppString(mConfig->getString(section, "name", "")); + shortcut["link"] = Utils::coreStringToAppString(mConfig->getString(section, "link", "")); + shortcut["icon"] = Utils::coreStringToAppString(mConfig->getString(section, "icon", "")); + shortcuts << shortcut; + } + } + return shortcuts; +} + +void SettingsModel::setShortcuts(QVariantList data) { + if (getShortcuts() != data) { + // clean + auto sections = mConfig->getSectionsNamesList(); + for (auto section : sections) { + auto sectionTokens = Utils::coreStringToAppString(section).split('_'); + if (sectionTokens.size() > 1 && sectionTokens[0].compare("shortcut", Qt::CaseInsensitive) == 0) { + mConfig->cleanSection(section); + } + } + int count = 0; + for (auto shortcut : data) { + auto mShortcut = shortcut.toMap(); + auto key = Utils::appStringToCoreString("shortcut_" + QString::number(count++)); + mConfig->setString(key, "name", Utils::appStringToCoreString(mShortcut["name"].toString())); + mConfig->setString(key, "link", Utils::appStringToCoreString(mShortcut["link"].toString())); + mConfig->setString(key, "icon", Utils::appStringToCoreString(mShortcut["icon"].toString())); + } + + emit shortcutsChanged(data); + } +} + // clang-format off void SettingsModel::notifyConfigReady(){ DEFINE_NOTIFY_CONFIG_READY(disableChatFeature, DisableChatFeature) @@ -642,6 +683,8 @@ void SettingsModel::notifyConfigReady(){ DEFINE_NOTIFY_CONFIG_READY(syncLdapContacts, SyncLdapContacts) DEFINE_NOTIFY_CONFIG_READY(configLocale, ConfigLocale) DEFINE_NOTIFY_CONFIG_READY(downloadFolder, DownloadFolder) + DEFINE_NOTIFY_CONFIG_READY(shortcutCount, ShortcutCount) + DEFINE_NOTIFY_CONFIG_READY(shortcuts, Shortcuts) } DEFINE_GETSET_CONFIG(SettingsModel, bool, Bool, disableChatFeature, DisableChatFeature, "disable_chat_feature", true) @@ -749,4 +792,11 @@ DEFINE_GETSET_CONFIG_STRING(SettingsModel, DownloadFolder, "download_folder", "") +DEFINE_GETSET_CONFIG(SettingsModel, + int, + Int, + shortcutCount, + ShortcutCount, + "shortcut_count", + 0) // clang-format on diff --git a/Linphone/model/setting/SettingsModel.hpp b/Linphone/model/setting/SettingsModel.hpp index 31a5badb7..0bfc5ae56 100644 --- a/Linphone/model/setting/SettingsModel.hpp +++ b/Linphone/model/setting/SettingsModel.hpp @@ -168,6 +168,8 @@ public: DECLARE_GETSET(bool, ipv6Enabled, Ipv6Enabled) DECLARE_GETSET(QString, configLocale, ConfigLocale) DECLARE_GETSET(QString, downloadFolder, DownloadFolder) + DECLARE_GETSET(int, shortcutCount, ShortcutCount) + DECLARE_GETSET(QVariantList, shortcuts, Shortcuts) signals: void logsUploadUrlChanged(); @@ -198,8 +200,6 @@ signals: void mediaEncryptionChanged(); void mediaEncryptionMandatoryChanged(); - void showAudioCodecsChanged(bool status); - void micVolumeChanged(float volume); void logsEnabledChanged(bool status); diff --git a/Linphone/view/Control/Container/VerticalTabBar.qml b/Linphone/view/Control/Container/VerticalTabBar.qml index c8795fd51..6260c9768 100644 --- a/Linphone/view/Control/Container/VerticalTabBar.qml +++ b/Linphone/view/Control/Container/VerticalTabBar.qml @@ -14,6 +14,12 @@ Control.TabBar { readonly property alias cornerRadius: bottomLeftCorner.radius property AccountGui defaultAccount + + // Call it after model is ready. If done before, Repeater will not be updated + function initButtons(){ + actionsRepeater.model = mainItem.model + } + onDefaultAccountChanged: { if (defaultAccount) defaultAccount.core?.lRefreshNotifications() } @@ -77,14 +83,13 @@ Control.TabBar { height: parent.height/2 } } - + Repeater { id: actionsRepeater - model: mainItem.model Control.TabButton { id: tabButton width: mainItem.width - height: visible ? undefined : 0 + height: visible && buttonIcon.isImageReady ? undefined : 0 bottomInset: 32 * DefaultStyle.dp topInset: 32 * DefaultStyle.dp @@ -112,10 +117,12 @@ Control.TabBar { Layout.preferredHeight: buttonSize Layout.alignment: Qt.AlignHCenter fillMode: Image.PreserveAspectFit - colorizationColor: DefaultStyle.grey_0 + colorizationColor: DefaultStyle.grey_0 + useColor: !modelData.colored } Text { id: buttonText + visible: buttonIcon.isImageReady text: modelData.label font { weight: mainItem.currentIndex === index ? 800 * DefaultStyle.dp : 400 * DefaultStyle.dp diff --git a/Linphone/view/Control/Display/EffectImage.qml b/Linphone/view/Control/Display/EffectImage.qml index 02f3f8005..2ecd403bf 100644 --- a/Linphone/view/Control/Display/EffectImage.qml +++ b/Linphone/view/Control/Display/EffectImage.qml @@ -17,6 +17,7 @@ Loader { property int imageHeight: height property bool useColor: colorizationColor != undefined property bool shadowEnabled: false + property bool isImageReady: false asynchronous: true sourceComponent: Component{Item { Image { @@ -31,6 +32,7 @@ Loader { Layout.preferredWidth: mainItem.imageWidth Layout.preferredHeight: mainItem.imageHeight anchors.centerIn: parent + onStatusChanged: mainItem.isImageReady = (status == Image.Ready) } MultiEffect { id: effect diff --git a/Linphone/view/Page/Layout/Main/MainLayout.qml b/Linphone/view/Page/Layout/Main/MainLayout.qml index 1e4f0f9df..90f5b7781 100644 --- a/Linphone/view/Page/Layout/Main/MainLayout.qml +++ b/Linphone/view/Page/Layout/Main/MainLayout.qml @@ -11,6 +11,7 @@ import QtQuick.Effects import Linphone import UtilsCpp import SettingsCpp +import 'qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js' as Utils Item { id: mainItem @@ -116,7 +117,6 @@ Item { Layout.fillHeight: true Layout.preferredWidth: 82 * DefaultStyle.dp defaultAccount: accountProxy.defaultAccount - currentIndex: SettingsCpp.getLastActiveTabIndex() Binding on currentIndex { when: mainItem.contextualMenuOpenedComponent != undefined value: -1 @@ -129,7 +129,6 @@ Item { ] onCurrentIndexChanged: { if (currentIndex == -1) return - SettingsCpp.setLastActiveTabIndex(currentIndex) if (currentIndex === 0 && accountProxy.defaultAccount) accountProxy.defaultAccount.core?.lResetMissedCalls() if (mainItem.contextualMenuOpenedComponent) { closeContextualMenuComponent() @@ -140,6 +139,16 @@ Item { mainStackView.currentItem.forceActiveFocus() } } + Component.onCompleted:{ + if(SettingsCpp.shortcutCount > 0){ + var shortcuts = SettingsCpp.shortcuts + shortcuts.forEach((shortcut) => { + model.push({icon: shortcut.icon, selectedIcon: shortcut.icon, label: shortcut.name, colored: true, link:shortcut.link}) + }); + } + initButtons() + currentIndex= SettingsCpp.getLastActiveTabIndex() + } } ColumnLayout { spacing:0 @@ -494,8 +503,17 @@ Item { StackLayout { id: mainStackLayout objectName: "mainStackLayout" - currentIndex: tabbar.currentIndex + property int _currentIndex: tabbar.currentIndex + currentIndex: -1 onActiveFocusChanged: if(activeFocus && currentIndex >= 0) children[currentIndex].forceActiveFocus() + on_CurrentIndexChanged:{ + if(count > 0 && _currentIndex >= count && tabbar.model[_currentIndex].link){ + Qt.openUrlExternally(tabbar.model[_currentIndex].link) + }else { + currentIndex = _currentIndex + SettingsCpp.setLastActiveTabIndex(currentIndex) + } + } CallPage { id: callPage Connections {