diff --git a/CMakeLists.txt b/CMakeLists.txt index 043b3092..50fdf41c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,7 @@ include(ECMQtDeclareLoggingCategory) include(ECMGenerateExportHeader) include(KDEInstallDirs) include(KDEGitCommitHooks) +include(ECMFindQmlModule) include(KDECMakeSettings) include(KDECompilerSettings NO_POLICY_SCOPE) include(ECMAddAppIcon) @@ -68,6 +69,8 @@ add_definitions(-DQT_NO_CAST_FROM_ASCII ki18n_install(po) +ecm_find_qmlmodule(org.kde.kirigamiaddons.labs.mobileform 0.1) + install(PROGRAMS org.kde.kasts.desktop DESTINATION ${KDE_INSTALL_APPDIR}) install(FILES org.kde.kasts.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR}) install(FILES kasts.svg DESTINATION ${KDE_INSTALL_FULL_ICONDIR}/hicolor/scalable/apps) diff --git a/src/qml/Settings/AboutPage.qml b/src/qml/Settings/AboutPage.qml index 8f527756..c9bd9f05 100644 --- a/src/qml/Settings/AboutPage.qml +++ b/src/qml/Settings/AboutPage.qml @@ -9,10 +9,11 @@ import QtQuick.Controls 2.14 as Controls import QtQuick.Layouts 1.14 import org.kde.kirigami 2.12 as Kirigami +import org.kde.kirigamiaddons.labs.mobileform 0.1 as MobileForm import org.kde.kasts 1.0 -Kirigami.AboutPage { +MobileForm.AboutPage { title: i18n("About") aboutData: About } diff --git a/src/qml/Settings/GeneralSettingsPage.qml b/src/qml/Settings/GeneralSettingsPage.qml index ed5b95e9..cb552a24 100644 --- a/src/qml/Settings/GeneralSettingsPage.qml +++ b/src/qml/Settings/GeneralSettingsPage.qml @@ -10,192 +10,284 @@ import QtQuick.Controls 2.15 as Controls import QtQuick.Layouts 1.14 import org.kde.kirigami 2.12 as Kirigami +import org.kde.kirigamiaddons.labs.mobileform 0.1 as MobileForm import org.kde.kasts 1.0 Kirigami.ScrollablePage { + id: page title: i18n("General Settings") - Kirigami.FormLayout { + leftPadding: 0 + rightPadding: 0 + topPadding: Kirigami.Units.gridUnit + bottomPadding: Kirigami.Units.gridUnit - Kirigami.Heading { - Kirigami.FormData.isSection: true - text: i18n("Appearance") - } + Kirigami.Theme.colorSet: Kirigami.Theme.Window + Kirigami.Theme.inherit: false - Controls.CheckBox { - id: alwaysShowFeedTitles - checked: SettingsManager.alwaysShowFeedTitles - text: i18n("Always show podcast titles in subscription view") - onToggled: SettingsManager.alwaysShowFeedTitles = checked - } + ColumnLayout { + spacing: 0 + width: page.width - Kirigami.Heading { - Kirigami.FormData.isSection: true - text: i18n("Play Settings") - } + MobileForm.FormCard { + Layout.fillWidth: true - Controls.CheckBox { - id: showTimeLeft - Kirigami.FormData.label: i18nc("Label for settings related to the play time, e.g. whether the total track time is shown or a countdown of the remaining play time", "Play Time:") - checked: SettingsManager.toggleRemainingTime - text: i18n("Show time left instead of total track time") - onToggled: SettingsManager.toggleRemainingTime = checked - } - Controls.CheckBox { - id: adjustTimeLeft - checked: SettingsManager.adjustTimeLeft - enabled: SettingsManager.toggleRemainingTime - text: i18n("Adjust time left based on current playback speed") - onToggled: SettingsManager.adjustTimeLeft = checked - } - Controls.CheckBox { - id: prioritizeStreaming - Kirigami.FormData.label: i18nc("Label for settings related to streaming of episodes (as opposed to playing back locally downloaded files)", "Streaming:") - checked: SettingsManager.prioritizeStreaming - text: i18n("Prioritize streaming over downloading") - onToggled: SettingsManager.prioritizeStreaming = checked - } + contentItem: ColumnLayout { + spacing: 0 - Kirigami.Heading { - Kirigami.FormData.isSection: true - text: i18n("Queue Settings") - } + MobileForm.FormCardHeader { + title: i18n("Appearance") + } - Controls.CheckBox { - id: continuePlayingNextEntry - checked: SettingsManager.continuePlayingNextEntry - text: i18n("Continue playing next episode after current one finishes") - onToggled: SettingsManager.continuePlayingNextEntry = checked - } - Controls.CheckBox { - id: refreshOnStartup - Kirigami.FormData.label: i18nc("Label for settings related to podcast updates", "Update Settings:") - checked: SettingsManager.refreshOnStartup - text: i18n("Automatically fetch podcast updates on startup") - onToggled: SettingsManager.refreshOnStartup = checked - } - Controls.CheckBox { - id: doFullUpdate - checked: SettingsManager.doFullUpdate - text: i18n("Update existing episode data on refresh (slower)") - onToggled: SettingsManager.doFullUpdate = checked - } - - Controls.CheckBox { - id: autoQueue - Kirigami.FormData.label: i18n("New Episodes:") - checked: SettingsManager.autoQueue - text: i18n("Automatically Queue") - - onToggled: { - SettingsManager.autoQueue = checked - if (!checked) { - autoDownload.checked = false - SettingsManager.autoDownload = false + MobileForm.FormCheckDelegate { + id: alwaysShowFeedTitles + text: i18n("Always show podcast titles in subscription view") + onToggled: SettingsManager.alwaysShowFeedTitles = checked } } } - Controls.CheckBox { - id: autoDownload - checked: SettingsManager.autoDownload - text: i18n("Automatically Download") + MobileForm.FormCard { + Layout.fillWidth: true + Layout.topMargin: Kirigami.Units.largeSpacing - enabled: autoQueue.checked - onToggled: SettingsManager.autoDownload = checked - } + contentItem: ColumnLayout { + spacing: 0 - Controls.ComboBox { - Kirigami.FormData.label: i18n("Played Episodes:") - Layout.alignment: Qt.AlignHCenter - textRole: "text" - valueRole: "value" - model: [{"text": i18n("Do Not Delete"), "value": 0}, - {"text": i18n("Delete Immediately"), "value": 1}, - {"text": i18n("Delete at Next Startup"), "value": 2}] - Component.onCompleted: currentIndex = indexOfValue(SettingsManager.autoDeleteOnPlayed) - onActivated: { - SettingsManager.autoDeleteOnPlayed = currentValue; + MobileForm.FormCardHeader { + title: i18n("Playback settings") + } + + MobileForm.FormCheckDelegate { + id: showTimeLeft + Kirigami.FormData.label: i18nc("Label for settings related to the play time, e.g. whether the total track time is shown or a countdown of the remaining play time", "Play Time:") + checked: SettingsManager.toggleRemainingTime + text: i18n("Show time left instead of total track time") + onToggled: SettingsManager.toggleRemainingTime = checked + } + MobileForm.FormCheckDelegate { + id: adjustTimeLeft + checked: SettingsManager.adjustTimeLeft + enabled: SettingsManager.toggleRemainingTime + text: i18n("Adjust time left based on current playback speed") + onToggled: SettingsManager.adjustTimeLeft = checked + } + MobileForm.FormCheckDelegate { + id: prioritizeStreaming + checked: SettingsManager.prioritizeStreaming + text: i18n("Prioritize streaming over downloading") + onToggled: SettingsManager.prioritizeStreaming = checked + } } } - Controls.CheckBox { - checked: SettingsManager.resetPositionOnPlayed - text: i18n("Reset Play Position") - onToggled: SettingsManager.resetPositionOnPlayed = checked - } + MobileForm.FormCard { + Layout.fillWidth: true + Layout.topMargin: Kirigami.Units.largeSpacing - Controls.RadioButton { - Kirigami.FormData.label: i18n("When adding new podcasts:") - checked: SettingsManager.markUnreadOnNewFeed === 0 - text: i18n("Mark all episodes as played") - onToggled: SettingsManager.markUnreadOnNewFeed = 0 - } + contentItem: ColumnLayout { + spacing: 0 - RowLayout { - Controls.RadioButton { - id: markCustomUnreadNumberButton - checked: SettingsManager.markUnreadOnNewFeed === 1 - text: i18n("Mark most recent episodes as unplayed:") - onToggled: SettingsManager.markUnreadOnNewFeed = 1 - } + MobileForm.FormCardHeader { + title: i18n("Queue settings") + } - Controls.SpinBox { - id: markCustomUnreadNumberSpinBox - enabled: markCustomUnreadNumberButton.checked - value: SettingsManager.markUnreadOnNewFeedCustomAmount - from: 0 - to: 100 + MobileForm.FormCheckDelegate { + id: continuePlayingNextEntry + checked: SettingsManager.continuePlayingNextEntry + text: i18n("Continue playing next episode after current one finishes") + onToggled: SettingsManager.continuePlayingNextEntry = checked + } + MobileForm.FormCheckDelegate { + id: refreshOnStartup + Kirigami.FormData.label: i18nc("Label for settings related to podcast updates", "Update Settings:") + checked: SettingsManager.refreshOnStartup + text: i18n("Automatically fetch podcast updates on startup") + onToggled: SettingsManager.refreshOnStartup = checked + } + MobileForm.FormCheckDelegate { + id: doFullUpdate + checked: SettingsManager.doFullUpdate + text: i18n("Update existing episode data on refresh (slower)") + onToggled: SettingsManager.doFullUpdate = checked + } - onValueModified: SettingsManager.markUnreadOnNewFeedCustomAmount = value + MobileForm.FormCheckDelegate { + id: autoQueue + checked: SettingsManager.autoQueue + text: i18n("Automatically queue new episodes") + + onToggled: { + SettingsManager.autoQueue = checked + if (!checked) { + autoDownload.checked = false + SettingsManager.autoDownload = false + } + } + } + + MobileForm.FormCheckDelegate { + id: autoDownload + checked: SettingsManager.autoDownload + text: i18n("Automatically download new episodes") + + enabled: autoQueue.checked + onToggled: SettingsManager.autoDownload = checked + } + + MobileForm.FormDelegateSeparator { above: autoDownload; below: episodeBehavior } + + MobileForm.FormComboBoxDelegate { + id: episodeBehavior + text: i18n("Played episode behavior") + textRole: "text" + valueRole: "value" + model: [{"text": i18n("Do Not Delete"), "value": 0}, + {"text": i18n("Delete Immediately"), "value": 1}, + {"text": i18n("Delete at Next Startup"), "value": 2}] + Component.onCompleted: currentIndex = indexOfValue(SettingsManager.autoDeleteOnPlayed) + onActivated: { + SettingsManager.autoDeleteOnPlayed = currentValue; + } + } + + MobileForm.FormDelegateSeparator { above: episodeBehavior; below: resetPositionOnPlayed } + + MobileForm.FormCheckDelegate { + id: resetPositionOnPlayed + checked: SettingsManager.resetPositionOnPlayed + text: i18n("Reset play position after an episode is played") + onToggled: SettingsManager.resetPositionOnPlayed = checked + } } } - Controls.RadioButton { - checked: SettingsManager.markUnreadOnNewFeed === 2 - text: i18n("Mark all episodes as unplayed") - onToggled: SettingsManager.markUnreadOnNewFeed = 2 + MobileForm.FormCard { + Layout.fillWidth: true + Layout.topMargin: Kirigami.Units.largeSpacing + + contentItem: ColumnLayout { + spacing: 0 + + MobileForm.FormCardHeader { + title: i18n("When adding new podcasts") + } + + MobileForm.FormRadioDelegate { + checked: SettingsManager.markUnreadOnNewFeed === 0 + text: i18n("Mark all episodes as played") + onToggled: SettingsManager.markUnreadOnNewFeed = 0 + } + + + RowLayout { + Layout.fillWidth: true + MobileForm.FormRadioDelegate { + id: markCustomUnreadNumberButton + checked: SettingsManager.markUnreadOnNewFeed === 1 + text: i18n("Mark most recent episodes as unplayed") + onToggled: SettingsManager.markUnreadOnNewFeed = 1 + } + + Controls.SpinBox { + Layout.rightMargin: Kirigami.Units.gridUnit + id: markCustomUnreadNumberSpinBox + enabled: markCustomUnreadNumberButton.checked + value: SettingsManager.markUnreadOnNewFeedCustomAmount + from: 0 + to: 100 + + onValueModified: SettingsManager.markUnreadOnNewFeedCustomAmount = value + } + } + + MobileForm.FormRadioDelegate { + checked: SettingsManager.markUnreadOnNewFeed === 2 + text: i18n("Mark all episodes as unplayed") + onToggled: SettingsManager.markUnreadOnNewFeed = 2 + } + } } - Kirigami.Heading { - Kirigami.FormData.isSection: true - text: i18n("Article") + MobileForm.FormCard { + Layout.fillWidth: true + Layout.topMargin: Kirigami.Units.largeSpacing + + contentItem: ColumnLayout { + spacing: 0 + + MobileForm.FormCardHeader { + title: i18n("Article") + } + + MobileForm.AbstractFormDelegate { + id: fontSize + background: Item {} + + contentItem: RowLayout { + Controls.Label { + Layout.fillWidth: true + text: i18n("Font size") + } + + Controls.SpinBox { + id: articleFontSizeSpinBox + + enabled: !useSystemFontCheckBox.checked + value: SettingsManager.articleFontSize + Kirigami.FormData.label: i18n("Font size:") + from: 6 + to: 20 + + onValueModified: SettingsManager.articleFontSize = value + } + } + } + + MobileForm.FormDelegateSeparator { above: fontSize; below: useSystemFontCheckBox } + + MobileForm.FormCheckDelegate { + id: useSystemFontCheckBox + checked: SettingsManager.articleFontUseSystem + text: i18n("Use system default") + + onToggled: SettingsManager.articleFontUseSystem = checked + } + } } - Controls.SpinBox { - id: articleFontSizeSpinBox + MobileForm.FormCard { + Layout.fillWidth: true + Layout.topMargin: Kirigami.Units.largeSpacing - enabled: !useSystemFontCheckBox.checked - value: SettingsManager.articleFontSize - Kirigami.FormData.label: i18n("Font size:") - from: 6 - to: 20 + contentItem: ColumnLayout { + spacing: 0 - onValueModified: SettingsManager.articleFontSize = value - } + MobileForm.FormCardHeader { + title: i18n("Errors") + } - Controls.CheckBox { - id: useSystemFontCheckBox - checked: SettingsManager.articleFontUseSystem - text: i18n("Use system default") + MobileForm.AbstractFormDelegate { + background: Item {} + contentItem: RowLayout { + Controls.Label { + Layout.fillWidth: true + text: i18n("Error log") + } - onToggled: SettingsManager.articleFontUseSystem = checked - } + Controls.Button { + icon.name: "error" + text: i18n("Open Log") + onClicked: settingsErrorOverlay.open() + } + } + } - Kirigami.Heading { - Kirigami.FormData.isSection: true - text: i18n("Errors") - } - - Controls.Button { - icon.name: "error" - text: i18n("Show Error Log") - onClicked: settingsErrorOverlay.open() - } - - ErrorListOverlay { - id: settingsErrorOverlay + ErrorListOverlay { + id: settingsErrorOverlay + } + } } } } diff --git a/src/qml/Settings/NetworkSettingsPage.qml b/src/qml/Settings/NetworkSettingsPage.qml index 490d5d0e..da06401b 100644 --- a/src/qml/Settings/NetworkSettingsPage.qml +++ b/src/qml/Settings/NetworkSettingsPage.qml @@ -10,40 +10,64 @@ import QtQuick.Controls 2.14 as Controls import QtQuick.Layouts 1.14 import org.kde.kirigami 2.12 as Kirigami +import org.kde.kirigamiaddons.labs.mobileform 0.1 as MobileForm import org.kde.kasts 1.0 Kirigami.ScrollablePage { + id: page title: i18n("Network Settings") - Kirigami.FormLayout { - Controls.CheckBox { - id: allowMeteredFeedUpdates - checked: SettingsManager.allowMeteredFeedUpdates - Kirigami.FormData.label: i18n("On metered connections:") - text: i18n("Allow podcast updates") - onToggled: SettingsManager.allowMeteredFeedUpdates = checked - } + leftPadding: 0 + rightPadding: 0 + topPadding: Kirigami.Units.gridUnit + bottomPadding: Kirigami.Units.gridUnit - Controls.CheckBox { - id: allowMeteredEpisodeDownloads - checked: SettingsManager.allowMeteredEpisodeDownloads - text: i18n("Allow episode downloads") - onToggled: SettingsManager.allowMeteredEpisodeDownloads = checked - } + Kirigami.Theme.colorSet: Kirigami.Theme.Window + Kirigami.Theme.inherit: false - Controls.CheckBox { - id: allowMeteredImageDownloads - checked: SettingsManager.allowMeteredImageDownloads - text: i18n("Allow image downloads") - onToggled: SettingsManager.allowMeteredImageDownloads = checked - } + ColumnLayout { + spacing: 0 + width: page.width - Controls.CheckBox { - id: allowMeteredStreaming - checked: SettingsManager.allowMeteredStreaming - text: i18n("Allow streaming") - onToggled: SettingsManager.allowMeteredStreaming = checked + MobileForm.FormCard { + Layout.fillWidth: true + + contentItem: ColumnLayout { + spacing: 0 + + MobileForm.FormCardHeader { + title: i18n("On metered connections") + } + + MobileForm.FormCheckDelegate { + id: allowMeteredFeedUpdates + checked: SettingsManager.allowMeteredFeedUpdates + text: i18n("Allow podcast updates") + onToggled: SettingsManager.allowMeteredFeedUpdates = checked + } + + MobileForm.FormCheckDelegate { + id: allowMeteredEpisodeDownloads + checked: SettingsManager.allowMeteredEpisodeDownloads + text: i18n("Allow episode downloads") + onToggled: SettingsManager.allowMeteredEpisodeDownloads = checked + } + + MobileForm.FormCheckDelegate { + id: allowMeteredImageDownloads + checked: SettingsManager.allowMeteredImageDownloads + text: i18n("Allow image downloads") + onToggled: SettingsManager.allowMeteredImageDownloads = checked + } + + MobileForm.FormCheckDelegate { + id: allowMeteredStreaming + checked: SettingsManager.allowMeteredStreaming + text: i18n("Allow streaming") + onToggled: SettingsManager.allowMeteredStreaming = checked + } + } } } } diff --git a/src/qml/Settings/StorageSettingsPage.qml b/src/qml/Settings/StorageSettingsPage.qml index 5bfc646d..74455cc4 100644 --- a/src/qml/Settings/StorageSettingsPage.qml +++ b/src/qml/Settings/StorageSettingsPage.qml @@ -11,67 +11,137 @@ import QtQuick.Layouts 1.14 import QtQuick.Dialogs 1.3 import org.kde.kirigami 2.12 as Kirigami +import org.kde.kirigamiaddons.labs.mobileform 0.1 as MobileForm import org.kde.kasts 1.0 Kirigami.ScrollablePage { + id: page title: i18n("Storage Settings") - Kirigami.FormLayout { - RowLayout { - visible: Qt.platform.os !== "android" // not functional on android - Kirigami.FormData.label: i18n("Storage path:") + leftPadding: 0 + rightPadding: 0 + topPadding: Kirigami.Units.gridUnit + bottomPadding: Kirigami.Units.gridUnit + Kirigami.Theme.colorSet: Kirigami.Theme.Window + Kirigami.Theme.inherit: false + + ColumnLayout { + spacing: 0 + width: page.width + + MobileForm.FormCard { Layout.fillWidth: true - Controls.TextField { - Layout.fillWidth: true - readOnly: true - text: StorageManager.storagePath - enabled: !defaultStoragePath.checked - } - Controls.Button { - icon.name: "document-open-folder" - text: i18n("Select folder...") - enabled: !defaultStoragePath.checked - onClicked: storagePathDialog.open() - } - FileDialog { - id: storagePathDialog - title: i18n("Select Storage Path") - selectFolder: true - folder: "file://" + StorageManager.storagePath - onAccepted: { - StorageManager.setStoragePath(fileUrl); + + contentItem: ColumnLayout { + spacing: 0 + + MobileForm.FormCardHeader { + title: i18n("Storage path") + } + + MobileForm.AbstractFormDelegate { + id: storagePath + visible: Qt.platform.os !== "android" // not functional on android + background: Item {} + + contentItem: RowLayout { + spacing: 0 + ColumnLayout { + spacing: Kirigami.Units.smallSpacing + Controls.Label { + Layout.fillWidth: true + elide: Text.ElideRight + text: i18n("Storage path") + } + Controls.Label { + Layout.fillWidth: true + elide: Text.ElideRight + color: Kirigami.Theme.disabledTextColor + text: StorageManager.storagePath + } + } + + Controls.Button { + Layout.leftMargin: Kirigami.Units.largeSpacing + icon.name: "document-open-folder" + text: i18n("Select folder...") + enabled: !defaultStoragePath.checked + onClicked: storagePathDialog.open() + } + FileDialog { + id: storagePathDialog + title: i18n("Select Storage Path") + selectFolder: true + folder: "file://" + StorageManager.storagePath + onAccepted: { + StorageManager.setStoragePath(fileUrl); + } + } + } + } + + MobileForm.FormDelegateSeparator { above: storagePath; below: defaultStoragePath } + + MobileForm.FormCheckDelegate { + id: defaultStoragePath + visible: Qt.platform.os !== "android" // not functional on android + checked: SettingsManager.storagePath == "" + text: i18n("Use default path") + onToggled: { + if (checked) { + StorageManager.setStoragePath(""); + } + } } } } - Controls.CheckBox { - id: defaultStoragePath - visible: Qt.platform.os !== "android" // not functional on android - checked: SettingsManager.storagePath == "" - text: i18n("Use default path") - onToggled: { - if (checked) { - StorageManager.setStoragePath(""); + MobileForm.FormCard { + Layout.topMargin: Kirigami.Units.largeSpacing + Layout.fillWidth: true + + contentItem: ColumnLayout { + spacing: 0 + + MobileForm.FormCardHeader { + title: i18n("Information") } - } - } - Controls.Label { - Kirigami.FormData.label: i18n("Podcast Downloads:") - text: i18nc("Using of disk space", "Using %1 of disk space", StorageManager.formattedEnclosureDirSize) - } + MobileForm.FormTextDelegate { + text: i18n("Podcast downloads") + description: i18nc("Using of disk space", "Using %1 of disk space", StorageManager.formattedEnclosureDirSize) + } - RowLayout { - Kirigami.FormData.label: i18n("Image Cache:") - Controls.Label { - text: i18nc("Using of disk space", "Using %1 of disk space", StorageManager.formattedImageDirSize) - } - Controls.Button { - icon.name: "edit-clear-all" - text: i18n("Clear Cache") - onClicked: StorageManager.clearImageCache(); + MobileForm.FormDelegateSeparator {} + + MobileForm.AbstractFormDelegate { + background: Item {} + contentItem: RowLayout { + spacing: Kirigami.Units.largeSpacing + ColumnLayout { + spacing: Kirigami.Units.smallSpacing + Controls.Label { + Layout.fillWidth: true + elide: Text.ElideRight + text: i18n("Image cache") + } + Controls.Label { + Layout.fillWidth: true + elide: Text.ElideRight + color: Kirigami.Theme.disabledTextColor + text: i18nc("Using of disk space", "Using %1 of disk space", StorageManager.formattedImageDirSize) + } + } + + Controls.Button { + icon.name: "edit-clear-all" + text: i18n("Clear Cache") + onClicked: StorageManager.clearImageCache(); + } + } + } } } }