diff --git a/CMakeLists.txt b/CMakeLists.txt index b099cccf4..981b8032d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ set (RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE project(kdeconnect VERSION ${RELEASE_SERVICE_VERSION}) -set(KF_MIN_VERSION "5.240") +set(KF_MIN_VERSION "6.0.0") set(QT_MIN_VERSION "6.7.0") set(CMAKE_CXX_STANDARD 20) @@ -94,7 +94,7 @@ ecm_find_qmlmodule(QtQuick.Particles 2.0) add_definitions(-DQT_NO_URL_CAST_FROM_STRING -DQT_NO_KEYWORDS -DQT_NO_CAST_FROM_ASCII) -find_package(Qt6 ${QT_MIN_VERSION} REQUIRED COMPONENTS DBus Quick QuickControls2 Network Multimedia) +find_package(Qt6 ${QT_MIN_VERSION} REQUIRED COMPONENTS DBus Quick QuickWidgets QuickControls2 Network Multimedia) find_package(KF6 ${KF_MIN_VERSION} REQUIRED COMPONENTS I18n ConfigWidgets DBusAddons IconThemes Notifications KIO KCMUtils Service Solid Kirigami People WindowSystem GuiAddons DocTools Crash) diff --git a/app/qml/FindDevicesPage.qml b/app/qml/FindDevicesPage.qml index 6d6b67c53..8c7745bb2 100644 --- a/app/qml/FindDevicesPage.qml +++ b/app/qml/FindDevicesPage.qml @@ -57,6 +57,7 @@ Kirigami.ScrollablePage text: i18nd("kdeconnect-app", "No devices found") icon.name: 'edit-none-symbolic' anchors.centerIn: parent + width: parent.width - (Kirigami.Units.largeSpacing * 4) visible: devices.count === 0 } diff --git a/kcm/CMakeLists.txt b/kcm/CMakeLists.txt index 690cc2e24..dec601b49 100644 --- a/kcm/CMakeLists.txt +++ b/kcm/CMakeLists.txt @@ -1,7 +1,8 @@ +qt_add_resources(kcm_SRCS assets.qrc) + add_definitions(-DTRANSLATION_DOMAIN="kdeconnect-kcm") - -kcoreaddons_add_plugin(kcm_kdeconnect SOURCES kcm.cpp INSTALL_NAMESPACE plasma/kcms/systemsettings_qwidgets) +kcoreaddons_add_plugin(kcm_kdeconnect SOURCES kcm.cpp ${kcm_SRCS} INSTALL_NAMESPACE plasma/kcms/systemsettings_qwidgets) kcmutils_generate_desktop_file(kcm_kdeconnect) ki18n_wrap_ui(kcm_kdeconnect kcm.ui) @@ -9,6 +10,7 @@ ki18n_wrap_ui(kcm_kdeconnect kcm.ui) target_link_libraries(kcm_kdeconnect Qt::Core Qt::Gui + Qt::QuickWidgets KF6::I18n KF6::KCMUtils kdeconnectinterfaces diff --git a/kcm/Messages.sh b/kcm/Messages.sh index 150dda395..814dba6df 100755 --- a/kcm/Messages.sh +++ b/kcm/Messages.sh @@ -5,5 +5,6 @@ $XGETTEXT rc.cpp -o $podir/kdeconnect-kcm.pot rm -f rc.cpp #.cpp (-j passed to merge into existing file) +$XGETTEXT `find . -name '*.qml'` -j -o $podir/kdeconnect-kcm.pot $XGETTEXT `find . -name '*.cpp'` -j -o $podir/kdeconnect-kcm.pot diff --git a/kcm/assets.qrc b/kcm/assets.qrc new file mode 100644 index 000000000..daf779c30 --- /dev/null +++ b/kcm/assets.qrc @@ -0,0 +1,7 @@ + + + + + list.qml + + diff --git a/kcm/kcm.cpp b/kcm/kcm.cpp index 4cd9add52..6bc6feb62 100644 --- a/kcm/kcm.cpp +++ b/kcm/kcm.cpp @@ -14,6 +14,9 @@ #include #include +#include +#include + #include "dbushelpers.h" #include "dbusinterfaces.h" #include "devicesmodel.h" @@ -22,6 +25,21 @@ K_PLUGIN_CLASS_WITH_JSON(KdeConnectKcm, "kcm_kdeconnect.json") +class QQuickWidgetPaleteChangeWatcher : public QObject +{ + using QObject::QObject; + + bool eventFilter(QObject *watched, QEvent *event) override + { + if (event->type() == QEvent::PaletteChange || event->type() == QEvent::ApplicationPaletteChange) { + // We know that watched is a QQuickWidget + QQuickWidget *w = static_cast(watched); + w->setClearColor(w->palette().color(QPalette::Window)); + } + return QObject::eventFilter(watched, event); + } +}; + KdeConnectKcm::KdeConnectKcm(QObject *parent, const KPluginMetaData &md, const QVariantList &args) : KCModule(parent, md) , daemon(new DaemonDbusInterface(this)) @@ -37,7 +55,14 @@ KdeConnectKcm::KdeConnectKcm(QObject *parent, const KPluginMetaData &md, const Q sortProxyModel = new DevicesSortProxyModel(devicesModel); - kcmUi.deviceList->setModel(sortProxyModel); + kcmUi.list_quick_widget->setMinimumWidth(250 * kcmUi.list_quick_widget->devicePixelRatio()); + kcmUi.list_quick_widget->rootContext()->setContextObject(new KLocalizedContext(kcmUi.list_quick_widget)); + kcmUi.list_quick_widget->setClearColor(kcmUi.list_quick_widget->palette().color(QPalette::Window)); + kcmUi.list_quick_widget->setSource(QUrl(QStringLiteral("qrc:/kdeconnectkcm/list.qml"))); + kcmUi.list_quick_widget->rootObject()->setProperty("model", QVariant::fromValue(sortProxyModel)); + connect(kcmUi.list_quick_widget->rootObject(), SIGNAL(clicked(QString)), this, SLOT(deviceSelected(QString))); + + kcmUi.list_quick_widget->installEventFilter(new QQuickWidgetPaleteChangeWatcher(kcmUi.list_quick_widget)); kcmUi.deviceInfo->setVisible(false); kcmUi.progressBar->setVisible(false); @@ -67,8 +92,6 @@ KdeConnectKcm::KdeConnectKcm(QObject *parent, const KPluginMetaData &md, const Q setButtons(KCModule::Help | KCModule::NoAdditionalButton); - connect(devicesModel, &QAbstractItemModel::dataChanged, this, &KdeConnectKcm::resetSelection); - connect(kcmUi.deviceList->selectionModel(), &QItemSelectionModel::currentChanged, this, &KdeConnectKcm::deviceSelected); connect(kcmUi.accept_button, &QAbstractButton::clicked, this, &KdeConnectKcm::acceptPairing); connect(kcmUi.reject_button, &QAbstractButton::clicked, this, &KdeConnectKcm::cancelPairing); connect(kcmUi.cancel_button, &QAbstractButton::clicked, this, &KdeConnectKcm::cancelPairing); @@ -88,11 +111,8 @@ KdeConnectKcm::KdeConnectKcm(QObject *parent, const KPluginMetaData &md, const Q const QString pluginCM = colonIdx < 0 ? QString() : input.mid(colonIdx + 1); connect(devicesModel, &DevicesModel::rowsInserted, this, [this, deviceId, pluginCM]() { - auto row = devicesModel->rowForDevice(deviceId); - if (row >= 0) { - const QModelIndex idx = sortProxyModel->mapFromSource(devicesModel->index(row)); - kcmUi.deviceList->selectionModel()->setCurrentIndex(idx, QItemSelectionModel::ClearAndSelect); - } + kcmUi.list_quick_widget->rootObject()->setProperty("currentDeviceId", deviceId); + deviceSelected(deviceId); if (!pluginCM.isEmpty()) { kcmUi.pluginSelector->showConfiguration(pluginCM); } @@ -136,29 +156,19 @@ void KdeConnectKcm::refresh() daemon->forceOnNetworkChange(); } -void KdeConnectKcm::resetSelection() -{ - if (!currentDevice) { - return; - } - kcmUi.deviceList->selectionModel()->setCurrentIndex(sortProxyModel->mapFromSource(currentIndex), QItemSelectionModel::ClearAndSelect); -} - -void KdeConnectKcm::deviceSelected(const QModelIndex ¤t) +void KdeConnectKcm::deviceSelected(const QString &deviceId) { if (currentDevice) { disconnect(currentDevice, nullptr, this, nullptr); } - if (!current.isValid()) { + currentDevice = devicesModel->getDevice(devicesModel->rowForDevice(deviceId)); + if (!currentDevice) { currentDevice = nullptr; kcmUi.deviceInfo->setVisible(false); return; } - currentIndex = sortProxyModel->mapToSource(current); - currentDevice = devicesModel->getDevice(currentIndex.row()); - kcmUi.noDevicePlaceholder->setVisible(false); bool valid = (currentDevice != nullptr && currentDevice->isValid()); kcmUi.deviceInfo->setVisible(valid); diff --git a/kcm/kcm.h b/kcm/kcm.h index 0fa2831a9..7d2a9d574 100644 --- a/kcm/kcm.h +++ b/kcm/kcm.h @@ -30,11 +30,10 @@ private: void save() override; private Q_SLOTS: - void deviceSelected(const QModelIndex ¤t); + void deviceSelected(const QString &deviceId); void requestPairing(); void pluginsConfigChanged(bool changed); void sendPing(); - void resetSelection(); void pairingFailed(const QString &error); void refresh(); void renameShow(); @@ -53,7 +52,6 @@ private: DevicesModel *devicesModel; DevicesSortProxyModel *sortProxyModel; DeviceDbusInterface *currentDevice; - QModelIndex currentIndex; QStringList m_oldSupportedPluginNames; public Q_SLOTS: diff --git a/kcm/kcm.ui b/kcm/kcm.ui index a1521a1f8..b3e561de8 100644 --- a/kcm/kcm.ui +++ b/kcm/kcm.ui @@ -51,7 +51,6 @@ 12 - 75 true @@ -59,14 +58,14 @@ KDE Connect - Qt::PlainText + Qt::TextFormat::PlainText - Qt::Horizontal + Qt::Orientation::Horizontal @@ -82,8 +81,7 @@ Edit - - .. + @@ -104,15 +102,24 @@ Save - - .. + - + + + + 0 + 0 + + + + QQuickWidget::ResizeMode::SizeRootObjectToView + + @@ -152,7 +159,7 @@ - QLayout::SetMaximumSize + QLayout::SizeConstraint::SetMaximumSize @@ -185,7 +192,6 @@ 10 - 75 true @@ -193,7 +199,7 @@ Device - Qt::PlainText + Qt::TextFormat::PlainText @@ -213,7 +219,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -229,10 +235,10 @@ - 🔑 abababab + KSqueezedTextLabel - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse @@ -241,7 +247,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -340,7 +346,7 @@ - + @@ -351,7 +357,7 @@ - Qt::WheelFocus + Qt::FocusPolicy::WheelFocus @@ -373,10 +379,10 @@ <html><head/><body><p>No device selected.<br><br>If you own an Android device, make sure to install the <a href="https://play.google.com/store/apps/details?id=org.kde.kdeconnect_tp"><span style=" text-decoration: underline;">KDE Connect Android app</span></a> (also available <a href="https://f-droid.org/repository/browse/?fdid=org.kde.kdeconnect_tp"><span style=" text-decoration: underline;">from F-Droid</span></a>) and it should appear in the list. If you have an iPhone, make sure to install the <a href="https://apps.apple.com/us/app/kde-connect/id1580245991"><span style=" text-decoration: underline;">KDE Connect iOS app</span></a> <br><br>If you are having problems, visit the <a href="https://userbase.kde.org/KDEConnect"><span style=" text-decoration: underline;">KDE Connect Community wiki</span></a> for help.</p></body></html> - Qt::RichText + Qt::TextFormat::RichText - Qt::AlignCenter + Qt::AlignmentFlag::AlignCenter true @@ -388,7 +394,7 @@ true - Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse + Qt::TextInteractionFlag::LinksAccessibleByKeyboard|Qt::TextInteractionFlag::LinksAccessibleByMouse @@ -401,12 +407,6 @@ - - KPluginWidget - QWidget -
kpluginwidget.h
- 1 -
KMessageWidget QFrame @@ -418,6 +418,17 @@ QLabel
ksqueezedtextlabel.h
+ + QQuickWidget + QWidget +
QtQuickWidgets/QQuickWidget
+
+ + KPluginWidget + QWidget +
kpluginwidget.h
+ 1 +
diff --git a/kcm/list.qml b/kcm/list.qml new file mode 100644 index 000000000..41f16e657 --- /dev/null +++ b/kcm/list.qml @@ -0,0 +1,81 @@ +/* + * SPDX-FileCopyrightText: 2016 Aleix Pol Gonzalez + * + * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL + */ + +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import org.kde.kirigami as Kirigami +import org.kde.kdeconnect + +ScrollView { + id: root + + focus: true + + signal clicked(string device) + + property string currentDeviceId + + property alias model: devices.model + + Component.onCompleted: { + if (background) { + background.visible = true + } + } + + ListView { + id: devices + + focus: true + + section { + property: "status" + delegate: Kirigami.ListSectionHeader { + + width: ListView.view.width + + text: switch (parseInt(section)) + { + case DevicesModel.Paired: + return i18nd("kdeconnect-kcm", "Remembered") + case DevicesModel.Reachable: + return i18nd("kdeconnect-kcm", "Available") + case (DevicesModel.Reachable | DevicesModel.Paired): + return i18nd("kdeconnect-kcm", "Connected") + } + } + } + Kirigami.PlaceholderMessage { + text: i18nd("kdeconnect-kcm", "No devices found") + icon.name: 'edit-none-symbolic' + anchors.centerIn: parent + width: parent.width - (Kirigami.Units.largeSpacing * 4) + visible: devices.count === 0 + } + + delegate: ItemDelegate { + id: delegate + icon.name: iconName + text: model.name + width: ListView.view.width + highlighted: root.currentDeviceId === deviceId + + focus: true + + contentItem: Kirigami.IconTitleSubtitle { + title: delegate.text + subtitle: toolTip + icon: icon.fromControlsIcon(delegate.icon) + } + + onClicked: { + root.currentDeviceId = deviceId + root.clicked(deviceId) + } + } + } +}