mirror of
https://invent.kde.org/marcoa/shift-shell.git
synced 2026-08-02 09:48:50 +00:00
homescreens/folio: Add import/export homescreen layout setting
This commit is contained in:
parent
df80fb65fc
commit
f1aff0b13e
10 changed files with 163 additions and 18 deletions
|
|
@ -212,12 +212,8 @@ void FavouritesModel::deleteGhostEntry()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FavouritesModel::save()
|
QJsonArray FavouritesModel::exportToJson()
|
||||||
{
|
{
|
||||||
if (!m_applet) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonArray arr;
|
QJsonArray arr;
|
||||||
for (int i = 0; i < m_delegates.size(); i++) {
|
for (int i = 0; i < m_delegates.size(); i++) {
|
||||||
FolioDelegate *delegate = m_delegates[i].delegate;
|
FolioDelegate *delegate = m_delegates[i].delegate;
|
||||||
|
|
@ -229,6 +225,16 @@ void FavouritesModel::save()
|
||||||
|
|
||||||
arr.append(delegate->toJson());
|
arr.append(delegate->toJson());
|
||||||
}
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FavouritesModel::save()
|
||||||
|
{
|
||||||
|
if (!m_applet) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonArray arr = exportToJson();
|
||||||
QByteArray data = QJsonDocument(arr).toJson(QJsonDocument::Compact);
|
QByteArray data = QJsonDocument(arr).toJson(QJsonDocument::Compact);
|
||||||
|
|
||||||
m_applet->config().writeEntry("Favourites", QString::fromStdString(data.toStdString()));
|
m_applet->config().writeEntry("Favourites", QString::fromStdString(data.toStdString()));
|
||||||
|
|
@ -242,12 +248,16 @@ void FavouritesModel::load()
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonDocument doc = QJsonDocument::fromJson(m_applet->config().readEntry("Favourites", "{}").toUtf8());
|
QJsonDocument doc = QJsonDocument::fromJson(m_applet->config().readEntry("Favourites", "{}").toUtf8());
|
||||||
|
loadFromJson(doc.array());
|
||||||
|
}
|
||||||
|
|
||||||
|
void FavouritesModel::loadFromJson(QJsonArray arr)
|
||||||
|
{
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
|
|
||||||
m_delegates.clear();
|
m_delegates.clear();
|
||||||
|
|
||||||
for (QJsonValueRef r : doc.array()) {
|
for (QJsonValueRef r : arr) {
|
||||||
QJsonObject obj = r.toObject();
|
QJsonObject obj = r.toObject();
|
||||||
FolioDelegate *delegate = FolioDelegate::fromJson(obj, this);
|
FolioDelegate *delegate = FolioDelegate::fromJson(obj, this);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,12 +59,14 @@ public:
|
||||||
|
|
||||||
QPointF getDelegateScreenPosition(int position) const;
|
QPointF getDelegateScreenPosition(int position) const;
|
||||||
|
|
||||||
|
QJsonArray exportToJson();
|
||||||
|
void save();
|
||||||
Q_INVOKABLE void load();
|
Q_INVOKABLE void load();
|
||||||
|
void loadFromJson(QJsonArray arr);
|
||||||
|
|
||||||
void setApplet(Plasma::Applet *applet);
|
void setApplet(Plasma::Applet *applet);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void save();
|
|
||||||
void evaluateDelegatePositions(bool emitSignal = true);
|
void evaluateDelegatePositions(bool emitSignal = true);
|
||||||
|
|
||||||
// get the x (or y) position where delegates start being placed
|
// get the x (or y) position where delegates start being placed
|
||||||
|
|
|
||||||
|
|
@ -265,6 +265,9 @@ void ApplicationFolderModel::removeDelegate(int index)
|
||||||
|
|
||||||
QPointF ApplicationFolderModel::getDelegatePosition(int index)
|
QPointF ApplicationFolderModel::getDelegatePosition(int index)
|
||||||
{
|
{
|
||||||
|
if (index < 0 || index >= m_folder->m_delegates.size()) {
|
||||||
|
return {0, 0};
|
||||||
|
}
|
||||||
auto delegate = m_folder->m_delegates[index];
|
auto delegate = m_folder->m_delegates[index];
|
||||||
return {delegate.xPosition, delegate.yPosition};
|
return {delegate.xPosition, delegate.yPosition};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,13 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include "foliosettings.h"
|
#include "foliosettings.h"
|
||||||
|
#include "favouritesmodel.h"
|
||||||
|
#include "pagelistmodel.h"
|
||||||
|
|
||||||
|
#include <QFile>
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QTextStream>
|
||||||
|
|
||||||
FolioSettings::FolioSettings(QObject *parent)
|
FolioSettings::FolioSettings(QObject *parent)
|
||||||
: QObject{parent}
|
: QObject{parent}
|
||||||
|
|
@ -139,3 +146,56 @@ void FolioSettings::load()
|
||||||
Q_EMIT showFavouritesAppLabelsChanged();
|
Q_EMIT showFavouritesAppLabelsChanged();
|
||||||
Q_EMIT delegateIconSizeChanged();
|
Q_EMIT delegateIconSizeChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FolioSettings::saveLayoutToFile(QString path)
|
||||||
|
{
|
||||||
|
if (path.startsWith(QStringLiteral("file://"))) {
|
||||||
|
path = path.replace(QStringLiteral("file://"), QString());
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonArray favourites = FavouritesModel::self()->exportToJson();
|
||||||
|
QJsonArray pages = PageListModel::self()->exportToJson();
|
||||||
|
|
||||||
|
QJsonObject obj;
|
||||||
|
obj[QStringLiteral("Favourites")] = favourites;
|
||||||
|
obj[QStringLiteral("Pages")] = pages;
|
||||||
|
|
||||||
|
QByteArray data = QJsonDocument(obj).toJson(QJsonDocument::Compact);
|
||||||
|
|
||||||
|
QFile file{path};
|
||||||
|
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||||
|
file.write(data);
|
||||||
|
} else {
|
||||||
|
qDebug() << "failed to write to file:" << file.errorString();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FolioSettings::loadLayoutFromFile(QString path)
|
||||||
|
{
|
||||||
|
if (path.startsWith(QStringLiteral("file://"))) {
|
||||||
|
path = path.replace(QStringLiteral("file://"), QString());
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile file(path);
|
||||||
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
|
qDebug() << "failed to open file:" << file.errorString();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QTextStream in(&file);
|
||||||
|
QString contents = in.readAll();
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
QJsonDocument doc = QJsonDocument::fromJson(contents.toUtf8());
|
||||||
|
QJsonObject obj = doc.object();
|
||||||
|
|
||||||
|
// TODO error checking
|
||||||
|
FavouritesModel::self()->loadFromJson(obj[QStringLiteral("Favourites")].toArray());
|
||||||
|
PageListModel::self()->loadFromJson(obj[QStringLiteral("Pages")].toArray());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,9 @@ public:
|
||||||
|
|
||||||
Q_INVOKABLE void load();
|
Q_INVOKABLE void load();
|
||||||
|
|
||||||
|
Q_INVOKABLE bool saveLayoutToFile(QString path);
|
||||||
|
Q_INVOKABLE bool loadLayoutFromFile(QString path);
|
||||||
|
|
||||||
Q_INVOKABLE void setApplet(Plasma::Applet *applet);
|
Q_INVOKABLE void setApplet(Plasma::Applet *applet);
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
|
|
|
||||||
|
|
@ -644,7 +644,7 @@ QPointF HomeScreenState::getFavouritesDelegateScreenPosition(int position)
|
||||||
|
|
||||||
QPointF HomeScreenState::getFolderDelegateScreenPosition(int position)
|
QPointF HomeScreenState::getFolderDelegateScreenPosition(int position)
|
||||||
{
|
{
|
||||||
if (!m_currentFolder) {
|
if (!m_currentFolder || position < 0 || position >= m_currentFolder->applications()->rowCount()) {
|
||||||
return {0, 0};
|
return {0, 0};
|
||||||
}
|
}
|
||||||
auto pos = m_currentFolder->applications()->getDelegatePosition(position);
|
auto pos = m_currentFolder->applications()->getDelegatePosition(position);
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ MobileShell.GridView {
|
||||||
cellWidth: effectiveContentWidth / Math.min(Math.floor(effectiveContentWidth / (Folio.FolioSettings.delegateIconSize + Kirigami.Units.largeSpacing * 3)), 8)
|
cellWidth: effectiveContentWidth / Math.min(Math.floor(effectiveContentWidth / (Folio.FolioSettings.delegateIconSize + Kirigami.Units.largeSpacing * 3)), 8)
|
||||||
cellHeight: cellWidth + reservedSpaceForLabel
|
cellHeight: cellWidth + reservedSpaceForLabel
|
||||||
|
|
||||||
boundsBehavior: Flickable.OvershootBounds
|
boundsBehavior: Flickable.StopAtBounds
|
||||||
|
|
||||||
readonly property int columns: Math.floor(effectiveContentWidth / cellWidth)
|
readonly property int columns: Math.floor(effectiveContentWidth / cellWidth)
|
||||||
readonly property int rows: Math.ceil(root.count / columns)
|
readonly property int rows: Math.ceil(root.count / columns)
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Window
|
import QtQuick.Window
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
import QtQuick.Dialogs
|
||||||
import QtQuick.Controls as QQC2
|
import QtQuick.Controls as QQC2
|
||||||
|
|
||||||
import org.kde.kirigami 2.20 as Kirigami
|
import org.kde.kirigami 2.20 as Kirigami
|
||||||
|
|
@ -178,6 +179,7 @@ Kirigami.ApplicationWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
FormCard.FormCard {
|
FormCard.FormCard {
|
||||||
|
Layout.bottomMargin: Kirigami.Units.gridUnit
|
||||||
FormCard.FormButtonDelegate {
|
FormCard.FormButtonDelegate {
|
||||||
id: containmentSettings
|
id: containmentSettings
|
||||||
text: i18n('Switch Homescreen')
|
text: i18n('Switch Homescreen')
|
||||||
|
|
@ -189,20 +191,73 @@ Kirigami.ApplicationWindow {
|
||||||
|
|
||||||
FormCard.FormButtonDelegate {
|
FormCard.FormButtonDelegate {
|
||||||
id: exportSettings
|
id: exportSettings
|
||||||
enabled: false
|
text: i18n('Export layout')
|
||||||
text: 'Export layout (in development)'
|
|
||||||
icon.name: 'document-export'
|
icon.name: 'document-export'
|
||||||
|
onClicked: exportFileDialog.open()
|
||||||
}
|
}
|
||||||
|
|
||||||
FormCard.FormDelegateSeparator { above: exportSettings; below: importSettings }
|
FormCard.FormDelegateSeparator { above: exportSettings; below: importSettings }
|
||||||
|
|
||||||
FormCard.FormButtonDelegate {
|
FormCard.FormButtonDelegate {
|
||||||
id: importSettings
|
id: importSettings
|
||||||
enabled: false
|
text: i18n('Import layout')
|
||||||
text: 'Import layout (in development)'
|
|
||||||
icon.name: 'document-import'
|
icon.name: 'document-import'
|
||||||
|
onClicked: importFileDialog.open()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FileDialog {
|
||||||
|
id: exportFileDialog
|
||||||
|
title: i18n("Export layout to")
|
||||||
|
currentFolder: StandardPaths.standardLocations(StandardPaths.DownloadsLocation)
|
||||||
|
fileMode: FileDialog.SaveFile
|
||||||
|
defaultSuffix: 'json'
|
||||||
|
nameFilters: ["JSON files (*.json)"]
|
||||||
|
onAccepted: {
|
||||||
|
console.log('saving layout to ' + selectedFile);
|
||||||
|
if (selectedFile) {
|
||||||
|
let status = Folio.FolioSettings.saveLayoutToFile(selectedFile);
|
||||||
|
if (status) {
|
||||||
|
exportedSuccessfullyPrompt.open();
|
||||||
|
} else {
|
||||||
|
exportFailedPrompt.open();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FileDialog {
|
||||||
|
id: importFileDialog
|
||||||
|
currentFolder: StandardPaths.standardLocations(StandardPaths.DownloadsLocation)
|
||||||
|
fileMode: FileDialog.OpenFile
|
||||||
|
nameFilters: ["JSON files (*.json)"]
|
||||||
|
onAccepted: {
|
||||||
|
console.log('about to load layout from ' + selectedFile);
|
||||||
|
confirmImportPrompt.open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Kirigami.PromptDialog {
|
||||||
|
id: exportFailedPrompt
|
||||||
|
title: i18n("Export Status")
|
||||||
|
subtitle: i18n("Failed to export to %1", String(exportFileDialog.selectedFile).substring('file://'.length))
|
||||||
|
standardButtons: Kirigami.Dialog.Close
|
||||||
|
}
|
||||||
|
|
||||||
|
Kirigami.PromptDialog {
|
||||||
|
id: exportedSuccessfullyPrompt
|
||||||
|
title: i18n("Export Status")
|
||||||
|
subtitle: i18n("Homescreen layout exported successfully to %1", String(exportFileDialog.selectedFile).substring('file://'.length))
|
||||||
|
standardButtons: Kirigami.Dialog.Close
|
||||||
|
}
|
||||||
|
|
||||||
|
Kirigami.PromptDialog {
|
||||||
|
id: confirmImportPrompt
|
||||||
|
title: i18n("Confirm Import")
|
||||||
|
subtitle: i18n("This will overwrite your existing homescreen layout!")
|
||||||
|
standardButtons: Kirigami.Dialog.Ok | Kirigami.Dialog.Cancel
|
||||||
|
onAccepted: Folio.FolioSettings.loadLayoutFromFile(importFileDialog.selectedFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -94,16 +94,22 @@ bool PageListModel::isLastPageEmpty()
|
||||||
return m_pages.size() == 0 ? true : m_pages[m_pages.size() - 1]->isPageEmpty();
|
return m_pages.size() == 0 ? true : m_pages[m_pages.size() - 1]->isPageEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QJsonArray PageListModel::exportToJson()
|
||||||
|
{
|
||||||
|
QJsonArray arr;
|
||||||
|
for (auto &page : m_pages) {
|
||||||
|
arr.push_back(page->toJson());
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
void PageListModel::save()
|
void PageListModel::save()
|
||||||
{
|
{
|
||||||
if (!m_applet) {
|
if (!m_applet) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonArray arr;
|
QJsonArray arr = exportToJson();
|
||||||
for (auto &page : m_pages) {
|
|
||||||
arr.push_back(page->toJson());
|
|
||||||
}
|
|
||||||
QByteArray data = QJsonDocument(arr).toJson(QJsonDocument::Compact);
|
QByteArray data = QJsonDocument(arr).toJson(QJsonDocument::Compact);
|
||||||
|
|
||||||
m_applet->config().writeEntry("Pages", QString::fromStdString(data.toStdString()));
|
m_applet->config().writeEntry("Pages", QString::fromStdString(data.toStdString()));
|
||||||
|
|
@ -117,12 +123,16 @@ void PageListModel::load()
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonDocument doc = QJsonDocument::fromJson(m_applet->config().readEntry("Pages", "{}").toUtf8());
|
QJsonDocument doc = QJsonDocument::fromJson(m_applet->config().readEntry("Pages", "{}").toUtf8());
|
||||||
|
loadFromJson(doc.array());
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageListModel::loadFromJson(QJsonArray arr)
|
||||||
|
{
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
|
|
||||||
m_pages.clear();
|
m_pages.clear();
|
||||||
|
|
||||||
for (QJsonValueRef r : doc.array()) {
|
for (QJsonValueRef r : arr) {
|
||||||
QJsonArray obj = r.toArray();
|
QJsonArray obj = r.toArray();
|
||||||
|
|
||||||
PageModel *page = PageModel::fromJson(obj, this);
|
PageModel *page = PageModel::fromJson(obj, this);
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,10 @@ public:
|
||||||
Q_INVOKABLE void addPageAtEnd();
|
Q_INVOKABLE void addPageAtEnd();
|
||||||
bool isLastPageEmpty();
|
bool isLastPageEmpty();
|
||||||
|
|
||||||
|
QJsonArray exportToJson();
|
||||||
void save();
|
void save();
|
||||||
Q_INVOKABLE void load();
|
Q_INVOKABLE void load();
|
||||||
|
void loadFromJson(QJsonArray arr);
|
||||||
|
|
||||||
void setApplet(Plasma::Applet *applet);
|
void setApplet(Plasma::Applet *applet);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue