noctalia
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
import Quickshell
|
||||
import qs.Commons
|
||||
import qs.Services.UI
|
||||
import qs.Widgets
|
||||
|
||||
NIconButton {
|
||||
id: root
|
||||
|
||||
property var cfg: pluginApi?.pluginSettings || ({})
|
||||
property var defaults: pluginApi?.manifest?.metadata?.defaultSettings || ({})
|
||||
readonly property string iconColorKey: cfg.iconColor ?? defaults.iconColor ?? "none"
|
||||
property var pluginApi: null
|
||||
property ShellScreen screen
|
||||
property string section: ""
|
||||
property int sectionWidgetIndex: -1
|
||||
property int sectionWidgetsCount: 0
|
||||
property string widgetId: ""
|
||||
|
||||
baseSize: Style.getCapsuleHeightForScreen(screen?.name)
|
||||
border.color: Style.capsuleBorderColor
|
||||
border.width: Style.capsuleBorderWidth
|
||||
colorBg: Style.capsuleColor
|
||||
colorFg: Color.resolveColorKey(iconColorKey)
|
||||
customRadius: Style.radiusL
|
||||
icon: "cards"
|
||||
tooltipDirection: BarService.getTooltipDirection(screen?.name)
|
||||
tooltipText: pluginApi?.tr("widget.tooltip")
|
||||
|
||||
onClicked: {
|
||||
if (pluginApi) {
|
||||
root.pluginApi?.mainInstance.toggle();
|
||||
}
|
||||
}
|
||||
onRightClicked: {
|
||||
PanelService.showContextMenu(contextMenu, root, screen);
|
||||
}
|
||||
|
||||
NPopupContextMenu {
|
||||
id: contextMenu
|
||||
|
||||
model: [
|
||||
{
|
||||
"label": I18n.tr("actions.widget-settings"),
|
||||
"action": "widget-settings",
|
||||
"icon": "settings"
|
||||
},
|
||||
]
|
||||
|
||||
onTriggered: action => {
|
||||
contextMenu.close();
|
||||
PanelService.closeContextMenu(screen);
|
||||
|
||||
if (action === "widget-settings") {
|
||||
BarService.openPluginSettings(screen, pluginApi.manifest);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
import QtQuick
|
||||
import Quickshell.Io
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property var pluginApi: null
|
||||
|
||||
function hide() {
|
||||
if (windowLoader.item)
|
||||
windowLoader.item.close();
|
||||
else
|
||||
windowLoader.active = false;
|
||||
}
|
||||
function show() {
|
||||
windowLoader.active = true;
|
||||
}
|
||||
function toggle() {
|
||||
if (windowLoader.active)
|
||||
hide();
|
||||
else
|
||||
show();
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: windowLoader
|
||||
|
||||
active: false
|
||||
source: "Wallcards.qml"
|
||||
|
||||
onLoaded: item.pluginApi = Qt.binding(() => root.pluginApi)
|
||||
|
||||
Connections {
|
||||
function onQuitRequested() {
|
||||
windowLoader.active = false;
|
||||
}
|
||||
|
||||
target: windowLoader.item
|
||||
}
|
||||
}
|
||||
IpcHandler {
|
||||
function hide() {
|
||||
root.hide();
|
||||
}
|
||||
function show() {
|
||||
root.show();
|
||||
}
|
||||
function toggle() {
|
||||
root.toggle();
|
||||
}
|
||||
|
||||
target: "plugin:wallcards"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
# Wallcards
|
||||
|
||||
A `lively` wallpaper selector for images and videos with live preview.
|
||||
|
||||
> [!NOTE]
|
||||
> Heavily inspired by other work — see Credits for details.
|
||||
|
||||
https://github.com/user-attachments/assets/9ffbc83d-95e5-4dcd-a834-7bd224211b55
|
||||
|
||||
## Features
|
||||
|
||||
- Browse image and video wallpapers as a scrollable card stack
|
||||
- Live preview — applies the wallpaper and updates the colorscheme as you navigate
|
||||
- Filter by type or by dominant color
|
||||
- Keyboard and partial mouse navigation
|
||||
- Full settings panel with layout and behavior options
|
||||
|
||||
## Dependencies
|
||||
|
||||
```sh
|
||||
pacman -S ffmpeg mpvpaper imagemagick
|
||||
```
|
||||
|
||||
## IPC Commands
|
||||
|
||||
Control the plugin from the command line:
|
||||
|
||||
```sh
|
||||
qs -c noctalia-shell ipc call plugin:wallcards toggle
|
||||
```
|
||||
|
||||
## Keybinding Examples
|
||||
|
||||
Add to your compositor configuration:
|
||||
|
||||
### Hyprland
|
||||
|
||||
```conf
|
||||
bind = SUPER, A, exec, qs -c noctalia-shell ipc call plugin:wallcards toggle
|
||||
```
|
||||
|
||||
### Keybinds
|
||||
|
||||
#### Navigation
|
||||
|
||||
| Key | Action |
|
||||
| --- | --- |
|
||||
| `J` / `←` | Previous wallpaper |
|
||||
| `K` / `→` | Next wallpaper |
|
||||
| `H` | Scroll page back |
|
||||
| `L` | Scroll page forward |
|
||||
| `R` | Shuffle |
|
||||
|
||||
#### Actions
|
||||
|
||||
| Key | Action |
|
||||
| --- | --- |
|
||||
| `Enter` | Apply wallpaper and close |
|
||||
| `Space` / `↓` | Apply wallpaper |
|
||||
| `Esc` / `Q` | Close |
|
||||
|
||||
#### Filters
|
||||
|
||||
| Key | Action |
|
||||
| --- | --- |
|
||||
| `A` | Show all |
|
||||
| `I` | Filter images |
|
||||
| `V` | Filter videos |
|
||||
| `F` | Toggle color filter (based on current card) |
|
||||
|
||||
#### View
|
||||
|
||||
| Key | Action |
|
||||
| --- | --- |
|
||||
| `T` | Toggle top bar |
|
||||
| `P` | Toggle live preview |
|
||||
| `?` | Toggle shortcut panel |
|
||||
|
||||
#### Layout
|
||||
|
||||
| Key | Action |
|
||||
| --- | --- |
|
||||
| `Shift + H / L` | Adjust card height |
|
||||
| `Shift + J / K` | Adjust center card width |
|
||||
| `Shift + N / P` | Adjust number of visible cards |
|
||||
| `Ctrl + J / K` | Adjust card spacing |
|
||||
| `Ctrl + H / L` | Adjust side strip width |
|
||||
|
||||
#### Save
|
||||
|
||||
| Key | Action |
|
||||
| --- | --- |
|
||||
| `Ctrl + S` | Save current layout and view settings |
|
||||
|
||||
Scroll wheel also works for navigation.
|
||||
|
||||
## Configuration
|
||||
|
||||
All settings are available through the plugin settings panel in Noctalia. They can also be edited directly in `settings.json` in the plugin directory `~/.config/noctalia/plugins/wallcards`.
|
||||
|
||||
| Setting | Description |
|
||||
| --- | --- |
|
||||
| `animation_cards_duration` | Duration of card transition animations in ms |
|
||||
| `animation_window_duration` | Duration of open/close animations in ms |
|
||||
| `animate_window` | Enable or disable open/close animations |
|
||||
| `background_color` | Color of the dimmed backdrop |
|
||||
| `background_opacity` | Opacity of the dimmed backdrop |
|
||||
| `cards_shown` | Number of visible cards in the stack |
|
||||
| `card_height` | Height of the card area in pixels |
|
||||
| `card_spacing` | Gap between cards in pixels |
|
||||
| `card_strip_width` | Width of non-center cards |
|
||||
| `card_radius` | Border radius of the cards |
|
||||
| `center_width_ratio` | Width of the center card as a ratio of the screen |
|
||||
| `image_filter` | File extensions treated as images |
|
||||
| `video_filter` | File extensions treated as videos |
|
||||
| `hide_help` | Hide the keyboard shortcuts panel |
|
||||
| `hide_top_bar` | Hide the toolbar above the cards |
|
||||
| `live_preview` | Apply wallpaper while navigating |
|
||||
| `selected_filter` | Default filter on open (`all`, `images`, `videos`) |
|
||||
| `shear_factor` | Shearing applied to the card stack |
|
||||
| `top_bar_height` | Height of the toolbar |
|
||||
|
||||
## Known Issues
|
||||
|
||||
- When a video card is played, the following warning is spamed ` WARN: vaExportSurfaceHandle failed`. Please contact me, if you have a solution for this.
|
||||
- Performance for going left or right differs. It is also affected by the total number of cards (is on my todo list)
|
||||
|
||||
## License
|
||||
|
||||
MIT License - see repository for details.
|
||||
|
||||
## Credits
|
||||
|
||||
- Inspired by [ilyamiro](https://github.com/ilyamiro/nixos-configuration) and [liixini](https://github.com/liixini/skwd)
|
||||
- Built for [Noctalia Shell](https://github.com/noctalia-dev/noctalia-shell)
|
||||
@@ -0,0 +1,360 @@
|
||||
import qs.Commons
|
||||
import qs.Widgets
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
|
||||
property int editAnimationCardsDuration: pluginApi?.pluginSettings?.animation_cards_duration ?? pluginApi?.manifest?.metadata?.defaultSettings?.animation_cards_duration
|
||||
property int editAnimationDuration: pluginApi?.pluginSettings?.animation_duration ?? pluginApi?.manifest?.metadata?.defaultSettings?.animation_window_duration
|
||||
property int editAnimationWindowDuration: pluginApi?.pluginSettings?.animation_window_duration ?? pluginApi?.manifest?.metadata?.defaultSettings?.animation_window_duration
|
||||
property color editBackgroundColor: pluginApi?.pluginSettings?.background_color ?? pluginApi?.manifest?.metadata?.defaultSettings?.background_color
|
||||
property real editBackgroundOpacity: pluginApi?.pluginSettings?.background_opacity ?? pluginApi?.manifest?.metadata?.defaultSettings?.background_opacity
|
||||
property int editCardHeight: pluginApi?.pluginSettings?.card_height ?? pluginApi?.manifest?.metadata?.defaultSettings?.card_height
|
||||
property int editCardSpacing: pluginApi?.pluginSettings?.card_spacing ?? pluginApi?.manifest?.metadata?.defaultSettings?.card_spacing
|
||||
property int editCardStripWidth: pluginApi?.pluginSettings?.card_strip_width ?? pluginApi?.manifest?.metadata?.defaultSettings?.card_strip_width
|
||||
property int editCardsShown: pluginApi?.pluginSettings?.cards_shown ?? pluginApi?.manifest?.metadata?.defaultSettings?.cards_shown
|
||||
property real editCenterWidthRatio: pluginApi?.pluginSettings?.center_width_ratio ?? pluginApi?.manifest?.metadata?.defaultSettings?.center_width_ratio
|
||||
property bool editHideHelp: pluginApi?.pluginSettings?.hide_help ?? pluginApi?.manifest?.metadata?.defaultSettings?.hide_help
|
||||
property bool editHideTopBar: pluginApi?.pluginSettings?.hide_top_bar ?? pluginApi?.manifest?.metadata?.defaultSettings?.hide_top_bar ?? false
|
||||
property bool editAnimateWindow: pluginApi?.pluginSettings?.animate_window ?? pluginApi?.manifest?.metadata?.defaultSettings?.animate_window ?? true
|
||||
property string editIconColor: pluginApi?.pluginSettings?.icon_color ?? "none"
|
||||
property bool editLivePreview: pluginApi?.pluginSettings?.live_preview ?? pluginApi?.manifest?.metadata?.defaultSettings?.live_preview
|
||||
property string editSelectedFilter: pluginApi?.pluginSettings?.selected_filter || pluginApi?.manifest?.metadata?.defaultSettings?.selected_filter
|
||||
property real editShearFactor: pluginApi?.pluginSettings?.shear_factor ?? pluginApi?.manifest?.metadata?.defaultSettings?.shear_factor
|
||||
property int editTopBarHeight: pluginApi?.pluginSettings?.top_bar_height ?? pluginApi?.manifest?.metadata?.defaultSettings?.top_bar_height
|
||||
property var pluginApi: null
|
||||
|
||||
function saveSettings() {
|
||||
if (!pluginApi || !pluginApi.pluginSettings) {
|
||||
Logger.e("Wallcards", "Cannot save: pluginApi or pluginSettings is null");
|
||||
return;
|
||||
}
|
||||
|
||||
pluginApi.pluginSettings.animation_cards_duration = root.editAnimationCardsDuration;
|
||||
pluginApi.pluginSettings.animation_window_duration = root.editAnimationWindowDuration;
|
||||
pluginApi.pluginSettings.background_color = root.editBackgroundColor.toString();
|
||||
pluginApi.pluginSettings.background_opacity = root.editBackgroundOpacity;
|
||||
|
||||
pluginApi.pluginSettings.center_width_ratio = root.editCenterWidthRatio;
|
||||
pluginApi.pluginSettings.card_height = root.editCardHeight;
|
||||
pluginApi.pluginSettings.card_spacing = root.editCardSpacing;
|
||||
pluginApi.pluginSettings.card_strip_width = root.editCardStripWidth;
|
||||
pluginApi.pluginSettings.cards_shown = root.editCardsShown;
|
||||
|
||||
pluginApi.pluginSettings.shear_factor = root.editShearFactor;
|
||||
|
||||
pluginApi.pluginSettings.top_bar_height = root.editTopBarHeight;
|
||||
|
||||
pluginApi.pluginSettings.iconColor = root.editIconColor;
|
||||
pluginApi.pluginSettings.selected_filter = root.editSelectedFilter;
|
||||
pluginApi.pluginSettings.live_preview = root.editLivePreview;
|
||||
pluginApi.pluginSettings.hide_help = root.editHideHelp;
|
||||
pluginApi.pluginSettings.hide_top_bar = root.editHideTopBar;
|
||||
pluginApi.pluginSettings.animate_window = root.editAnimateWindow;
|
||||
|
||||
pluginApi.saveSettings();
|
||||
Logger.i("Wallcards", "Settings saved");
|
||||
}
|
||||
|
||||
Layout.rightMargin: Style.marginL
|
||||
spacing: Style.marginL
|
||||
|
||||
// ── Icon ──
|
||||
NComboBox {
|
||||
currentKey: root.editIconColor
|
||||
description: I18n.tr("common.select-color-description")
|
||||
label: I18n.tr("common.select-icon-color")
|
||||
minimumWidth: 200
|
||||
model: Color.colorKeyModel
|
||||
|
||||
onSelected: key => root.editIconColor = key
|
||||
}
|
||||
NDivider {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
// ── Behavior ──
|
||||
NToggle {
|
||||
checked: root.editLivePreview
|
||||
defaultValue: pluginApi?.manifest?.metadata?.defaultSettings?.live_preview ?? false
|
||||
description: root.pluginApi?.tr("settings.live-preview.description")
|
||||
label: root.pluginApi?.tr("settings.live-preview.label")
|
||||
|
||||
onToggled: c => root.editLivePreview = c
|
||||
}
|
||||
NComboBox {
|
||||
currentKey: root.editSelectedFilter
|
||||
defaultValue: pluginApi?.manifest?.metadata?.defaultSettings?.selected_filter || "all"
|
||||
description: root.pluginApi?.tr("settings.default-filter.description")
|
||||
label: root.pluginApi?.tr("settings.default-filter.label")
|
||||
model: [
|
||||
{
|
||||
"key": "all",
|
||||
"name": root.pluginApi?.tr("buttons.all")
|
||||
},
|
||||
{
|
||||
"key": "images",
|
||||
"name": root.pluginApi?.tr("buttons.images")
|
||||
},
|
||||
{
|
||||
"key": "videos",
|
||||
"name": root.pluginApi?.tr("buttons.videos")
|
||||
}
|
||||
]
|
||||
|
||||
onSelected: key => root.editSelectedFilter = key
|
||||
}
|
||||
NToggle {
|
||||
checked: root.editHideHelp
|
||||
defaultValue: pluginApi?.manifest?.metadata?.defaultSettings?.hide_help ?? false
|
||||
description: root.pluginApi?.tr("settings.hide-shortcuts.description")
|
||||
label: root.pluginApi?.tr("settings.hide-shortcuts.label")
|
||||
|
||||
onToggled: c => root.editHideHelp = c
|
||||
}
|
||||
NToggle {
|
||||
checked: root.editHideTopBar
|
||||
defaultValue: pluginApi?.manifest?.metadata?.defaultSettings?.hide_top_bar ?? false
|
||||
description: root.pluginApi?.tr("settings.hide-top-bar.description")
|
||||
label: root.pluginApi?.tr("settings.hide-top-bar.label")
|
||||
|
||||
onToggled: c => root.editHideTopBar = c
|
||||
}
|
||||
NDivider {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
// ── Card Layout ──
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginXXS
|
||||
|
||||
NLabel {
|
||||
description: root.pluginApi?.tr("settings.center-card-width.description")
|
||||
label: root.pluginApi?.tr("settings.center-card-width.label")
|
||||
}
|
||||
NValueSlider {
|
||||
Layout.fillWidth: true
|
||||
from: 0.20
|
||||
stepSize: 0.01
|
||||
text: (root.editCenterWidthRatio * 100).toFixed(0) + "%"
|
||||
to: 0.60
|
||||
value: root.editCenterWidthRatio
|
||||
|
||||
onMoved: value => root.editCenterWidthRatio = value
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginXXS
|
||||
|
||||
NLabel {
|
||||
description: root.pluginApi?.tr("settings.card-height.description")
|
||||
label: root.pluginApi?.tr("settings.card-height.label")
|
||||
}
|
||||
NValueSlider {
|
||||
Layout.fillWidth: true
|
||||
from: 100
|
||||
stepSize: 10
|
||||
text: root.editCardHeight + "px"
|
||||
to: 800
|
||||
value: root.editCardHeight
|
||||
|
||||
onMoved: value => root.editCardHeight = value
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginXXS
|
||||
|
||||
NLabel {
|
||||
description: root.pluginApi?.tr("settings.strip-width.description")
|
||||
label: root.pluginApi?.tr("settings.strip-width.label")
|
||||
}
|
||||
NValueSlider {
|
||||
Layout.fillWidth: true
|
||||
from: 20
|
||||
stepSize: 5
|
||||
text: root.editCardStripWidth + "px"
|
||||
to: 150
|
||||
value: root.editCardStripWidth
|
||||
|
||||
onMoved: value => root.editCardStripWidth = value
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginXXS
|
||||
|
||||
NLabel {
|
||||
description: root.pluginApi?.tr("settings.card-spacing.description")
|
||||
label: root.pluginApi?.tr("settings.card-spacing.label")
|
||||
}
|
||||
NValueSlider {
|
||||
Layout.fillWidth: true
|
||||
from: 0
|
||||
stepSize: 1
|
||||
text: root.editCardSpacing + "px"
|
||||
to: 50
|
||||
value: root.editCardSpacing
|
||||
|
||||
onMoved: value => root.editCardSpacing = value
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginXXS
|
||||
|
||||
NLabel {
|
||||
description: root.pluginApi?.tr("settings.cards-shown.description")
|
||||
label: root.pluginApi?.tr("settings.cards-shown.label")
|
||||
}
|
||||
NValueSlider {
|
||||
Layout.fillWidth: true
|
||||
from: 5
|
||||
stepSize: 2
|
||||
text: root.editCardsShown
|
||||
to: 15
|
||||
value: root.editCardsShown
|
||||
|
||||
onMoved: value => root.editCardsShown = value
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginXXS
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginXXS
|
||||
|
||||
NLabel {
|
||||
description: root.pluginApi?.tr("settings.shear-factor.description")
|
||||
label: root.pluginApi?.tr("settings.shear-factor.label")
|
||||
}
|
||||
NValueSlider {
|
||||
Layout.fillWidth: true
|
||||
from: -0.3
|
||||
stepSize: 0.01
|
||||
text: root.editShearFactor.toFixed(2)
|
||||
to: 0.3
|
||||
value: root.editShearFactor
|
||||
|
||||
onMoved: value => root.editShearFactor = value
|
||||
}
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginXXS
|
||||
|
||||
NLabel {
|
||||
description: root.pluginApi?.tr("settings.card-animation.description")
|
||||
label: root.pluginApi?.tr("settings.card-animation.label")
|
||||
}
|
||||
NValueSlider {
|
||||
Layout.fillWidth: true
|
||||
from: 0
|
||||
stepSize: 100
|
||||
text: root.editAnimationCardsDuration + "ms"
|
||||
to: 1500
|
||||
value: root.editAnimationCardsDuration
|
||||
|
||||
onMoved: value => root.editAnimationCardsDuration = value
|
||||
}
|
||||
}
|
||||
NDivider {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
// ── Appearance ──
|
||||
RowLayout {
|
||||
NLabel {
|
||||
Layout.alignment: Qt.AlignTop
|
||||
description: root.pluginApi?.tr("settings.background-color.description")
|
||||
label: root.pluginApi?.tr("settings.background-color.label")
|
||||
}
|
||||
NColorPicker {
|
||||
selectedColor: root.editBackgroundColor
|
||||
|
||||
onColorSelected: color => root.editBackgroundColor = color
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginXXS
|
||||
|
||||
NLabel {
|
||||
description: root.pluginApi?.tr("settings.background-opacity.description")
|
||||
label: root.pluginApi?.tr("settings.background-opacity.label")
|
||||
}
|
||||
NValueSlider {
|
||||
Layout.fillWidth: true
|
||||
from: 0
|
||||
stepSize: 0.05
|
||||
text: (root.editBackgroundOpacity * 100).toFixed(0) + "%"
|
||||
to: 1
|
||||
value: root.editBackgroundOpacity
|
||||
|
||||
onMoved: value => root.editBackgroundOpacity = value
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginXXS
|
||||
|
||||
NLabel {
|
||||
description: root.pluginApi?.tr("settings.window-animation-speed.description")
|
||||
label: root.pluginApi?.tr("settings.window-animation-speed.label")
|
||||
}
|
||||
NValueSlider {
|
||||
Layout.fillWidth: true
|
||||
from: 0
|
||||
stepSize: 100
|
||||
text: root.editAnimationWindowDuration + "ms"
|
||||
to: 1500
|
||||
value: root.editAnimationWindowDuration
|
||||
|
||||
onMoved: value => root.editAnimationWindowDuration = value
|
||||
}
|
||||
}
|
||||
NToggle {
|
||||
checked: root.editAnimateWindow
|
||||
defaultValue: pluginApi?.manifest?.metadata?.defaultSettings?.animate_window ?? true
|
||||
description: root.pluginApi?.tr("settings.animate-window.description")
|
||||
label: root.pluginApi?.tr("settings.animate-window.label")
|
||||
|
||||
onToggled: c => root.editAnimateWindow = c
|
||||
}
|
||||
NDivider {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
// ── Top Bar ──
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginXXS
|
||||
|
||||
NLabel {
|
||||
description: root.pluginApi?.tr("settings.top-bar-height.description")
|
||||
label: root.pluginApi?.tr("settings.top-bar-height.label")
|
||||
}
|
||||
NValueSlider {
|
||||
Layout.fillWidth: true
|
||||
from: 10
|
||||
stepSize: 2
|
||||
text: root.editTopBarHeight + "px"
|
||||
to: 80
|
||||
value: root.editTopBarHeight
|
||||
|
||||
onMoved: value => root.editTopBarHeight = value
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginXXS
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,414 @@
|
||||
import "src"
|
||||
import "src/Utils.js" as Utils
|
||||
import qs.Commons
|
||||
import qs.Widgets
|
||||
import qs.Services.UI
|
||||
import QtQuick
|
||||
import QtMultimedia
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import Quickshell.Wayland
|
||||
import Qt5Compat.GraphicalEffects
|
||||
import Qt.labs.folderlistmodel
|
||||
|
||||
PanelWindow {
|
||||
id: root
|
||||
|
||||
property int animationCardsDuration: pluginApi?.pluginSettings?.animation_cards_duration ?? pluginApi?.manifest?.metadata?.defaultSettings?.animation_cards_duration
|
||||
property int animationWindowDuration: pluginApi?.pluginSettings?.animation_window_duration ?? pluginApi?.manifest?.metadata?.defaultSettings?.animation_window_duration
|
||||
property bool animateWindow: pluginApi?.pluginSettings?.animate_window ?? pluginApi?.manifest?.metadata?.defaultSettings?.animate_window ?? true
|
||||
property color backgroundColor: pluginApi?.pluginSettings?.background_color ?? pluginApi?.manifest?.metadata?.defaultSettings?.background_color
|
||||
property real backgroundOpacity: pluginApi?.pluginSettings?.background_opacity ?? pluginApi?.manifest?.metadata?.defaultSettings?.background_opacity
|
||||
property int cardHeight: pluginApi?.pluginSettings?.card_height ?? pluginApi?.manifest?.metadata?.defaultSettings?.card_height
|
||||
property int cardRadius: Style.radiusM
|
||||
property int cardSpacing: pluginApi?.pluginSettings?.card_spacing ?? pluginApi?.manifest?.metadata?.defaultSettings?.card_spacing
|
||||
property int cardStripWidth: pluginApi?.pluginSettings?.card_strip_width ?? pluginApi?.manifest?.metadata?.defaultSettings?.card_strip_width
|
||||
property int cardsShown: pluginApi?.pluginSettings?.cards_shown ?? pluginApi?.manifest?.metadata?.defaultSettings?.cards_shown
|
||||
property real centerWidthRatio: pluginApi?.pluginSettings?.center_width_ratio ?? pluginApi?.manifest?.metadata?.defaultSettings?.center_width_ratio
|
||||
property int currentIndex: cardDeck.currentIndex
|
||||
property string currentCardColor: filteredFiles[currentIndex]?.filterColor ?? ""
|
||||
property var imageFilter: pluginApi?.manifest?.metadata?.defaultSettings?.image_filter
|
||||
property var videoFilter: pluginApi?.manifest?.metadata?.defaultSettings?.video_filter
|
||||
property var filteredFiles: []
|
||||
property var availableColors: []
|
||||
property bool hideHelp: pluginApi?.pluginSettings?.hide_help ?? pluginApi?.manifest?.metadata?.defaultSettings?.hide_help ?? true
|
||||
property bool hideTopBar: pluginApi?.pluginSettings?.hide_top_bar ?? pluginApi?.manifest?.metadata?.defaultSettings?.hide_top_bar ?? false
|
||||
property bool livePreview: pluginApi?.pluginSettings?.live_preview ?? pluginApi?.manifest?.metadata?.defaultSettings?.live_preview
|
||||
property bool loading: thumbnailService.loading
|
||||
property int pendingProcesses: 0
|
||||
property var pluginApi: null
|
||||
property string selectedFilter: pluginApi?.pluginSettings?.selected_filter || pluginApi?.manifest?.metadata?.defaultSettings?.selected_filter
|
||||
property string selectedColorFilter: ""
|
||||
property real shearFactor: pluginApi?.pluginSettings?.shear_factor ?? pluginApi?.manifest?.metadata?.defaultSettings?.shear_factor
|
||||
property int thumbnailRevision: thumbnailService.thumbnailRevision
|
||||
property int topBarHeight: pluginApi?.pluginSettings?.top_bar_height ?? pluginApi?.manifest?.metadata?.defaultSettings?.top_bar_height
|
||||
property int topBarRadius: Style.radiusM
|
||||
|
||||
signal quitRequested
|
||||
|
||||
function applyCurrentCard() {
|
||||
var f = filteredFiles[cardDeck.currentIndex];
|
||||
if (!f)
|
||||
return;
|
||||
|
||||
applicant.command = ["bash", "-c", Utils.wallpaperCommand(f)];
|
||||
applicant.running = true;
|
||||
|
||||
var wallpaperPath = f.isVideo ? f.thumbnail : f.filePath;
|
||||
WallpaperService.changeWallpaper(wallpaperPath);
|
||||
}
|
||||
|
||||
function applyFilterToFiles() {
|
||||
var currentFile = filteredFiles[cardDeck.currentIndex]?.filePath ?? "";
|
||||
|
||||
var all = thumbnailService.files ?? [];
|
||||
var result = all;
|
||||
|
||||
if (selectedFilter === "images")
|
||||
result = result.filter(f => !f.isVideo);
|
||||
else if (selectedFilter === "videos")
|
||||
result = result.filter(f => f.isVideo);
|
||||
|
||||
var colors = {};
|
||||
for (var c = 0; c < result.length; c++)
|
||||
colors[result[c].filterColor] = true;
|
||||
availableColors = Object.keys(colors);
|
||||
|
||||
if (selectedColorFilter !== "")
|
||||
result = result.filter(f => f.filterColor === selectedColorFilter);
|
||||
|
||||
filteredFiles = result;
|
||||
|
||||
var newIdx = 0;
|
||||
if (currentFile !== "") {
|
||||
for (var i = 0; i < result.length; i++) {
|
||||
if (result[i].filePath === currentFile) {
|
||||
newIdx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cardDeck.jumpTo(newIdx);
|
||||
}
|
||||
|
||||
function close() {
|
||||
if (exitAnimation.running)
|
||||
return;
|
||||
if (root.animateWindow) {
|
||||
exitAnimation.start();
|
||||
} else {
|
||||
root.quitRequested();
|
||||
}
|
||||
}
|
||||
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive
|
||||
WlrLayershell.layer: WlrLayer.Overlay
|
||||
aboveWindows: true
|
||||
color: "transparent"
|
||||
exclusionMode: "Ignore"
|
||||
exclusiveZone: 0
|
||||
implicitHeight: screen.height
|
||||
implicitWidth: screen.width
|
||||
screen: pluginApi.panelOpenScreen
|
||||
|
||||
onCurrentIndexChanged: {
|
||||
if (root.livePreview)
|
||||
applyCurrentCard();
|
||||
}
|
||||
|
||||
onSelectedFilterChanged: applyFilterToFiles()
|
||||
onSelectedColorFilterChanged: applyFilterToFiles()
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
if (root.animateWindow) {
|
||||
enterAnimation.start();
|
||||
} else {
|
||||
content.opacity = 1;
|
||||
content.scale = 1;
|
||||
background.opacity = root.backgroundOpacity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: applicant
|
||||
|
||||
command: []
|
||||
running: false
|
||||
}
|
||||
|
||||
Connections {
|
||||
function onFilesChanged() {
|
||||
root.applyFilterToFiles();
|
||||
}
|
||||
|
||||
target: thumbnailService
|
||||
}
|
||||
|
||||
ThumbnailService {
|
||||
id: thumbnailService
|
||||
|
||||
cacheDir: root.pluginApi?.Settings.cacheDir + "/wallcards"
|
||||
imageFilter: root.imageFilter
|
||||
videoFilter: root.videoFilter
|
||||
wallpaperDir: root.pluginApi?.Settings.data.wallpaper.directory
|
||||
}
|
||||
|
||||
ParallelAnimation {
|
||||
id: enterAnimation
|
||||
|
||||
NumberAnimation {
|
||||
duration: root.animationWindowDuration
|
||||
easing.type: Easing.OutCubic
|
||||
from: 0.85
|
||||
property: "scale"
|
||||
target: content
|
||||
to: 1.0
|
||||
}
|
||||
NumberAnimation {
|
||||
duration: root.animationWindowDuration
|
||||
easing.type: Easing.OutCubic
|
||||
from: 0
|
||||
property: "opacity"
|
||||
target: content
|
||||
to: 1
|
||||
}
|
||||
NumberAnimation {
|
||||
duration: root.animationWindowDuration
|
||||
easing.type: Easing.OutCubic
|
||||
from: 0
|
||||
property: "opacity"
|
||||
target: background
|
||||
to: root.backgroundOpacity
|
||||
}
|
||||
}
|
||||
|
||||
ParallelAnimation {
|
||||
id: exitAnimation
|
||||
|
||||
property int duration: root.animationWindowDuration * 0.4
|
||||
|
||||
onFinished: root.quitRequested()
|
||||
|
||||
NumberAnimation {
|
||||
duration: exitAnimation.duration
|
||||
easing.type: Easing.InCubic
|
||||
property: "opacity"
|
||||
target: content
|
||||
to: 0
|
||||
}
|
||||
NumberAnimation {
|
||||
duration: exitAnimation.duration
|
||||
easing.type: Easing.InCubic
|
||||
property: "scale"
|
||||
target: content
|
||||
to: 0.85
|
||||
}
|
||||
NumberAnimation {
|
||||
duration: exitAnimation.duration
|
||||
easing.type: Easing.InCubic
|
||||
property: "opacity"
|
||||
target: background
|
||||
to: 0
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: background
|
||||
|
||||
anchors.fill: parent
|
||||
color: root.backgroundColor
|
||||
opacity: 0
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
|
||||
onClicked: root.close()
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: content
|
||||
|
||||
anchors.fill: parent
|
||||
focus: true
|
||||
opacity: 0
|
||||
scale: 0.85
|
||||
|
||||
Keys.onPressed: event => {
|
||||
if (event.modifiers & Qt.ShiftModifier) {
|
||||
if (event.key === Qt.Key_H) {
|
||||
root.cardHeight = Math.max(root.cardHeight - 10, parent.height * 0.10);
|
||||
event.accepted = true;
|
||||
return;
|
||||
} else if (event.key === Qt.Key_L) {
|
||||
root.cardHeight = Math.min(root.cardHeight + 10, parent.height * 0.75);
|
||||
event.accepted = true;
|
||||
return;
|
||||
} else if (event.key === Qt.Key_J) {
|
||||
cardDeck.centerWidthRatio = Math.max(cardDeck.centerWidthRatio - 0.01, 0.2);
|
||||
event.accepted = true;
|
||||
return;
|
||||
} else if (event.key === Qt.Key_K) {
|
||||
cardDeck.centerWidthRatio = Math.min(cardDeck.centerWidthRatio + 0.01, 0.6);
|
||||
event.accepted = true;
|
||||
return;
|
||||
} else if (event.key === Qt.Key_N) {
|
||||
root.cardsShown = Math.max(root.cardsShown - 2, 5);
|
||||
event.accepted = true;
|
||||
return;
|
||||
} else if (event.key === Qt.Key_P) {
|
||||
root.cardsShown = Math.min(root.cardsShown + 2, 15);
|
||||
event.accepted = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
if (event.key === Qt.Key_K) {
|
||||
root.cardSpacing = Math.max(root.cardSpacing + 2, 0);
|
||||
event.accepted = true;
|
||||
return;
|
||||
} else if (event.key === Qt.Key_J) {
|
||||
root.cardSpacing = Math.max(root.cardSpacing - 2, 0);
|
||||
event.accepted = true;
|
||||
return;
|
||||
} else if (event.key === Qt.Key_L) {
|
||||
root.cardStripWidth = Math.min(root.cardStripWidth + 5, 300);
|
||||
event.accepted = true;
|
||||
return;
|
||||
} else if (event.key === Qt.Key_H) {
|
||||
root.cardStripWidth = Math.max(root.cardStripWidth - 5, 20);
|
||||
event.accepted = true;
|
||||
return;
|
||||
} else if (event.key === Qt.Key_S) {
|
||||
root.pluginApi.pluginSettings.card_height = root.cardHeight;
|
||||
root.pluginApi.pluginSettings.center_width_ratio = cardDeck.centerWidthRatio;
|
||||
root.pluginApi.pluginSettings.cards_shown = root.cardsShown;
|
||||
root.pluginApi.pluginSettings.card_spacing = root.cardSpacing;
|
||||
root.pluginApi.pluginSettings.card_strip_width = root.cardStripWidth;
|
||||
root.pluginApi.pluginSettings.hide_top_bar = root.hideTopBar;
|
||||
root.pluginApi.pluginSettings.live_preview = root.livePreview;
|
||||
root.pluginApi.pluginSettings.selected_filter = root.selectedFilter;
|
||||
root.pluginApi.pluginSettings.hide_help = root.hideHelp;
|
||||
root.pluginApi.pluginSettings.animate_window = root.animateWindow;
|
||||
root.pluginApi.saveSettings();
|
||||
event.accepted = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function handleKey(event, bindings) {
|
||||
const action = bindings[event.key];
|
||||
if (action) {
|
||||
action();
|
||||
event.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
const bindings = {
|
||||
[Qt.Key_Question]: () => sideBar.expanded = !sideBar.expanded,
|
||||
[Qt.Key_Q]: () => root.close(),
|
||||
[Qt.Key_Return]: () => {
|
||||
root.applyCurrentCard();
|
||||
root.close();
|
||||
},
|
||||
[Qt.Key_Space]: () => root.applyCurrentCard(),
|
||||
[Qt.Key_Escape]: () => root.close(),
|
||||
[Qt.Key_A]: () => root.selectedFilter = "all",
|
||||
[Qt.Key_I]: () => root.selectedFilter = "images",
|
||||
[Qt.Key_V]: () => root.selectedFilter = "videos",
|
||||
[Qt.Key_T]: () => root.hideTopBar = !root.hideTopBar,
|
||||
[Qt.Key_F]: () => {
|
||||
if (root.selectedColorFilter !== "")
|
||||
root.selectedColorFilter = "";
|
||||
else
|
||||
root.selectedColorFilter = root.currentCardColor;
|
||||
},
|
||||
[Qt.Key_R]: () => {
|
||||
cardDeck.randomJump();
|
||||
topBar.flashShuffle();
|
||||
},
|
||||
[Qt.Key_P]: () => root.livePreview = !root.livePreview,
|
||||
[Qt.Key_K]: () => cardDeck.navigateTo(cardDeck.currentIndex + 1),
|
||||
[Qt.Key_J]: () => cardDeck.navigateTo(cardDeck.currentIndex - 1),
|
||||
[Qt.Key_L]: () => cardDeck.navigateTo(cardDeck.currentIndex + root.cardsShown - 2),
|
||||
[Qt.Key_H]: () => cardDeck.navigateTo(cardDeck.currentIndex - root.cardsShown + 2)
|
||||
};
|
||||
|
||||
const action = bindings[event.key];
|
||||
if (action) {
|
||||
action();
|
||||
event.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
LoadingBar {
|
||||
id: loadingBar
|
||||
|
||||
anchors.centerIn: parent
|
||||
pending: thumbnailService.pendingProcesses
|
||||
total: thumbnailService.fileCount
|
||||
}
|
||||
|
||||
TopBar {
|
||||
id: topBar
|
||||
|
||||
anchors.bottom: cardDeck.top
|
||||
anchors.bottomMargin: root.topBarHeight / 3
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.horizontalCenterOffset: shearFactor * -root.topBarHeight * 4 / 3
|
||||
animationDuration: root.animationCardsDuration
|
||||
availableColors: root.availableColors
|
||||
colorOrder: thumbnailService.colorOrder
|
||||
colorOrderColors: thumbnailService.colorOrderColors
|
||||
currentCardColor: root.currentCardColor
|
||||
currentIndex: cardDeck.currentIndex
|
||||
filteredCount: root.filteredFiles.length
|
||||
height: root.topBarHeight
|
||||
livePreview: root.livePreview
|
||||
pluginApi: root.pluginApi
|
||||
radius: root.topBarRadius
|
||||
selectedColorFilter: root.selectedColorFilter
|
||||
selectedFilter: root.selectedFilter
|
||||
shearFactor: root.shearFactor
|
||||
visible: !loadingBar.visible && !root.hideTopBar
|
||||
width: cardDeck.width
|
||||
|
||||
onColorFilterSelected: key => root.selectedColorFilter = key
|
||||
onFilterSelected: key => root.selectedFilter = key
|
||||
onLivePreviewToggled: root.livePreview = !root.livePreview
|
||||
onShuffleRequested: cardDeck.randomJump()
|
||||
}
|
||||
|
||||
SideBar {
|
||||
id: sideBar
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Style.marginL
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
hideHelp: root.hideHelp
|
||||
visible: !loadingBar.visible
|
||||
}
|
||||
|
||||
CardDeck {
|
||||
id: cardDeck
|
||||
|
||||
anchors.centerIn: parent
|
||||
animationDuration: root.animationCardsDuration
|
||||
cardRadius: root.cardRadius
|
||||
cardSpacing: root.cardSpacing
|
||||
cardStripWidth: root.cardStripWidth
|
||||
cardsShown: root.cardsShown
|
||||
centerWidthRatio: root.centerWidthRatio
|
||||
filteredCount: root.filteredFiles.length
|
||||
filteredModel: root.filteredFiles
|
||||
height: root.cardHeight
|
||||
shearFactor: root.shearFactor
|
||||
visible: !loadingBar.visible
|
||||
|
||||
onApplyRequested: root.applyCurrentCard()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
{
|
||||
"buttons": {
|
||||
"all": "Alle",
|
||||
"images": "Bilder",
|
||||
"videos": "Videos",
|
||||
"shuffle": "Mischen",
|
||||
"live-preview": "Live",
|
||||
"color-na": "✕"
|
||||
},
|
||||
"widget": {
|
||||
"tooltip": "Wallcards öffnen",
|
||||
"generate-thumbs-message": "Miniaturbilder werden erstellt…"
|
||||
},
|
||||
"settings": {
|
||||
"icon-color": {
|
||||
"label": "Symbolfarbe",
|
||||
"description": "Farbe des Leistensymbols"
|
||||
},
|
||||
"live-preview": {
|
||||
"label": "Live-Vorschau",
|
||||
"description": "Hintergrundbild beim Durchblättern anwenden"
|
||||
},
|
||||
"default-filter": {
|
||||
"label": "Standardfilter",
|
||||
"description": "Anfänglicher Dateitypfilter beim Öffnen"
|
||||
},
|
||||
"hide-shortcuts": {
|
||||
"label": "Tastenkürzel ausblenden",
|
||||
"description": "Tastenkürzel-Leiste ausblenden"
|
||||
},
|
||||
"hide-top-bar": {
|
||||
"label": "Kopfleiste ausblenden",
|
||||
"description": "Werkzeugleiste über den Karten ausblenden"
|
||||
},
|
||||
"center-card-width": {
|
||||
"label": "Breite der mittleren Karte",
|
||||
"description": "Breite der mittleren Karte in Prozent des Bildschirms"
|
||||
},
|
||||
"card-height": {
|
||||
"label": "Kartenhöhe",
|
||||
"description": "Höhe der Hintergrundbilder-Karten"
|
||||
},
|
||||
"strip-width": {
|
||||
"label": "Streifenbreite",
|
||||
"description": "Breite der seitlichen Kartenstreifen"
|
||||
},
|
||||
"card-spacing": {
|
||||
"label": "Kartenabstand",
|
||||
"description": "Abstand zwischen den Karten"
|
||||
},
|
||||
"cards-shown": {
|
||||
"label": "Angezeigte Karten",
|
||||
"description": "Anzahl sichtbarer Karten (ungerade Zahlen empfohlen)"
|
||||
},
|
||||
"shear-factor": {
|
||||
"label": "Scherungsfaktor",
|
||||
"description": "Neigungswinkel des Kartenlayouts"
|
||||
},
|
||||
"card-animation": {
|
||||
"label": "Kartenanimation",
|
||||
"description": "Geschwindigkeit der Kartenübergänge"
|
||||
},
|
||||
"background-color": {
|
||||
"label": "Hintergrundfarbe",
|
||||
"description": "Farbe der abgedunkelten Überblendung"
|
||||
},
|
||||
"background-opacity": {
|
||||
"label": "Hintergrund-Deckkraft",
|
||||
"description": "Deckkraft der abgedunkelten Überblendung"
|
||||
},
|
||||
"window-animation-speed": {
|
||||
"label": "Fensteranimation-Geschwindigkeit",
|
||||
"description": "Geschwindigkeit der Öffnen- und Schließen-Übergänge"
|
||||
},
|
||||
"animate-window": {
|
||||
"label": "Fensteranimation",
|
||||
"description": "Öffnen- und Schließen-Übergänge animieren"
|
||||
},
|
||||
"top-bar-height": {
|
||||
"label": "Kopfleistenhöhe",
|
||||
"description": "Höhe der Werkzeugleiste"
|
||||
}
|
||||
},
|
||||
"shortcuts": {
|
||||
"key-separator": "/",
|
||||
"header": {
|
||||
"navigation": "NAVIGATION",
|
||||
"actions": "AKTIONEN",
|
||||
"filters": "FILTER",
|
||||
"view": "ANSICHT",
|
||||
"layout": "LAYOUT"
|
||||
},
|
||||
"label": {
|
||||
"help-title": "Tastenkürzel",
|
||||
"navigate": "Navigieren",
|
||||
"jump": "Springen",
|
||||
"shuffle": "Mischen",
|
||||
"apply-quit": "Anwenden + Schließen",
|
||||
"apply": "Anwenden",
|
||||
"quit": "Schließen",
|
||||
"filter-all": "Alle",
|
||||
"filter-images": "Bilder",
|
||||
"filter-videos": "Videos",
|
||||
"filter-colors": "Farbfilter",
|
||||
"top-bar": "Kopfleiste umschalten",
|
||||
"live-preview": "Live-Vorschau umschalten",
|
||||
"center-height": "Kartenhöhe",
|
||||
"center-width": "Kartenbreite",
|
||||
"cards-shown": "Angezeigte Karten",
|
||||
"cards-spacing": "Abstand",
|
||||
"cards-width": "Kartenbreite",
|
||||
"save": "Einstellungen speichern",
|
||||
"hide": "Ausblenden"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
{
|
||||
"buttons": {
|
||||
"all": "All",
|
||||
"images": "Images",
|
||||
"videos": "Videos",
|
||||
"shuffle": "Shuffle",
|
||||
"live-preview": "Live",
|
||||
"color-na": "✕"
|
||||
},
|
||||
"widget": {
|
||||
"tooltip": "Open Wallcards",
|
||||
"generate-thumbs-message": "Generating thumbnails…"
|
||||
},
|
||||
"settings": {
|
||||
"icon-color": {
|
||||
"label": "Icon Color",
|
||||
"description": "Color of the bar widget icon"
|
||||
},
|
||||
"live-preview": {
|
||||
"label": "Live Preview",
|
||||
"description": "Apply wallpaper while browsing cards"
|
||||
},
|
||||
"default-filter": {
|
||||
"label": "Default Filter",
|
||||
"description": "Initial file type filter when opening"
|
||||
},
|
||||
"hide-shortcuts": {
|
||||
"label": "Hide Shortcuts",
|
||||
"description": "Hide the keyboard shortcuts panel"
|
||||
},
|
||||
"hide-top-bar": {
|
||||
"label": "Hide Top Bar",
|
||||
"description": "Hide the toolbar above the cards"
|
||||
},
|
||||
"center-card-width": {
|
||||
"label": "Center Card Width",
|
||||
"description": "Width of the center card as percentage of screen"
|
||||
},
|
||||
"card-height": {
|
||||
"label": "Card Height",
|
||||
"description": "Height of the wallpaper cards"
|
||||
},
|
||||
"strip-width": {
|
||||
"label": "Strip Width",
|
||||
"description": "Width of the side card strips"
|
||||
},
|
||||
"card-spacing": {
|
||||
"label": "Card Spacing",
|
||||
"description": "Gap between cards"
|
||||
},
|
||||
"cards-shown": {
|
||||
"label": "Cards Shown",
|
||||
"description": "Number of visible cards (odd numbers recommended)"
|
||||
},
|
||||
"shear-factor": {
|
||||
"label": "Shear Factor",
|
||||
"description": "Skew angle of the card layout"
|
||||
},
|
||||
"card-animation": {
|
||||
"label": "Card Animation",
|
||||
"description": "Speed of card transitions"
|
||||
},
|
||||
"background-color": {
|
||||
"label": "Background Color",
|
||||
"description": "Color of the dimmed overlay"
|
||||
},
|
||||
"background-opacity": {
|
||||
"label": "Background Opacity",
|
||||
"description": "Opacity of the dimmed overlay"
|
||||
},
|
||||
"window-animation-speed": {
|
||||
"label": "Window Animation Speed",
|
||||
"description": "Speed of open and close transitions"
|
||||
},
|
||||
"animate-window": {
|
||||
"label": "Window Animation",
|
||||
"description": "Animate the open and close transitions"
|
||||
},
|
||||
"top-bar-height": {
|
||||
"label": "Top Bar Height",
|
||||
"description": "Height of the toolbar"
|
||||
}
|
||||
},
|
||||
"shortcuts": {
|
||||
"key-separator": "/",
|
||||
"header": {
|
||||
"navigation": "NAVIGATION",
|
||||
"actions": "ACTIONS",
|
||||
"filters": "FILTERS",
|
||||
"view": "VIEW",
|
||||
"layout": "LAYOUT"
|
||||
},
|
||||
"label": {
|
||||
"help-title": "Shortcuts",
|
||||
"navigate": "Navigate",
|
||||
"jump": "Jump",
|
||||
"shuffle": "Shuffle",
|
||||
"apply-quit": "Apply + Quit",
|
||||
"apply": "Apply",
|
||||
"quit": "Quit",
|
||||
"filter-all": "All",
|
||||
"filter-images": "Images",
|
||||
"filter-videos": "Videos",
|
||||
"filter-colors": "Color Filter",
|
||||
"top-bar": "Toggle Top Bar",
|
||||
"live-preview": "Toggle Live Preview",
|
||||
"center-height": "Center Height",
|
||||
"center-width": "Center Width",
|
||||
"cards-shown": "Cards Shown",
|
||||
"cards-spacing": "Spacing",
|
||||
"cards-width": "Cards Width",
|
||||
"save": "Save Settings",
|
||||
"hide": "Hide"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
{
|
||||
"buttons": {
|
||||
"all": "Todos",
|
||||
"images": "Imágenes",
|
||||
"videos": "Vídeos",
|
||||
"shuffle": "Mezclar",
|
||||
"live-preview": "En vivo",
|
||||
"color-na": "✕"
|
||||
},
|
||||
"widget": {
|
||||
"tooltip": "Abrir Wallcards",
|
||||
"generate-thumbs-message": "Generando miniaturas…"
|
||||
},
|
||||
"settings": {
|
||||
"icon-color": {
|
||||
"label": "Color del icono",
|
||||
"description": "Color del icono del widget de barra"
|
||||
},
|
||||
"live-preview": {
|
||||
"label": "Vista previa en vivo",
|
||||
"description": "Aplicar fondo mientras navegas por las tarjetas"
|
||||
},
|
||||
"default-filter": {
|
||||
"label": "Filtro predeterminado",
|
||||
"description": "Filtro de tipo de archivo inicial al abrir"
|
||||
},
|
||||
"hide-shortcuts": {
|
||||
"label": "Ocultar atajos",
|
||||
"description": "Ocultar el panel de atajos de teclado"
|
||||
},
|
||||
"hide-top-bar": {
|
||||
"label": "Ocultar barra superior",
|
||||
"description": "Ocultar la barra de herramientas sobre las tarjetas"
|
||||
},
|
||||
"center-card-width": {
|
||||
"label": "Ancho de tarjeta central",
|
||||
"description": "Ancho de la tarjeta central como porcentaje de la pantalla"
|
||||
},
|
||||
"card-height": {
|
||||
"label": "Altura de tarjeta",
|
||||
"description": "Altura de las tarjetas de fondo"
|
||||
},
|
||||
"strip-width": {
|
||||
"label": "Ancho de franja",
|
||||
"description": "Ancho de las franjas laterales"
|
||||
},
|
||||
"card-spacing": {
|
||||
"label": "Espaciado de tarjetas",
|
||||
"description": "Espacio entre tarjetas"
|
||||
},
|
||||
"cards-shown": {
|
||||
"label": "Tarjetas visibles",
|
||||
"description": "Número de tarjetas visibles (se recomiendan números impares)"
|
||||
},
|
||||
"shear-factor": {
|
||||
"label": "Factor de inclinación",
|
||||
"description": "Ángulo de inclinación del diseño de tarjetas"
|
||||
},
|
||||
"card-animation": {
|
||||
"label": "Animación de tarjetas",
|
||||
"description": "Velocidad de las transiciones de tarjetas"
|
||||
},
|
||||
"background-color": {
|
||||
"label": "Color de fondo",
|
||||
"description": "Color de la superposición oscurecida"
|
||||
},
|
||||
"background-opacity": {
|
||||
"label": "Opacidad del fondo",
|
||||
"description": "Opacidad de la superposición oscurecida"
|
||||
},
|
||||
"window-animation-speed": {
|
||||
"label": "Velocidad de animación de ventana",
|
||||
"description": "Velocidad de las transiciones de abrir y cerrar"
|
||||
},
|
||||
"animate-window": {
|
||||
"label": "Animación de ventana",
|
||||
"description": "Animar las transiciones de abrir y cerrar"
|
||||
},
|
||||
"top-bar-height": {
|
||||
"label": "Altura de barra superior",
|
||||
"description": "Altura de la barra de herramientas"
|
||||
}
|
||||
},
|
||||
"shortcuts": {
|
||||
"key-separator": "/",
|
||||
"header": {
|
||||
"navigation": "NAVEGACIÓN",
|
||||
"actions": "ACCIONES",
|
||||
"filters": "FILTROS",
|
||||
"view": "VISTA",
|
||||
"layout": "DISEÑO"
|
||||
},
|
||||
"label": {
|
||||
"help-title": "Atajos",
|
||||
"navigate": "Navegar",
|
||||
"jump": "Saltar",
|
||||
"shuffle": "Mezclar",
|
||||
"apply-quit": "Aplicar + Cerrar",
|
||||
"apply": "Aplicar",
|
||||
"quit": "Cerrar",
|
||||
"filter-all": "Todos",
|
||||
"filter-images": "Imágenes",
|
||||
"filter-videos": "Vídeos",
|
||||
"filter-colors": "Filtro de color",
|
||||
"top-bar": "Barra superior",
|
||||
"live-preview": "Vista previa",
|
||||
"center-height": "Altura central",
|
||||
"center-width": "Ancho central",
|
||||
"cards-shown": "Tarjetas visibles",
|
||||
"cards-spacing": "Espaciado",
|
||||
"cards-width": "Ancho de tarjetas",
|
||||
"save": "Guardar ajustes",
|
||||
"hide": "Ocultar"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
{
|
||||
"buttons": {
|
||||
"all": "Tous",
|
||||
"images": "Images",
|
||||
"videos": "Vidéos",
|
||||
"shuffle": "Mélanger",
|
||||
"live-preview": "En direct",
|
||||
"color-na": "✕"
|
||||
},
|
||||
"widget": {
|
||||
"tooltip": "Ouvrir Wallcards",
|
||||
"generate-thumbs-message": "Génération des miniatures…"
|
||||
},
|
||||
"settings": {
|
||||
"icon-color": {
|
||||
"label": "Couleur de l'icône",
|
||||
"description": "Couleur de l'icône du widget de barre"
|
||||
},
|
||||
"live-preview": {
|
||||
"label": "Aperçu en direct",
|
||||
"description": "Appliquer le fond d'écran en parcourant les cartes"
|
||||
},
|
||||
"default-filter": {
|
||||
"label": "Filtre par défaut",
|
||||
"description": "Filtre de type de fichier initial à l'ouverture"
|
||||
},
|
||||
"hide-shortcuts": {
|
||||
"label": "Masquer les raccourcis",
|
||||
"description": "Masquer le panneau des raccourcis clavier"
|
||||
},
|
||||
"hide-top-bar": {
|
||||
"label": "Masquer la barre supérieure",
|
||||
"description": "Masquer la barre d'outils au-dessus des cartes"
|
||||
},
|
||||
"center-card-width": {
|
||||
"label": "Largeur de la carte centrale",
|
||||
"description": "Largeur de la carte centrale en pourcentage de l'écran"
|
||||
},
|
||||
"card-height": {
|
||||
"label": "Hauteur des cartes",
|
||||
"description": "Hauteur des cartes de fond d'écran"
|
||||
},
|
||||
"strip-width": {
|
||||
"label": "Largeur des bandes",
|
||||
"description": "Largeur des bandes latérales"
|
||||
},
|
||||
"card-spacing": {
|
||||
"label": "Espacement des cartes",
|
||||
"description": "Espace entre les cartes"
|
||||
},
|
||||
"cards-shown": {
|
||||
"label": "Cartes affichées",
|
||||
"description": "Nombre de cartes visibles (nombres impairs recommandés)"
|
||||
},
|
||||
"shear-factor": {
|
||||
"label": "Facteur de cisaillement",
|
||||
"description": "Angle d'inclinaison de la disposition des cartes"
|
||||
},
|
||||
"card-animation": {
|
||||
"label": "Animation des cartes",
|
||||
"description": "Vitesse des transitions de cartes"
|
||||
},
|
||||
"background-color": {
|
||||
"label": "Couleur de fond",
|
||||
"description": "Couleur de la superposition assombrie"
|
||||
},
|
||||
"background-opacity": {
|
||||
"label": "Opacité du fond",
|
||||
"description": "Opacité de la superposition assombrie"
|
||||
},
|
||||
"window-animation-speed": {
|
||||
"label": "Vitesse d'animation de la fenêtre",
|
||||
"description": "Vitesse des transitions d'ouverture et de fermeture"
|
||||
},
|
||||
"animate-window": {
|
||||
"label": "Animation de la fenêtre",
|
||||
"description": "Animer les transitions d'ouverture et de fermeture"
|
||||
},
|
||||
"top-bar-height": {
|
||||
"label": "Hauteur de la barre supérieure",
|
||||
"description": "Hauteur de la barre d'outils"
|
||||
}
|
||||
},
|
||||
"shortcuts": {
|
||||
"key-separator": "/",
|
||||
"header": {
|
||||
"navigation": "NAVIGATION",
|
||||
"actions": "ACTIONS",
|
||||
"filters": "FILTRES",
|
||||
"view": "AFFICHAGE",
|
||||
"layout": "DISPOSITION"
|
||||
},
|
||||
"label": {
|
||||
"help-title": "Raccourcis",
|
||||
"navigate": "Naviguer",
|
||||
"jump": "Sauter",
|
||||
"shuffle": "Mélanger",
|
||||
"apply-quit": "Appliquer + Quitter",
|
||||
"apply": "Appliquer",
|
||||
"quit": "Quitter",
|
||||
"filter-all": "Tous",
|
||||
"filter-images": "Images",
|
||||
"filter-videos": "Vidéos",
|
||||
"filter-colors": "Filtre couleur",
|
||||
"top-bar": "Barre supérieure",
|
||||
"live-preview": "Aperçu en direct",
|
||||
"center-height": "Hauteur centrale",
|
||||
"center-width": "Largeur centrale",
|
||||
"cards-shown": "Cartes affichées",
|
||||
"cards-spacing": "Espacement",
|
||||
"cards-width": "Largeur des cartes",
|
||||
"save": "Enregistrer",
|
||||
"hide": "Masquer"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
{
|
||||
"buttons": {
|
||||
"all": "Összes",
|
||||
"images": "Képek",
|
||||
"videos": "Videók",
|
||||
"shuffle": "Keverés",
|
||||
"live-preview": "Élő",
|
||||
"color-na": "✕"
|
||||
},
|
||||
"widget": {
|
||||
"tooltip": "Wallcards megnyitása",
|
||||
"generate-thumbs-message": "Miniatűrök létrehozása…"
|
||||
},
|
||||
"settings": {
|
||||
"icon-color": {
|
||||
"label": "Ikon színe",
|
||||
"description": "A sáv widget ikonjának színe"
|
||||
},
|
||||
"live-preview": {
|
||||
"label": "Élő előnézet",
|
||||
"description": "Háttérkép alkalmazása böngészés közben"
|
||||
},
|
||||
"default-filter": {
|
||||
"label": "Alapértelmezett szűrő",
|
||||
"description": "Kezdeti fájltípus-szűrő megnyitáskor"
|
||||
},
|
||||
"hide-shortcuts": {
|
||||
"label": "Gyorsbillentyűk elrejtése",
|
||||
"description": "A gyorsbillentyűk panel elrejtése"
|
||||
},
|
||||
"hide-top-bar": {
|
||||
"label": "Felső sáv elrejtése",
|
||||
"description": "Az eszköztár elrejtése a kártyák felett"
|
||||
},
|
||||
"center-card-width": {
|
||||
"label": "Középső kártya szélessége",
|
||||
"description": "A középső kártya szélessége a képernyő százalékában"
|
||||
},
|
||||
"card-height": {
|
||||
"label": "Kártya magassága",
|
||||
"description": "A háttérkép-kártyák magassága"
|
||||
},
|
||||
"strip-width": {
|
||||
"label": "Csík szélessége",
|
||||
"description": "Az oldalsó kártyacsíkok szélessége"
|
||||
},
|
||||
"card-spacing": {
|
||||
"label": "Kártyák térköze",
|
||||
"description": "Kártyák közötti rés"
|
||||
},
|
||||
"cards-shown": {
|
||||
"label": "Megjelenített kártyák",
|
||||
"description": "Látható kártyák száma (páratlan számok ajánlottak)"
|
||||
},
|
||||
"shear-factor": {
|
||||
"label": "Nyírási tényező",
|
||||
"description": "A kártya-elrendezés döntési szöge"
|
||||
},
|
||||
"card-animation": {
|
||||
"label": "Kártya animáció",
|
||||
"description": "Kártyaátmenetek sebessége"
|
||||
},
|
||||
"background-color": {
|
||||
"label": "Háttérszín",
|
||||
"description": "A sötétített fedőréteg színe"
|
||||
},
|
||||
"background-opacity": {
|
||||
"label": "Háttér átlátszatlansága",
|
||||
"description": "A sötétített fedőréteg átlátszatlansága"
|
||||
},
|
||||
"window-animation-speed": {
|
||||
"label": "Ablak animáció sebessége",
|
||||
"description": "A nyitás és zárás átmenetek sebessége"
|
||||
},
|
||||
"animate-window": {
|
||||
"label": "Ablak animáció",
|
||||
"description": "Nyitás és zárás átmenetek animálása"
|
||||
},
|
||||
"top-bar-height": {
|
||||
"label": "Felső sáv magassága",
|
||||
"description": "Az eszköztár magassága"
|
||||
}
|
||||
},
|
||||
"shortcuts": {
|
||||
"key-separator": "/",
|
||||
"header": {
|
||||
"navigation": "NAVIGÁCIÓ",
|
||||
"actions": "MŰVELETEK",
|
||||
"filters": "SZŰRŐK",
|
||||
"view": "NÉZET",
|
||||
"layout": "ELRENDEZÉS"
|
||||
},
|
||||
"label": {
|
||||
"help-title": "Gyorsbillentyűk",
|
||||
"navigate": "Navigálás",
|
||||
"jump": "Ugrás",
|
||||
"shuffle": "Keverés",
|
||||
"apply-quit": "Alkalmazás + Kilépés",
|
||||
"apply": "Alkalmazás",
|
||||
"quit": "Kilépés",
|
||||
"filter-all": "Összes",
|
||||
"filter-images": "Képek",
|
||||
"filter-videos": "Videók",
|
||||
"filter-colors": "Színszűrő",
|
||||
"top-bar": "Felső sáv",
|
||||
"live-preview": "Élő előnézet",
|
||||
"center-height": "Középső magasság",
|
||||
"center-width": "Középső szélesség",
|
||||
"cards-shown": "Megjelenített kártyák",
|
||||
"cards-spacing": "Térköz",
|
||||
"cards-width": "Kártyák szélessége",
|
||||
"save": "Beállítások mentése",
|
||||
"hide": "Elrejtés"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
{
|
||||
"buttons": {
|
||||
"all": "Tutti",
|
||||
"images": "Immagini",
|
||||
"videos": "Video",
|
||||
"shuffle": "Mescola",
|
||||
"live-preview": "Live",
|
||||
"color-na": "✕"
|
||||
},
|
||||
"widget": {
|
||||
"tooltip": "Apri Wallcards",
|
||||
"generate-thumbs-message": "Generazione miniature…"
|
||||
},
|
||||
"settings": {
|
||||
"icon-color": {
|
||||
"label": "Colore icona",
|
||||
"description": "Colore dell'icona del widget della barra"
|
||||
},
|
||||
"live-preview": {
|
||||
"label": "Anteprima dal vivo",
|
||||
"description": "Applica lo sfondo durante la navigazione delle schede"
|
||||
},
|
||||
"default-filter": {
|
||||
"label": "Filtro predefinito",
|
||||
"description": "Filtro tipo file iniziale all'apertura"
|
||||
},
|
||||
"hide-shortcuts": {
|
||||
"label": "Nascondi scorciatoie",
|
||||
"description": "Nascondi il pannello delle scorciatoie da tastiera"
|
||||
},
|
||||
"hide-top-bar": {
|
||||
"label": "Nascondi barra superiore",
|
||||
"description": "Nascondi la barra degli strumenti sopra le schede"
|
||||
},
|
||||
"center-card-width": {
|
||||
"label": "Larghezza scheda centrale",
|
||||
"description": "Larghezza della scheda centrale in percentuale dello schermo"
|
||||
},
|
||||
"card-height": {
|
||||
"label": "Altezza scheda",
|
||||
"description": "Altezza delle schede sfondo"
|
||||
},
|
||||
"strip-width": {
|
||||
"label": "Larghezza striscia",
|
||||
"description": "Larghezza delle strisce laterali"
|
||||
},
|
||||
"card-spacing": {
|
||||
"label": "Spaziatura schede",
|
||||
"description": "Distanza tra le schede"
|
||||
},
|
||||
"cards-shown": {
|
||||
"label": "Schede visibili",
|
||||
"description": "Numero di schede visibili (numeri dispari consigliati)"
|
||||
},
|
||||
"shear-factor": {
|
||||
"label": "Fattore di taglio",
|
||||
"description": "Angolo di inclinazione del layout delle schede"
|
||||
},
|
||||
"card-animation": {
|
||||
"label": "Animazione schede",
|
||||
"description": "Velocità delle transizioni delle schede"
|
||||
},
|
||||
"background-color": {
|
||||
"label": "Colore di sfondo",
|
||||
"description": "Colore della sovrapposizione oscurata"
|
||||
},
|
||||
"background-opacity": {
|
||||
"label": "Opacità dello sfondo",
|
||||
"description": "Opacità della sovrapposizione oscurata"
|
||||
},
|
||||
"window-animation-speed": {
|
||||
"label": "Velocità animazione finestra",
|
||||
"description": "Velocità delle transizioni di apertura e chiusura"
|
||||
},
|
||||
"animate-window": {
|
||||
"label": "Animazione finestra",
|
||||
"description": "Anima le transizioni di apertura e chiusura"
|
||||
},
|
||||
"top-bar-height": {
|
||||
"label": "Altezza barra superiore",
|
||||
"description": "Altezza della barra degli strumenti"
|
||||
}
|
||||
},
|
||||
"shortcuts": {
|
||||
"key-separator": "/",
|
||||
"header": {
|
||||
"navigation": "NAVIGAZIONE",
|
||||
"actions": "AZIONI",
|
||||
"filters": "FILTRI",
|
||||
"view": "VISTA",
|
||||
"layout": "LAYOUT"
|
||||
},
|
||||
"label": {
|
||||
"help-title": "Scorciatoie",
|
||||
"navigate": "Naviga",
|
||||
"jump": "Salta",
|
||||
"shuffle": "Mescola",
|
||||
"apply-quit": "Applica + Esci",
|
||||
"apply": "Applica",
|
||||
"quit": "Esci",
|
||||
"filter-all": "Tutti",
|
||||
"filter-images": "Immagini",
|
||||
"filter-videos": "Video",
|
||||
"filter-colors": "Filtro colore",
|
||||
"top-bar": "Barra superiore",
|
||||
"live-preview": "Anteprima dal vivo",
|
||||
"center-height": "Altezza centrale",
|
||||
"center-width": "Larghezza centrale",
|
||||
"cards-shown": "Schede visibili",
|
||||
"cards-spacing": "Spaziatura",
|
||||
"cards-width": "Larghezza schede",
|
||||
"save": "Salva impostazioni",
|
||||
"hide": "Nascondi"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
{
|
||||
"buttons": {
|
||||
"all": "すべて",
|
||||
"images": "画像",
|
||||
"videos": "動画",
|
||||
"shuffle": "シャッフル",
|
||||
"live-preview": "ライブ",
|
||||
"color-na": "✕"
|
||||
},
|
||||
"widget": {
|
||||
"tooltip": "Wallcardsを開く",
|
||||
"generate-thumbs-message": "サムネイルを生成中…"
|
||||
},
|
||||
"settings": {
|
||||
"icon-color": {
|
||||
"label": "アイコンの色",
|
||||
"description": "バーウィジェットのアイコンの色"
|
||||
},
|
||||
"live-preview": {
|
||||
"label": "ライブプレビュー",
|
||||
"description": "カードを閲覧しながら壁紙を適用"
|
||||
},
|
||||
"default-filter": {
|
||||
"label": "デフォルトフィルター",
|
||||
"description": "起動時のファイルタイプフィルター"
|
||||
},
|
||||
"hide-shortcuts": {
|
||||
"label": "ショートカットを非表示",
|
||||
"description": "キーボードショートカットパネルを非表示"
|
||||
},
|
||||
"hide-top-bar": {
|
||||
"label": "トップバーを非表示",
|
||||
"description": "カード上部のツールバーを非表示"
|
||||
},
|
||||
"center-card-width": {
|
||||
"label": "中央カードの幅",
|
||||
"description": "画面に対する中央カードの幅の割合"
|
||||
},
|
||||
"card-height": {
|
||||
"label": "カードの高さ",
|
||||
"description": "壁紙カードの高さ"
|
||||
},
|
||||
"strip-width": {
|
||||
"label": "ストリップ幅",
|
||||
"description": "サイドカードストリップの幅"
|
||||
},
|
||||
"card-spacing": {
|
||||
"label": "カード間隔",
|
||||
"description": "カード間のスペース"
|
||||
},
|
||||
"cards-shown": {
|
||||
"label": "表示カード数",
|
||||
"description": "表示するカードの数(奇数推奨)"
|
||||
},
|
||||
"shear-factor": {
|
||||
"label": "せん断係数",
|
||||
"description": "カードレイアウトの傾斜角度"
|
||||
},
|
||||
"card-animation": {
|
||||
"label": "カードアニメーション",
|
||||
"description": "カード遷移の速度"
|
||||
},
|
||||
"background-color": {
|
||||
"label": "背景色",
|
||||
"description": "暗転オーバーレイの色"
|
||||
},
|
||||
"background-opacity": {
|
||||
"label": "背景の不透明度",
|
||||
"description": "暗転オーバーレイの不透明度"
|
||||
},
|
||||
"window-animation-speed": {
|
||||
"label": "ウィンドウアニメーション速度",
|
||||
"description": "開閉時の遷移速度"
|
||||
},
|
||||
"animate-window": {
|
||||
"label": "ウィンドウアニメーション",
|
||||
"description": "開閉時の遷移をアニメーション化"
|
||||
},
|
||||
"top-bar-height": {
|
||||
"label": "トップバーの高さ",
|
||||
"description": "ツールバーの高さ"
|
||||
}
|
||||
},
|
||||
"shortcuts": {
|
||||
"key-separator": "/",
|
||||
"header": {
|
||||
"navigation": "ナビゲーション",
|
||||
"actions": "アクション",
|
||||
"filters": "フィルター",
|
||||
"view": "表示",
|
||||
"layout": "レイアウト"
|
||||
},
|
||||
"label": {
|
||||
"help-title": "ショートカット",
|
||||
"navigate": "移動",
|
||||
"jump": "ジャンプ",
|
||||
"shuffle": "シャッフル",
|
||||
"apply-quit": "適用して終了",
|
||||
"apply": "適用",
|
||||
"quit": "終了",
|
||||
"filter-all": "すべて",
|
||||
"filter-images": "画像",
|
||||
"filter-videos": "動画",
|
||||
"filter-colors": "カラーフィルター",
|
||||
"top-bar": "トップバー切替",
|
||||
"live-preview": "ライブプレビュー切替",
|
||||
"center-height": "中央の高さ",
|
||||
"center-width": "中央の幅",
|
||||
"cards-shown": "表示カード数",
|
||||
"cards-spacing": "間隔",
|
||||
"cards-width": "カード幅",
|
||||
"save": "設定を保存",
|
||||
"hide": "非表示"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
{
|
||||
"buttons": {
|
||||
"all": "Hemû",
|
||||
"images": "Wêne",
|
||||
"videos": "Vîdeo",
|
||||
"shuffle": "Tevlihev",
|
||||
"live-preview": "Zindî",
|
||||
"color-na": "✕"
|
||||
},
|
||||
"widget": {
|
||||
"tooltip": "Wallcards veke",
|
||||
"generate-thumbs-message": "Wêneyên biçûk têne çêkirin…"
|
||||
},
|
||||
"settings": {
|
||||
"icon-color": {
|
||||
"label": "Rengê îkonê",
|
||||
"description": "Rengê îkona wîceta barê"
|
||||
},
|
||||
"live-preview": {
|
||||
"label": "Pêşdîtina zindî",
|
||||
"description": "Dîwarê bi kar bîne dema ku kartên digerin"
|
||||
},
|
||||
"default-filter": {
|
||||
"label": "Parzûna standard",
|
||||
"description": "Parzûna celebê pelê ya destpêkê dema vekirinê"
|
||||
},
|
||||
"hide-shortcuts": {
|
||||
"label": "Kurterêyan veşêre",
|
||||
"description": "Panela kurterêyên klavyeyê veşêre"
|
||||
},
|
||||
"hide-top-bar": {
|
||||
"label": "Barê jorîn veşêre",
|
||||
"description": "Amûrbarê li ser kartan veşêre"
|
||||
},
|
||||
"center-card-width": {
|
||||
"label": "Firehiya karta navendî",
|
||||
"description": "Firehiya karta navendî wek sedî ya ekranê"
|
||||
},
|
||||
"card-height": {
|
||||
"label": "Bilindahiya kartê",
|
||||
"description": "Bilindahiya kartên dîwarê"
|
||||
},
|
||||
"strip-width": {
|
||||
"label": "Firehiya şirîtê",
|
||||
"description": "Firehiya şirîtên kartên alî"
|
||||
},
|
||||
"card-spacing": {
|
||||
"label": "Navbera kartan",
|
||||
"description": "Valahiya di navbera kartan de"
|
||||
},
|
||||
"cards-shown": {
|
||||
"label": "Kartên xuya",
|
||||
"description": "Hejmara kartên xuya (jimarên taq têne pêşniyar kirin)"
|
||||
},
|
||||
"shear-factor": {
|
||||
"label": "Faktora qutkirinê",
|
||||
"description": "Goşeya meylkirina sêwirana kartan"
|
||||
},
|
||||
"card-animation": {
|
||||
"label": "Anîmasyona kartê",
|
||||
"description": "Leza veguheztinên kartan"
|
||||
},
|
||||
"background-color": {
|
||||
"label": "Rengê paşperdê",
|
||||
"description": "Rengê tebeqa tarîkirî"
|
||||
},
|
||||
"background-opacity": {
|
||||
"label": "Zelalbûna paşperdê",
|
||||
"description": "Zelalbûna tebeqa tarîkirî"
|
||||
},
|
||||
"window-animation-speed": {
|
||||
"label": "Leza anîmasyona pencereyê",
|
||||
"description": "Leza veguheztinên vekirî û girtî"
|
||||
},
|
||||
"animate-window": {
|
||||
"label": "Anîmasyona pencereyê",
|
||||
"description": "Veguheztinên vekirî û girtî bianîme"
|
||||
},
|
||||
"top-bar-height": {
|
||||
"label": "Bilindahiya barê jorîn",
|
||||
"description": "Bilindahiya amûrbarê"
|
||||
}
|
||||
},
|
||||
"shortcuts": {
|
||||
"key-separator": "/",
|
||||
"header": {
|
||||
"navigation": "NAVÎGASYON",
|
||||
"actions": "ÇALAKÎ",
|
||||
"filters": "PARZÛN",
|
||||
"view": "DÎTIN",
|
||||
"layout": "SÊWIRAN"
|
||||
},
|
||||
"label": {
|
||||
"help-title": "Kurterê",
|
||||
"navigate": "Navîgasyon",
|
||||
"jump": "Bazdan",
|
||||
"shuffle": "Tevlihev",
|
||||
"apply-quit": "Bicîh bîne + Derkeve",
|
||||
"apply": "Bicîh bîne",
|
||||
"quit": "Derkeve",
|
||||
"filter-all": "Hemû",
|
||||
"filter-images": "Wêne",
|
||||
"filter-videos": "Vîdeo",
|
||||
"filter-colors": "Parzûna rengan",
|
||||
"top-bar": "Barê jorîn",
|
||||
"live-preview": "Pêşdîtina zindî",
|
||||
"center-height": "Bilindahiya navendî",
|
||||
"center-width": "Firehiya navendî",
|
||||
"cards-shown": "Kartên xuya",
|
||||
"cards-spacing": "Navber",
|
||||
"cards-width": "Firehiya kartan",
|
||||
"save": "Mîhengan tomar bike",
|
||||
"hide": "Veşêre"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
{
|
||||
"buttons": {
|
||||
"all": "Alles",
|
||||
"images": "Afbeeldingen",
|
||||
"videos": "Video's",
|
||||
"shuffle": "Willekeurig",
|
||||
"live-preview": "Live",
|
||||
"color-na": "✕"
|
||||
},
|
||||
"widget": {
|
||||
"tooltip": "Wallcards openen",
|
||||
"generate-thumbs-message": "Miniaturen genereren…"
|
||||
},
|
||||
"settings": {
|
||||
"icon-color": {
|
||||
"label": "Pictogramkleur",
|
||||
"description": "Kleur van het balkwidget-pictogram"
|
||||
},
|
||||
"live-preview": {
|
||||
"label": "Live voorbeeld",
|
||||
"description": "Achtergrond toepassen tijdens het bladeren"
|
||||
},
|
||||
"default-filter": {
|
||||
"label": "Standaardfilter",
|
||||
"description": "Initieel bestandstypefilter bij openen"
|
||||
},
|
||||
"hide-shortcuts": {
|
||||
"label": "Sneltoetsen verbergen",
|
||||
"description": "Het sneltoetsenpaneel verbergen"
|
||||
},
|
||||
"hide-top-bar": {
|
||||
"label": "Bovenste balk verbergen",
|
||||
"description": "De werkbalk boven de kaarten verbergen"
|
||||
},
|
||||
"center-card-width": {
|
||||
"label": "Breedte middelste kaart",
|
||||
"description": "Breedte van de middelste kaart als percentage van het scherm"
|
||||
},
|
||||
"card-height": {
|
||||
"label": "Kaarthoogte",
|
||||
"description": "Hoogte van de achtergrondkaarten"
|
||||
},
|
||||
"strip-width": {
|
||||
"label": "Stripbreedte",
|
||||
"description": "Breedte van de zijstroken"
|
||||
},
|
||||
"card-spacing": {
|
||||
"label": "Kaartafstand",
|
||||
"description": "Ruimte tussen kaarten"
|
||||
},
|
||||
"cards-shown": {
|
||||
"label": "Zichtbare kaarten",
|
||||
"description": "Aantal zichtbare kaarten (oneven aantallen aanbevolen)"
|
||||
},
|
||||
"shear-factor": {
|
||||
"label": "Schuinfactor",
|
||||
"description": "Hellingshoek van de kaartindeling"
|
||||
},
|
||||
"card-animation": {
|
||||
"label": "Kaartanimatie",
|
||||
"description": "Snelheid van kaartovergangen"
|
||||
},
|
||||
"background-color": {
|
||||
"label": "Achtergrondkleur",
|
||||
"description": "Kleur van de verduisterde overlay"
|
||||
},
|
||||
"background-opacity": {
|
||||
"label": "Achtergrond-dekking",
|
||||
"description": "Dekking van de verduisterde overlay"
|
||||
},
|
||||
"window-animation-speed": {
|
||||
"label": "Vensteranimatiesnelheid",
|
||||
"description": "Snelheid van open- en sluitovergangen"
|
||||
},
|
||||
"animate-window": {
|
||||
"label": "Vensteranimatie",
|
||||
"description": "Open- en sluitovergangen animeren"
|
||||
},
|
||||
"top-bar-height": {
|
||||
"label": "Hoogte bovenste balk",
|
||||
"description": "Hoogte van de werkbalk"
|
||||
}
|
||||
},
|
||||
"shortcuts": {
|
||||
"key-separator": "/",
|
||||
"header": {
|
||||
"navigation": "NAVIGATIE",
|
||||
"actions": "ACTIES",
|
||||
"filters": "FILTERS",
|
||||
"view": "WEERGAVE",
|
||||
"layout": "INDELING"
|
||||
},
|
||||
"label": {
|
||||
"help-title": "Sneltoetsen",
|
||||
"navigate": "Navigeren",
|
||||
"jump": "Springen",
|
||||
"shuffle": "Willekeurig",
|
||||
"apply-quit": "Toepassen + Sluiten",
|
||||
"apply": "Toepassen",
|
||||
"quit": "Sluiten",
|
||||
"filter-all": "Alles",
|
||||
"filter-images": "Afbeeldingen",
|
||||
"filter-videos": "Video's",
|
||||
"filter-colors": "Kleurfilter",
|
||||
"top-bar": "Bovenste balk",
|
||||
"live-preview": "Live voorbeeld",
|
||||
"center-height": "Middenhoogte",
|
||||
"center-width": "Middenbreedte",
|
||||
"cards-shown": "Zichtbare kaarten",
|
||||
"cards-spacing": "Afstand",
|
||||
"cards-width": "Kaartbreedte",
|
||||
"save": "Instellingen opslaan",
|
||||
"hide": "Verbergen"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
{
|
||||
"buttons": {
|
||||
"all": "Wszystkie",
|
||||
"images": "Obrazy",
|
||||
"videos": "Filmy",
|
||||
"shuffle": "Losuj",
|
||||
"live-preview": "Na żywo",
|
||||
"color-na": "✕"
|
||||
},
|
||||
"widget": {
|
||||
"tooltip": "Otwórz Wallcards",
|
||||
"generate-thumbs-message": "Generowanie miniatur…"
|
||||
},
|
||||
"settings": {
|
||||
"icon-color": {
|
||||
"label": "Kolor ikony",
|
||||
"description": "Kolor ikony widżetu paska"
|
||||
},
|
||||
"live-preview": {
|
||||
"label": "Podgląd na żywo",
|
||||
"description": "Zastosuj tapetę podczas przeglądania kart"
|
||||
},
|
||||
"default-filter": {
|
||||
"label": "Domyślny filtr",
|
||||
"description": "Początkowy filtr typu pliku przy otwieraniu"
|
||||
},
|
||||
"hide-shortcuts": {
|
||||
"label": "Ukryj skróty",
|
||||
"description": "Ukryj panel skrótów klawiszowych"
|
||||
},
|
||||
"hide-top-bar": {
|
||||
"label": "Ukryj górny pasek",
|
||||
"description": "Ukryj pasek narzędzi nad kartami"
|
||||
},
|
||||
"center-card-width": {
|
||||
"label": "Szerokość środkowej karty",
|
||||
"description": "Szerokość środkowej karty jako procent ekranu"
|
||||
},
|
||||
"card-height": {
|
||||
"label": "Wysokość karty",
|
||||
"description": "Wysokość kart tapet"
|
||||
},
|
||||
"strip-width": {
|
||||
"label": "Szerokość paska",
|
||||
"description": "Szerokość bocznych pasków kart"
|
||||
},
|
||||
"card-spacing": {
|
||||
"label": "Odstęp kart",
|
||||
"description": "Przerwa między kartami"
|
||||
},
|
||||
"cards-shown": {
|
||||
"label": "Widoczne karty",
|
||||
"description": "Liczba widocznych kart (zalecane liczby nieparzyste)"
|
||||
},
|
||||
"shear-factor": {
|
||||
"label": "Współczynnik ścinania",
|
||||
"description": "Kąt pochylenia układu kart"
|
||||
},
|
||||
"card-animation": {
|
||||
"label": "Animacja kart",
|
||||
"description": "Szybkość przejść kart"
|
||||
},
|
||||
"background-color": {
|
||||
"label": "Kolor tła",
|
||||
"description": "Kolor przyciemnionej nakładki"
|
||||
},
|
||||
"background-opacity": {
|
||||
"label": "Nieprzezroczystość tła",
|
||||
"description": "Nieprzezroczystość przyciemnionej nakładki"
|
||||
},
|
||||
"window-animation-speed": {
|
||||
"label": "Szybkość animacji okna",
|
||||
"description": "Szybkość przejść otwierania i zamykania"
|
||||
},
|
||||
"animate-window": {
|
||||
"label": "Animacja okna",
|
||||
"description": "Animuj przejścia otwierania i zamykania"
|
||||
},
|
||||
"top-bar-height": {
|
||||
"label": "Wysokość górnego paska",
|
||||
"description": "Wysokość paska narzędzi"
|
||||
}
|
||||
},
|
||||
"shortcuts": {
|
||||
"key-separator": "/",
|
||||
"header": {
|
||||
"navigation": "NAWIGACJA",
|
||||
"actions": "AKCJE",
|
||||
"filters": "FILTRY",
|
||||
"view": "WIDOK",
|
||||
"layout": "UKŁAD"
|
||||
},
|
||||
"label": {
|
||||
"help-title": "Skróty",
|
||||
"navigate": "Nawiguj",
|
||||
"jump": "Skocz",
|
||||
"shuffle": "Losuj",
|
||||
"apply-quit": "Zastosuj + Zamknij",
|
||||
"apply": "Zastosuj",
|
||||
"quit": "Zamknij",
|
||||
"filter-all": "Wszystkie",
|
||||
"filter-images": "Obrazy",
|
||||
"filter-videos": "Filmy",
|
||||
"filter-colors": "Filtr kolorów",
|
||||
"top-bar": "Górny pasek",
|
||||
"live-preview": "Podgląd na żywo",
|
||||
"center-height": "Wysokość środka",
|
||||
"center-width": "Szerokość środka",
|
||||
"cards-shown": "Widoczne karty",
|
||||
"cards-spacing": "Odstęp",
|
||||
"cards-width": "Szerokość kart",
|
||||
"save": "Zapisz ustawienia",
|
||||
"hide": "Ukryj"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
{
|
||||
"buttons": {
|
||||
"all": "Todos",
|
||||
"images": "Imagens",
|
||||
"videos": "Vídeos",
|
||||
"shuffle": "Aleatório",
|
||||
"live-preview": "Ao vivo",
|
||||
"color-na": "✕"
|
||||
},
|
||||
"widget": {
|
||||
"tooltip": "Abrir Wallcards",
|
||||
"generate-thumbs-message": "Gerando miniaturas…"
|
||||
},
|
||||
"settings": {
|
||||
"icon-color": {
|
||||
"label": "Cor do ícone",
|
||||
"description": "Cor do ícone do widget da barra"
|
||||
},
|
||||
"live-preview": {
|
||||
"label": "Pré-visualização ao vivo",
|
||||
"description": "Aplicar papel de parede enquanto navega pelos cartões"
|
||||
},
|
||||
"default-filter": {
|
||||
"label": "Filtro padrão",
|
||||
"description": "Filtro de tipo de arquivo inicial ao abrir"
|
||||
},
|
||||
"hide-shortcuts": {
|
||||
"label": "Ocultar atalhos",
|
||||
"description": "Ocultar o painel de atalhos de teclado"
|
||||
},
|
||||
"hide-top-bar": {
|
||||
"label": "Ocultar barra superior",
|
||||
"description": "Ocultar a barra de ferramentas acima dos cartões"
|
||||
},
|
||||
"center-card-width": {
|
||||
"label": "Largura do cartão central",
|
||||
"description": "Largura do cartão central como porcentagem da tela"
|
||||
},
|
||||
"card-height": {
|
||||
"label": "Altura do cartão",
|
||||
"description": "Altura dos cartões de papel de parede"
|
||||
},
|
||||
"strip-width": {
|
||||
"label": "Largura da faixa",
|
||||
"description": "Largura das faixas laterais dos cartões"
|
||||
},
|
||||
"card-spacing": {
|
||||
"label": "Espaçamento dos cartões",
|
||||
"description": "Espaço entre os cartões"
|
||||
},
|
||||
"cards-shown": {
|
||||
"label": "Cartões visíveis",
|
||||
"description": "Número de cartões visíveis (números ímpares recomendados)"
|
||||
},
|
||||
"shear-factor": {
|
||||
"label": "Fator de cisalhamento",
|
||||
"description": "Ângulo de inclinação do layout dos cartões"
|
||||
},
|
||||
"card-animation": {
|
||||
"label": "Animação dos cartões",
|
||||
"description": "Velocidade das transições dos cartões"
|
||||
},
|
||||
"background-color": {
|
||||
"label": "Cor de fundo",
|
||||
"description": "Cor da sobreposição escurecida"
|
||||
},
|
||||
"background-opacity": {
|
||||
"label": "Opacidade do fundo",
|
||||
"description": "Opacidade da sobreposição escurecida"
|
||||
},
|
||||
"window-animation-speed": {
|
||||
"label": "Velocidade da animação da janela",
|
||||
"description": "Velocidade das transições de abrir e fechar"
|
||||
},
|
||||
"animate-window": {
|
||||
"label": "Animação da janela",
|
||||
"description": "Animar as transições de abrir e fechar"
|
||||
},
|
||||
"top-bar-height": {
|
||||
"label": "Altura da barra superior",
|
||||
"description": "Altura da barra de ferramentas"
|
||||
}
|
||||
},
|
||||
"shortcuts": {
|
||||
"key-separator": "/",
|
||||
"header": {
|
||||
"navigation": "NAVEGAÇÃO",
|
||||
"actions": "AÇÕES",
|
||||
"filters": "FILTROS",
|
||||
"view": "VISUALIZAÇÃO",
|
||||
"layout": "LAYOUT"
|
||||
},
|
||||
"label": {
|
||||
"help-title": "Atalhos",
|
||||
"navigate": "Navegar",
|
||||
"jump": "Saltar",
|
||||
"shuffle": "Aleatório",
|
||||
"apply-quit": "Aplicar + Fechar",
|
||||
"apply": "Aplicar",
|
||||
"quit": "Fechar",
|
||||
"filter-all": "Todos",
|
||||
"filter-images": "Imagens",
|
||||
"filter-videos": "Vídeos",
|
||||
"filter-colors": "Filtro de cor",
|
||||
"top-bar": "Barra superior",
|
||||
"live-preview": "Pré-visualização",
|
||||
"center-height": "Altura central",
|
||||
"center-width": "Largura central",
|
||||
"cards-shown": "Cartões visíveis",
|
||||
"cards-spacing": "Espaçamento",
|
||||
"cards-width": "Largura dos cartões",
|
||||
"save": "Salvar configurações",
|
||||
"hide": "Ocultar"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
{
|
||||
"buttons": {
|
||||
"all": "Все",
|
||||
"images": "Изображения",
|
||||
"videos": "Видео",
|
||||
"shuffle": "Перемешать",
|
||||
"live-preview": "Живой",
|
||||
"color-na": "✕"
|
||||
},
|
||||
"widget": {
|
||||
"tooltip": "Открыть Wallcards",
|
||||
"generate-thumbs-message": "Создание миниатюр…"
|
||||
},
|
||||
"settings": {
|
||||
"icon-color": {
|
||||
"label": "Цвет значка",
|
||||
"description": "Цвет значка виджета панели"
|
||||
},
|
||||
"live-preview": {
|
||||
"label": "Предпросмотр",
|
||||
"description": "Применять обои при просмотре карточек"
|
||||
},
|
||||
"default-filter": {
|
||||
"label": "Фильтр по умолчанию",
|
||||
"description": "Начальный фильтр типа файлов при открытии"
|
||||
},
|
||||
"hide-shortcuts": {
|
||||
"label": "Скрыть горячие клавиши",
|
||||
"description": "Скрыть панель горячих клавиш"
|
||||
},
|
||||
"hide-top-bar": {
|
||||
"label": "Скрыть верхнюю панель",
|
||||
"description": "Скрыть панель инструментов над карточками"
|
||||
},
|
||||
"center-card-width": {
|
||||
"label": "Ширина центральной карточки",
|
||||
"description": "Ширина центральной карточки в процентах от экрана"
|
||||
},
|
||||
"card-height": {
|
||||
"label": "Высота карточки",
|
||||
"description": "Высота карточек обоев"
|
||||
},
|
||||
"strip-width": {
|
||||
"label": "Ширина полосы",
|
||||
"description": "Ширина боковых полос карточек"
|
||||
},
|
||||
"card-spacing": {
|
||||
"label": "Расстояние между карточками",
|
||||
"description": "Зазор между карточками"
|
||||
},
|
||||
"cards-shown": {
|
||||
"label": "Видимые карточки",
|
||||
"description": "Количество видимых карточек (рекомендуются нечётные числа)"
|
||||
},
|
||||
"shear-factor": {
|
||||
"label": "Коэффициент сдвига",
|
||||
"description": "Угол наклона расположения карточек"
|
||||
},
|
||||
"card-animation": {
|
||||
"label": "Анимация карточек",
|
||||
"description": "Скорость переходов карточек"
|
||||
},
|
||||
"background-color": {
|
||||
"label": "Цвет фона",
|
||||
"description": "Цвет затемнённого наложения"
|
||||
},
|
||||
"background-opacity": {
|
||||
"label": "Прозрачность фона",
|
||||
"description": "Прозрачность затемнённого наложения"
|
||||
},
|
||||
"window-animation-speed": {
|
||||
"label": "Скорость анимации окна",
|
||||
"description": "Скорость переходов открытия и закрытия"
|
||||
},
|
||||
"animate-window": {
|
||||
"label": "Анимация окна",
|
||||
"description": "Анимировать переходы открытия и закрытия"
|
||||
},
|
||||
"top-bar-height": {
|
||||
"label": "Высота верхней панели",
|
||||
"description": "Высота панели инструментов"
|
||||
}
|
||||
},
|
||||
"shortcuts": {
|
||||
"key-separator": "/",
|
||||
"header": {
|
||||
"navigation": "НАВИГАЦИЯ",
|
||||
"actions": "ДЕЙСТВИЯ",
|
||||
"filters": "ФИЛЬТРЫ",
|
||||
"view": "ВИД",
|
||||
"layout": "КОМПОНОВКА"
|
||||
},
|
||||
"label": {
|
||||
"help-title": "Горячие клавиши",
|
||||
"navigate": "Навигация",
|
||||
"jump": "Перейти",
|
||||
"shuffle": "Перемешать",
|
||||
"apply-quit": "Применить + Выйти",
|
||||
"apply": "Применить",
|
||||
"quit": "Выйти",
|
||||
"filter-all": "Все",
|
||||
"filter-images": "Изображения",
|
||||
"filter-videos": "Видео",
|
||||
"filter-colors": "Цветовой фильтр",
|
||||
"top-bar": "Верхняя панель",
|
||||
"live-preview": "Предпросмотр",
|
||||
"center-height": "Высота центра",
|
||||
"center-width": "Ширина центра",
|
||||
"cards-shown": "Видимые карточки",
|
||||
"cards-spacing": "Расстояние",
|
||||
"cards-width": "Ширина карточек",
|
||||
"save": "Сохранить настройки",
|
||||
"hide": "Скрыть"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
{
|
||||
"buttons": {
|
||||
"all": "Tümü",
|
||||
"images": "Resimler",
|
||||
"videos": "Videolar",
|
||||
"shuffle": "Karıştır",
|
||||
"live-preview": "Canlı",
|
||||
"color-na": "✕"
|
||||
},
|
||||
"widget": {
|
||||
"tooltip": "Wallcards'ı aç",
|
||||
"generate-thumbs-message": "Küçük resimler oluşturuluyor…"
|
||||
},
|
||||
"settings": {
|
||||
"icon-color": {
|
||||
"label": "Simge rengi",
|
||||
"description": "Çubuk widget simgesinin rengi"
|
||||
},
|
||||
"live-preview": {
|
||||
"label": "Canlı önizleme",
|
||||
"description": "Kartlara göz atarken duvar kağıdını uygula"
|
||||
},
|
||||
"default-filter": {
|
||||
"label": "Varsayılan filtre",
|
||||
"description": "Açılışta başlangıç dosya türü filtresi"
|
||||
},
|
||||
"hide-shortcuts": {
|
||||
"label": "Kısayolları gizle",
|
||||
"description": "Klavye kısayolları panelini gizle"
|
||||
},
|
||||
"hide-top-bar": {
|
||||
"label": "Üst çubuğu gizle",
|
||||
"description": "Kartların üzerindeki araç çubuğunu gizle"
|
||||
},
|
||||
"center-card-width": {
|
||||
"label": "Orta kart genişliği",
|
||||
"description": "Orta kartın ekran yüzdesi olarak genişliği"
|
||||
},
|
||||
"card-height": {
|
||||
"label": "Kart yüksekliği",
|
||||
"description": "Duvar kağıdı kartlarının yüksekliği"
|
||||
},
|
||||
"strip-width": {
|
||||
"label": "Şerit genişliği",
|
||||
"description": "Yan kart şeritlerinin genişliği"
|
||||
},
|
||||
"card-spacing": {
|
||||
"label": "Kart aralığı",
|
||||
"description": "Kartlar arasındaki boşluk"
|
||||
},
|
||||
"cards-shown": {
|
||||
"label": "Görünen kartlar",
|
||||
"description": "Görünür kart sayısı (tek sayılar önerilir)"
|
||||
},
|
||||
"shear-factor": {
|
||||
"label": "Kayma faktörü",
|
||||
"description": "Kart düzeninin eğim açısı"
|
||||
},
|
||||
"card-animation": {
|
||||
"label": "Kart animasyonu",
|
||||
"description": "Kart geçişlerinin hızı"
|
||||
},
|
||||
"background-color": {
|
||||
"label": "Arka plan rengi",
|
||||
"description": "Karartılmış katmanın rengi"
|
||||
},
|
||||
"background-opacity": {
|
||||
"label": "Arka plan opaklığı",
|
||||
"description": "Karartılmış katmanın opaklığı"
|
||||
},
|
||||
"window-animation-speed": {
|
||||
"label": "Pencere animasyon hızı",
|
||||
"description": "Açma ve kapama geçişlerinin hızı"
|
||||
},
|
||||
"animate-window": {
|
||||
"label": "Pencere animasyonu",
|
||||
"description": "Açma ve kapama geçişlerini animasyonla göster"
|
||||
},
|
||||
"top-bar-height": {
|
||||
"label": "Üst çubuk yüksekliği",
|
||||
"description": "Araç çubuğunun yüksekliği"
|
||||
}
|
||||
},
|
||||
"shortcuts": {
|
||||
"key-separator": "/",
|
||||
"header": {
|
||||
"navigation": "GEZİNME",
|
||||
"actions": "EYLEMLER",
|
||||
"filters": "FİLTRELER",
|
||||
"view": "GÖRÜNÜM",
|
||||
"layout": "DÜZEN"
|
||||
},
|
||||
"label": {
|
||||
"help-title": "Kısayollar",
|
||||
"navigate": "Gezin",
|
||||
"jump": "Atla",
|
||||
"shuffle": "Karıştır",
|
||||
"apply-quit": "Uygula + Kapat",
|
||||
"apply": "Uygula",
|
||||
"quit": "Kapat",
|
||||
"filter-all": "Tümü",
|
||||
"filter-images": "Resimler",
|
||||
"filter-videos": "Videolar",
|
||||
"filter-colors": "Renk filtresi",
|
||||
"top-bar": "Üst çubuk",
|
||||
"live-preview": "Canlı önizleme",
|
||||
"center-height": "Orta yükseklik",
|
||||
"center-width": "Orta genişlik",
|
||||
"cards-shown": "Görünen kartlar",
|
||||
"cards-spacing": "Aralık",
|
||||
"cards-width": "Kart genişliği",
|
||||
"save": "Ayarları kaydet",
|
||||
"hide": "Gizle"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
{
|
||||
"buttons": {
|
||||
"all": "Усі",
|
||||
"images": "Зображення",
|
||||
"videos": "Відео",
|
||||
"shuffle": "Перемішати",
|
||||
"live-preview": "Наживо",
|
||||
"color-na": "✕"
|
||||
},
|
||||
"widget": {
|
||||
"tooltip": "Відкрити Wallcards",
|
||||
"generate-thumbs-message": "Створення мініатюр…"
|
||||
},
|
||||
"settings": {
|
||||
"icon-color": {
|
||||
"label": "Колір значка",
|
||||
"description": "Колір значка віджета панелі"
|
||||
},
|
||||
"live-preview": {
|
||||
"label": "Попередній перегляд",
|
||||
"description": "Застосовувати шпалери під час перегляду карток"
|
||||
},
|
||||
"default-filter": {
|
||||
"label": "Фільтр за замовчуванням",
|
||||
"description": "Початковий фільтр типу файлів при відкритті"
|
||||
},
|
||||
"hide-shortcuts": {
|
||||
"label": "Сховати гарячі клавіші",
|
||||
"description": "Сховати панель гарячих клавіш"
|
||||
},
|
||||
"hide-top-bar": {
|
||||
"label": "Сховати верхню панель",
|
||||
"description": "Сховати панель інструментів над картками"
|
||||
},
|
||||
"center-card-width": {
|
||||
"label": "Ширина центральної картки",
|
||||
"description": "Ширина центральної картки у відсотках екрана"
|
||||
},
|
||||
"card-height": {
|
||||
"label": "Висота картки",
|
||||
"description": "Висота карток шпалер"
|
||||
},
|
||||
"strip-width": {
|
||||
"label": "Ширина смуги",
|
||||
"description": "Ширина бічних смуг карток"
|
||||
},
|
||||
"card-spacing": {
|
||||
"label": "Відстань між картками",
|
||||
"description": "Проміжок між картками"
|
||||
},
|
||||
"cards-shown": {
|
||||
"label": "Видимі картки",
|
||||
"description": "Кількість видимих карток (рекомендуються непарні числа)"
|
||||
},
|
||||
"shear-factor": {
|
||||
"label": "Коефіцієнт зсуву",
|
||||
"description": "Кут нахилу розташування карток"
|
||||
},
|
||||
"card-animation": {
|
||||
"label": "Анімація карток",
|
||||
"description": "Швидкість переходів карток"
|
||||
},
|
||||
"background-color": {
|
||||
"label": "Колір фону",
|
||||
"description": "Колір затемненого накладання"
|
||||
},
|
||||
"background-opacity": {
|
||||
"label": "Прозорість фону",
|
||||
"description": "Прозорість затемненого накладання"
|
||||
},
|
||||
"window-animation-speed": {
|
||||
"label": "Швидкість анімації вікна",
|
||||
"description": "Швидкість переходів відкриття та закриття"
|
||||
},
|
||||
"animate-window": {
|
||||
"label": "Анімація вікна",
|
||||
"description": "Анімувати переходи відкриття та закриття"
|
||||
},
|
||||
"top-bar-height": {
|
||||
"label": "Висота верхньої панелі",
|
||||
"description": "Висота панелі інструментів"
|
||||
}
|
||||
},
|
||||
"shortcuts": {
|
||||
"key-separator": "/",
|
||||
"header": {
|
||||
"navigation": "НАВІГАЦІЯ",
|
||||
"actions": "ДІЇ",
|
||||
"filters": "ФІЛЬТРИ",
|
||||
"view": "ВИГЛЯД",
|
||||
"layout": "КОМПОНУВАННЯ"
|
||||
},
|
||||
"label": {
|
||||
"help-title": "Гарячі клавіші",
|
||||
"navigate": "Навігація",
|
||||
"jump": "Перейти",
|
||||
"shuffle": "Перемішати",
|
||||
"apply-quit": "Застосувати + Вийти",
|
||||
"apply": "Застосувати",
|
||||
"quit": "Вийти",
|
||||
"filter-all": "Усі",
|
||||
"filter-images": "Зображення",
|
||||
"filter-videos": "Відео",
|
||||
"filter-colors": "Кольоровий фільтр",
|
||||
"top-bar": "Верхня панель",
|
||||
"live-preview": "Попередній перегляд",
|
||||
"center-height": "Висота центру",
|
||||
"center-width": "Ширина центру",
|
||||
"cards-shown": "Видимі картки",
|
||||
"cards-spacing": "Відстань",
|
||||
"cards-width": "Ширина карток",
|
||||
"save": "Зберегти налаштування",
|
||||
"hide": "Сховати"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
{
|
||||
"buttons": {
|
||||
"all": "Tất cả",
|
||||
"images": "Hình ảnh",
|
||||
"videos": "Video",
|
||||
"shuffle": "Xáo trộn",
|
||||
"live-preview": "Trực tiếp",
|
||||
"color-na": "✕"
|
||||
},
|
||||
"widget": {
|
||||
"tooltip": "Mở Wallcards",
|
||||
"generate-thumbs-message": "Đang tạo hình thu nhỏ…"
|
||||
},
|
||||
"settings": {
|
||||
"icon-color": {
|
||||
"label": "Màu biểu tượng",
|
||||
"description": "Màu của biểu tượng widget thanh"
|
||||
},
|
||||
"live-preview": {
|
||||
"label": "Xem trước trực tiếp",
|
||||
"description": "Áp dụng hình nền khi duyệt thẻ"
|
||||
},
|
||||
"default-filter": {
|
||||
"label": "Bộ lọc mặc định",
|
||||
"description": "Bộ lọc loại tệp ban đầu khi mở"
|
||||
},
|
||||
"hide-shortcuts": {
|
||||
"label": "Ẩn phím tắt",
|
||||
"description": "Ẩn bảng phím tắt bàn phím"
|
||||
},
|
||||
"hide-top-bar": {
|
||||
"label": "Ẩn thanh trên",
|
||||
"description": "Ẩn thanh công cụ phía trên các thẻ"
|
||||
},
|
||||
"center-card-width": {
|
||||
"label": "Chiều rộng thẻ giữa",
|
||||
"description": "Chiều rộng thẻ giữa tính theo phần trăm màn hình"
|
||||
},
|
||||
"card-height": {
|
||||
"label": "Chiều cao thẻ",
|
||||
"description": "Chiều cao của các thẻ hình nền"
|
||||
},
|
||||
"strip-width": {
|
||||
"label": "Chiều rộng dải",
|
||||
"description": "Chiều rộng các dải thẻ bên"
|
||||
},
|
||||
"card-spacing": {
|
||||
"label": "Khoảng cách thẻ",
|
||||
"description": "Khoảng cách giữa các thẻ"
|
||||
},
|
||||
"cards-shown": {
|
||||
"label": "Số thẻ hiển thị",
|
||||
"description": "Số lượng thẻ hiển thị (khuyến nghị số lẻ)"
|
||||
},
|
||||
"shear-factor": {
|
||||
"label": "Hệ số nghiêng",
|
||||
"description": "Góc nghiêng của bố cục thẻ"
|
||||
},
|
||||
"card-animation": {
|
||||
"label": "Hoạt ảnh thẻ",
|
||||
"description": "Tốc độ chuyển đổi thẻ"
|
||||
},
|
||||
"background-color": {
|
||||
"label": "Màu nền",
|
||||
"description": "Màu của lớp phủ tối"
|
||||
},
|
||||
"background-opacity": {
|
||||
"label": "Độ mờ nền",
|
||||
"description": "Độ mờ của lớp phủ tối"
|
||||
},
|
||||
"window-animation-speed": {
|
||||
"label": "Tốc độ hoạt ảnh cửa sổ",
|
||||
"description": "Tốc độ chuyển đổi mở và đóng"
|
||||
},
|
||||
"animate-window": {
|
||||
"label": "Hoạt ảnh cửa sổ",
|
||||
"description": "Tạo hoạt ảnh cho chuyển đổi mở và đóng"
|
||||
},
|
||||
"top-bar-height": {
|
||||
"label": "Chiều cao thanh trên",
|
||||
"description": "Chiều cao của thanh công cụ"
|
||||
}
|
||||
},
|
||||
"shortcuts": {
|
||||
"key-separator": "/",
|
||||
"header": {
|
||||
"navigation": "ĐIỀU HƯỚNG",
|
||||
"actions": "HÀNH ĐỘNG",
|
||||
"filters": "BỘ LỌC",
|
||||
"view": "HIỂN THỊ",
|
||||
"layout": "BỐ CỤC"
|
||||
},
|
||||
"label": {
|
||||
"help-title": "Phím tắt",
|
||||
"navigate": "Di chuyển",
|
||||
"jump": "Nhảy",
|
||||
"shuffle": "Xáo trộn",
|
||||
"apply-quit": "Áp dụng + Thoát",
|
||||
"apply": "Áp dụng",
|
||||
"quit": "Thoát",
|
||||
"filter-all": "Tất cả",
|
||||
"filter-images": "Hình ảnh",
|
||||
"filter-videos": "Video",
|
||||
"filter-colors": "Lọc màu",
|
||||
"top-bar": "Thanh trên",
|
||||
"live-preview": "Xem trước trực tiếp",
|
||||
"center-height": "Chiều cao giữa",
|
||||
"center-width": "Chiều rộng giữa",
|
||||
"cards-shown": "Số thẻ hiển thị",
|
||||
"cards-spacing": "Khoảng cách",
|
||||
"cards-width": "Chiều rộng thẻ",
|
||||
"save": "Lưu cài đặt",
|
||||
"hide": "Ẩn"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
{
|
||||
"buttons": {
|
||||
"all": "全部",
|
||||
"images": "图片",
|
||||
"videos": "视频",
|
||||
"shuffle": "随机",
|
||||
"live-preview": "实时",
|
||||
"color-na": "✕"
|
||||
},
|
||||
"widget": {
|
||||
"tooltip": "打开 Wallcards",
|
||||
"generate-thumbs-message": "正在生成缩略图…"
|
||||
},
|
||||
"settings": {
|
||||
"icon-color": {
|
||||
"label": "图标颜色",
|
||||
"description": "栏小部件图标的颜色"
|
||||
},
|
||||
"live-preview": {
|
||||
"label": "实时预览",
|
||||
"description": "浏览卡片时应用壁纸"
|
||||
},
|
||||
"default-filter": {
|
||||
"label": "默认筛选",
|
||||
"description": "打开时的初始文件类型筛选"
|
||||
},
|
||||
"hide-shortcuts": {
|
||||
"label": "隐藏快捷键",
|
||||
"description": "隐藏键盘快捷键面板"
|
||||
},
|
||||
"hide-top-bar": {
|
||||
"label": "隐藏顶栏",
|
||||
"description": "隐藏卡片上方的工具栏"
|
||||
},
|
||||
"center-card-width": {
|
||||
"label": "中央卡片宽度",
|
||||
"description": "中央卡片占屏幕的宽度百分比"
|
||||
},
|
||||
"card-height": {
|
||||
"label": "卡片高度",
|
||||
"description": "壁纸卡片的高度"
|
||||
},
|
||||
"strip-width": {
|
||||
"label": "条带宽度",
|
||||
"description": "侧面卡片条带的宽度"
|
||||
},
|
||||
"card-spacing": {
|
||||
"label": "卡片间距",
|
||||
"description": "卡片之间的间隔"
|
||||
},
|
||||
"cards-shown": {
|
||||
"label": "显示卡片数",
|
||||
"description": "可见卡片数量(建议使用奇数)"
|
||||
},
|
||||
"shear-factor": {
|
||||
"label": "剪切系数",
|
||||
"description": "卡片布局的倾斜角度"
|
||||
},
|
||||
"card-animation": {
|
||||
"label": "卡片动画",
|
||||
"description": "卡片过渡的速度"
|
||||
},
|
||||
"background-color": {
|
||||
"label": "背景颜色",
|
||||
"description": "暗化覆盖层的颜色"
|
||||
},
|
||||
"background-opacity": {
|
||||
"label": "背景不透明度",
|
||||
"description": "暗化覆盖层的不透明度"
|
||||
},
|
||||
"window-animation-speed": {
|
||||
"label": "窗口动画速度",
|
||||
"description": "打开和关闭过渡的速度"
|
||||
},
|
||||
"animate-window": {
|
||||
"label": "窗口动画",
|
||||
"description": "为打开和关闭过渡添加动画"
|
||||
},
|
||||
"top-bar-height": {
|
||||
"label": "顶栏高度",
|
||||
"description": "工具栏的高度"
|
||||
}
|
||||
},
|
||||
"shortcuts": {
|
||||
"key-separator": "/",
|
||||
"header": {
|
||||
"navigation": "导航",
|
||||
"actions": "操作",
|
||||
"filters": "筛选",
|
||||
"view": "视图",
|
||||
"layout": "布局"
|
||||
},
|
||||
"label": {
|
||||
"help-title": "快捷键",
|
||||
"navigate": "导航",
|
||||
"jump": "跳转",
|
||||
"shuffle": "随机",
|
||||
"apply-quit": "应用并退出",
|
||||
"apply": "应用",
|
||||
"quit": "退出",
|
||||
"filter-all": "全部",
|
||||
"filter-images": "图片",
|
||||
"filter-videos": "视频",
|
||||
"filter-colors": "颜色筛选",
|
||||
"top-bar": "顶栏",
|
||||
"live-preview": "实时预览",
|
||||
"center-height": "中央高度",
|
||||
"center-width": "中央宽度",
|
||||
"cards-shown": "显示卡片数",
|
||||
"cards-spacing": "间距",
|
||||
"cards-width": "卡片宽度",
|
||||
"save": "保存设置",
|
||||
"hide": "隐藏"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"id": "wallcards",
|
||||
"name": "Wallcards",
|
||||
"version": "0.1.1",
|
||||
"minNoctaliaVersion": "4.7.0",
|
||||
"author": "tonigineer",
|
||||
"license": "MIT",
|
||||
"repository": "https://github.com/noctalia-dev/noctalia-plugins",
|
||||
"description": "A `lively` wallpaper selector.",
|
||||
"tags": ["Desktop", "Theming"],
|
||||
"entryPoints": {
|
||||
"main": "Main.qml",
|
||||
"barWidget": "BarWidget.qml",
|
||||
"settings": "Settings.qml"
|
||||
},
|
||||
"dependencies": {
|
||||
"plugins": []
|
||||
},
|
||||
"metadata": {
|
||||
"defaultSettings": {
|
||||
"animation_cards_duration": 750,
|
||||
"animation_window_duration": 500,
|
||||
"animate_window": true,
|
||||
"background_color": null,
|
||||
"background_opacity": null,
|
||||
"card_height": 350,
|
||||
"card_spacing": 6,
|
||||
"card_strip_width": 90,
|
||||
"cards_shown": 11,
|
||||
"center_width_ratio": 0.33,
|
||||
"image_filter": ["png", "jpg", "jpeg"],
|
||||
"video_filter": ["mp4", "avi"],
|
||||
"hide_help": false,
|
||||
"hide_top_bar": false,
|
||||
"live_preview": false,
|
||||
"selected_filter": "images",
|
||||
"shear_factor": -0.25,
|
||||
"top_bar_height": 35
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 3.0 MiB |
@@ -0,0 +1,153 @@
|
||||
import qs.Commons
|
||||
import qs.Widgets
|
||||
import QtQuick
|
||||
import QtMultimedia
|
||||
import Qt5Compat.GraphicalEffects
|
||||
|
||||
Item {
|
||||
id: cardContent
|
||||
|
||||
required property int animationDuration
|
||||
required property real centerWidth
|
||||
required property string filePath
|
||||
required property bool isCenter
|
||||
required property bool isVideo
|
||||
required property real radius
|
||||
required property string thumbnailPath
|
||||
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
|
||||
Item {
|
||||
id: imgComposite
|
||||
|
||||
height: cardContent.height
|
||||
visible: false
|
||||
width: cardContent.centerWidth
|
||||
x: (cardContent.width - cardContent.centerWidth) / 2
|
||||
|
||||
Image {
|
||||
id: img
|
||||
|
||||
anchors.fill: parent
|
||||
// asynchronous: true // TODO: flickering when going backwards
|
||||
cache: true
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
smooth: true
|
||||
source: cardContent.thumbnailPath ? "file://" + cardContent.thumbnailPath : ""
|
||||
sourceSize.height: parent.height
|
||||
sourceSize.width: cardContent.centerWidth
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: border
|
||||
|
||||
anchors.fill: parent
|
||||
border.color: isCenter ? Color.mOutline : Qt.alpha(Color.mOutlineVariant, 0.5)
|
||||
border.width: Style.borderS
|
||||
color: "transparent"
|
||||
opacity: 0.75
|
||||
radius: cardContent.radius
|
||||
z: 20
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: mask
|
||||
|
||||
anchors.fill: parent
|
||||
radius: cardContent.radius
|
||||
visible: false
|
||||
}
|
||||
|
||||
OpacityMask {
|
||||
anchors.fill: parent
|
||||
maskSource: mask
|
||||
|
||||
source: ShaderEffectSource {
|
||||
sourceItem: imgComposite
|
||||
sourceRect: Qt.rect(-imgComposite.x, 0, cardContent.width, cardContent.height)
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: videoLoader
|
||||
|
||||
property bool shouldLoad: false
|
||||
property string videoPath: cardContent.isCenter && cardContent.isVideo ? cardContent.filePath : ""
|
||||
|
||||
active: shouldLoad && videoPath !== ""
|
||||
anchors.fill: parent
|
||||
z: 5
|
||||
|
||||
sourceComponent: Component {
|
||||
Item {
|
||||
id: videoContainer
|
||||
|
||||
anchors.fill: parent
|
||||
layer.enabled: true
|
||||
opacity: 0
|
||||
|
||||
layer.effect: OpacityMask {
|
||||
maskSource: Rectangle {
|
||||
height: videoContainer.height
|
||||
radius: cardContent.radius
|
||||
width: videoContainer.width
|
||||
}
|
||||
}
|
||||
|
||||
MediaPlayer {
|
||||
id: mediaPlayer
|
||||
|
||||
loops: MediaPlayer.Infinite
|
||||
source: "file://" + videoLoader.videoPath
|
||||
videoOutput: videoOutput
|
||||
|
||||
audioOutput: AudioOutput {
|
||||
volume: 0
|
||||
}
|
||||
|
||||
Component.onCompleted: play()
|
||||
onPlayingChanged: function () {
|
||||
if (mediaPlayer.playing)
|
||||
videoFadeIn.start();
|
||||
}
|
||||
}
|
||||
|
||||
VideoOutput {
|
||||
id: videoOutput
|
||||
|
||||
anchors.fill: parent
|
||||
fillMode: VideoOutput.PreserveAspectCrop
|
||||
}
|
||||
|
||||
NumberAnimation {
|
||||
id: videoFadeIn
|
||||
|
||||
duration: cardContent.animationDuration
|
||||
easing.type: Easing.OutCubic
|
||||
from: 0
|
||||
property: "opacity"
|
||||
target: videoContainer
|
||||
to: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onVideoPathChanged: {
|
||||
shouldLoad = false;
|
||||
if (videoPath !== "")
|
||||
videoDelayTimer.restart();
|
||||
else
|
||||
videoDelayTimer.stop();
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: videoDelayTimer
|
||||
|
||||
interval: cardContent.animationDuration
|
||||
|
||||
onTriggered: videoLoader.shouldLoad = true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
import qs.Commons
|
||||
import qs.Widgets
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
id: cardDeck
|
||||
|
||||
required property int animationDuration
|
||||
property real animationIndex: 0
|
||||
required property int cardRadius
|
||||
required property int cardSpacing
|
||||
required property int cardStripWidth
|
||||
required property int cardsShown
|
||||
property real centerWidth: parent.width * centerWidthRatio
|
||||
required property real centerWidthRatio
|
||||
property real centerX: width / 2 - centerWidth / 2
|
||||
property int currentIndex: 0
|
||||
required property int filteredCount
|
||||
required property var filteredModel
|
||||
property int halfVisible: Math.floor(visibleCount / 2)
|
||||
property real runningIndex: 0
|
||||
required property real shearFactor
|
||||
property int sideCount: Math.floor(cardsShown / 2) - 1
|
||||
property int visibleCount: cardsShown
|
||||
|
||||
signal applyRequested(int index)
|
||||
|
||||
function navigateTo(idx) {
|
||||
var maxLead = Math.max(1, halfVisible - 1);
|
||||
if (Math.abs(runningIndex - animationIndex) >= maxLead)
|
||||
return;
|
||||
|
||||
var newIdx = wrappedIndex(idx);
|
||||
var diff = 0;
|
||||
|
||||
if (filteredCount > 0) {
|
||||
diff = newIdx - currentIndex;
|
||||
var half = filteredCount / 2;
|
||||
if (diff > half)
|
||||
diff -= filteredCount;
|
||||
else if (diff < -half)
|
||||
diff += filteredCount;
|
||||
}
|
||||
|
||||
runningIndex += diff;
|
||||
animationIndex = runningIndex;
|
||||
currentIndex = newIdx;
|
||||
}
|
||||
function randomJump() {
|
||||
var rnd = Math.floor(Math.random() * filteredCount);
|
||||
if (rnd === currentIndex)
|
||||
rnd = (rnd + 1) % filteredCount;
|
||||
navigateTo(rnd);
|
||||
}
|
||||
function slotToWidth(slot) {
|
||||
var t = Math.min(Math.abs(slot), 1);
|
||||
return centerWidth + (cardStripWidth - centerWidth) * t;
|
||||
}
|
||||
function slotToX(slot) {
|
||||
var rightEdge = centerX + centerWidth + cardSpacing;
|
||||
var leftEdge = centerX - cardSpacing - cardStripWidth;
|
||||
|
||||
if (slot >= 0 && slot <= 1)
|
||||
return centerX + (rightEdge - centerX) * slot;
|
||||
if (slot > 1)
|
||||
return rightEdge + (slot - 1) * (cardStripWidth + cardSpacing);
|
||||
if (slot >= -1 && slot < 0)
|
||||
return centerX + (leftEdge - centerX) * (-slot);
|
||||
if (slot < -1)
|
||||
return leftEdge + (slot + 1) * (cardStripWidth + cardSpacing);
|
||||
return 0;
|
||||
}
|
||||
function wrappedIndex(idx) {
|
||||
return ((idx % filteredCount) + filteredCount) % filteredCount;
|
||||
}
|
||||
|
||||
function jumpTo(idx) {
|
||||
animBehavior.enabled = false;
|
||||
runningIndex = idx;
|
||||
animationIndex = idx;
|
||||
currentIndex = idx;
|
||||
reenableTimer.restart();
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: reenableTimer
|
||||
|
||||
interval: 0
|
||||
|
||||
onTriggered: animBehavior.enabled = true
|
||||
}
|
||||
|
||||
width: (cardsShown - 3) * cardStripWidth + (cardsShown - 3) * cardSpacing + centerWidth
|
||||
|
||||
Behavior on animationIndex {
|
||||
id: animBehavior
|
||||
|
||||
NumberAnimation {
|
||||
duration: cardDeck.animationDuration
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
transform: Matrix4x4 {
|
||||
property real s: cardDeck.shearFactor
|
||||
|
||||
matrix: Qt.matrix4x4(1, s, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: cardDeck.filteredCount > 0 ? cardDeck.visibleCount : 0
|
||||
|
||||
delegate: Rectangle {
|
||||
id: card
|
||||
|
||||
property real fractionalSlot: offset + (cardDeck.runningIndex - cardDeck.animationIndex)
|
||||
property bool isCenter: offset === 0
|
||||
property int modelIndex: cardDeck.wrappedIndex(Math.round(cardDeck.runningIndex) + offset)
|
||||
property int offset: index - cardDeck.halfVisible
|
||||
|
||||
signal applyRequested
|
||||
|
||||
border.color: isCenter ? Color.mOutline : Color.mSurface
|
||||
border.width: isCenter ? Style.borderM : Style.borderS
|
||||
color: "transparent"
|
||||
height: cardDeck.height
|
||||
opacity: Math.max(0, Math.min(1, cardDeck.halfVisible - Math.abs(fractionalSlot)))
|
||||
radius: cardDeck.cardRadius
|
||||
visible: (x + width) > 0 && x < cardDeck.width
|
||||
width: cardDeck.slotToWidth(fractionalSlot)
|
||||
x: cardDeck.slotToX(fractionalSlot)
|
||||
y: 0
|
||||
z: isCenter ? 100 : cardDeck.visibleCount - Math.abs(offset)
|
||||
|
||||
Card {
|
||||
animationDuration: cardDeck.animationDuration
|
||||
centerWidth: cardDeck.centerWidth
|
||||
filePath: cardDeck.filteredModel[card.modelIndex]?.filePath ?? ""
|
||||
isCenter: card.isCenter
|
||||
isVideo: cardDeck.filteredModel[card.modelIndex]?.isVideo ?? false
|
||||
radius: cardDeck.cardRadius
|
||||
thumbnailPath: cardDeck.filteredModel[card.modelIndex]?.thumbnail ?? ""
|
||||
}
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: card.isCenter ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
|
||||
onClicked: {
|
||||
if (card.isCenter)
|
||||
cardDeck.applyRequested(card.modelIndex);
|
||||
}
|
||||
|
||||
//
|
||||
onWheel: function (wheel) {
|
||||
if (wheel.angleDelta.y > 0)
|
||||
cardDeck.navigateTo(cardDeck.currentIndex - 1);
|
||||
else if (wheel.angleDelta.y < 0)
|
||||
cardDeck.navigateTo(cardDeck.currentIndex + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
import qs.Commons
|
||||
import qs.Widgets
|
||||
import QtQuick
|
||||
|
||||
Rectangle {
|
||||
id: loadingBar
|
||||
|
||||
property bool loading: pending > 0
|
||||
required property int pending
|
||||
property real progress: total > 0 ? 1 - (pending / total) : 0
|
||||
required property int total
|
||||
|
||||
color: Qt.alpha(Color.mSurface, 0.9)
|
||||
height: upperRow.height + Style.margin2S + progressBar.height
|
||||
radius: Style.radiusXS
|
||||
visible: loading
|
||||
width: upperRow.width + Style.margin2L
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: 300
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: upperRow
|
||||
|
||||
anchors.centerIn: parent
|
||||
anchors.verticalCenterOffset: -progressBar.height / 2
|
||||
|
||||
Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
Repeater {
|
||||
model: 3
|
||||
|
||||
Rectangle {
|
||||
property real angle: index * (2 * Math.PI / 3)
|
||||
|
||||
color: Color.mPrimary
|
||||
height: Style.marginXS
|
||||
radius: Style.marginXXS
|
||||
width: Style.marginXS
|
||||
x: Style.marginS + Style.marginS * Math.cos(angle + spinAnimation.value)
|
||||
y: Style.marginS + Style.marginS * Math.sin(angle + spinAnimation.value)
|
||||
|
||||
NumberAnimation on opacity {
|
||||
duration: 600
|
||||
from: 0.3
|
||||
loops: Animation.Infinite
|
||||
running: loadingBar.loading
|
||||
to: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
NumberAnimation {
|
||||
id: spinAnimation
|
||||
|
||||
property real value: 0
|
||||
|
||||
duration: 1200
|
||||
from: 0
|
||||
loops: Animation.Infinite
|
||||
property: "value"
|
||||
running: loadingBar.loading
|
||||
target: spinAnimation
|
||||
to: 2 * Math.PI
|
||||
}
|
||||
}
|
||||
|
||||
NText {
|
||||
text: `${root.pluginApi?.tr("widget.generate-thumbs-message")} ${String(Math.max(loadingBar.total - loadingBar.pending, 0)).padStart(String(loadingBar.total).length, " ")} / ${loadingBar.total}`
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: progressBar
|
||||
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
color: Qt.alpha(Color.mOnSurface, 0.1)
|
||||
height: Style.marginS
|
||||
radius: loadingBar.radius
|
||||
|
||||
Rectangle {
|
||||
color: Color.mPrimary
|
||||
height: parent.height
|
||||
radius: parent.radius
|
||||
width: parent.width * loadingBar.progress
|
||||
|
||||
Behavior on width {
|
||||
NumberAnimation {
|
||||
duration: 200
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
import QtQuick
|
||||
import qs.Commons
|
||||
import qs.Widgets
|
||||
|
||||
Row {
|
||||
id: hint
|
||||
|
||||
required property string keys
|
||||
required property string label
|
||||
|
||||
spacing: Style.marginXS
|
||||
|
||||
Row {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Style.marginXXS
|
||||
|
||||
Repeater {
|
||||
model: hint.keys.split(" / ")
|
||||
|
||||
Row {
|
||||
required property int index
|
||||
required property var modelData
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Style.marginXXS
|
||||
|
||||
// Separator between keys
|
||||
NText {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
color: Qt.alpha(Color.mOnSurface, 0.3)
|
||||
font.pointSize: Style.fontSizeXXS
|
||||
text: root.pluginApi?.tr("shortcuts.key-separator")
|
||||
visible: index > 0
|
||||
}
|
||||
|
||||
// Keycap
|
||||
Rectangle {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
border.color: Qt.alpha(Color.mOnSurface, 0.2)
|
||||
border.width: Style.borderS
|
||||
color: Qt.alpha(Color.mOnSurface, 0.08)
|
||||
height: Style.marginL + 2
|
||||
radius: Style.radiusXS
|
||||
width: Math.max(Style.marginL + 2, keycapText.width + Style.marginS)
|
||||
|
||||
Rectangle {
|
||||
anchors.bottomMargin: 2
|
||||
anchors.fill: parent
|
||||
border.color: Qt.alpha(Color.mOnSurface, 0.15)
|
||||
border.width: Style.borderS
|
||||
color: Qt.alpha(Color.mOnSurface, 0.05)
|
||||
radius: Style.radiusXS
|
||||
|
||||
NText {
|
||||
id: keycapText
|
||||
|
||||
anchors.centerIn: parent
|
||||
color: Qt.alpha(Color.mOnSurface, 0.6)
|
||||
font.bold: true
|
||||
font.pointSize: Style.fontSizeXXS
|
||||
text: modelData.trim()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NText {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
color: Qt.alpha(Color.mOnSurface, 0.4)
|
||||
font.pointSize: Style.fontSizeXXS
|
||||
text: hint.label
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
import QtQuick
|
||||
import qs.Commons
|
||||
import qs.Widgets
|
||||
|
||||
Rectangle {
|
||||
id: sideBar
|
||||
|
||||
property bool expanded: false
|
||||
property bool hideHelp: true
|
||||
|
||||
color: Qt.alpha(Color.mSurface, 0.9)
|
||||
radius: Style.radiusS
|
||||
width: expanded ? shortcutColumn.width + Style.margin2L : !hideHelp ? collapsedColumn.width + Style.margin2L : 0
|
||||
height: expanded ? shortcutColumn.height + Style.margin2L : !hideHelp ? collapsedColumn.height + Style.margin2L : 0
|
||||
|
||||
Behavior on width {
|
||||
NumberAnimation {
|
||||
duration: 150
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
Behavior on height {
|
||||
NumberAnimation {
|
||||
duration: 150
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
|
||||
clip: true
|
||||
|
||||
Column {
|
||||
id: collapsedColumn
|
||||
|
||||
anchors.centerIn: parent
|
||||
spacing: Style.marginS
|
||||
visible: !sideBar.expanded && !sideBar.hideHelp
|
||||
|
||||
ShortcutHint {
|
||||
keys: "?"
|
||||
label: root.pluginApi?.tr("shortcuts.label.help-title")
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
id: shortcutColumn
|
||||
|
||||
anchors.centerIn: parent
|
||||
spacing: Style.marginXS
|
||||
visible: sideBar.expanded
|
||||
|
||||
// Navigation
|
||||
NText {
|
||||
color: Qt.alpha(Color.mOnSurface, 0.35)
|
||||
font.bold: true
|
||||
font.pointSize: Style.fontSizeXXS
|
||||
text: root.pluginApi?.tr("shortcuts.header.navigation")
|
||||
}
|
||||
ShortcutHint {
|
||||
keys: "J / K"
|
||||
label: root.pluginApi?.tr("shortcuts.label.navigate")
|
||||
}
|
||||
ShortcutHint {
|
||||
keys: "H / L"
|
||||
label: root.pluginApi?.tr("shortcuts.label.jump")
|
||||
}
|
||||
ShortcutHint {
|
||||
keys: "R"
|
||||
label: root.pluginApi?.tr("shortcuts.label.shuffle")
|
||||
}
|
||||
|
||||
// Separator
|
||||
Rectangle {
|
||||
color: Qt.alpha(Color.mOnSurface, 0.1)
|
||||
height: 1
|
||||
width: shortcutColumn.width
|
||||
}
|
||||
|
||||
// Actions
|
||||
NText {
|
||||
color: Qt.alpha(Color.mOnSurface, 0.35)
|
||||
font.bold: true
|
||||
font.pointSize: Style.fontSizeXXS
|
||||
text: root.pluginApi?.tr("shortcuts.header.actions")
|
||||
}
|
||||
ShortcutHint {
|
||||
keys: "ENTER"
|
||||
label: root.pluginApi?.tr("shortcuts.label.apply-quit")
|
||||
}
|
||||
ShortcutHint {
|
||||
keys: "SPACE"
|
||||
label: root.pluginApi?.tr("shortcuts.label.apply")
|
||||
}
|
||||
ShortcutHint {
|
||||
keys: "ESC / Q"
|
||||
label: root.pluginApi?.tr("shortcuts.label.quit")
|
||||
}
|
||||
|
||||
// Separator
|
||||
Rectangle {
|
||||
color: Qt.alpha(Color.mOnSurface, 0.1)
|
||||
height: 1
|
||||
width: shortcutColumn.width
|
||||
}
|
||||
|
||||
// Filters
|
||||
NText {
|
||||
color: Qt.alpha(Color.mOnSurface, 0.35)
|
||||
font.bold: true
|
||||
font.pointSize: Style.fontSizeXXS
|
||||
text: root.pluginApi?.tr("shortcuts.header.filters")
|
||||
}
|
||||
ShortcutHint {
|
||||
keys: "A"
|
||||
label: root.pluginApi?.tr("shortcuts.label.filter-all")
|
||||
}
|
||||
ShortcutHint {
|
||||
keys: "I"
|
||||
label: root.pluginApi?.tr("shortcuts.label.filter-images")
|
||||
}
|
||||
ShortcutHint {
|
||||
keys: "V"
|
||||
label: root.pluginApi?.tr("shortcuts.label.filter-videos")
|
||||
}
|
||||
ShortcutHint {
|
||||
keys: "F"
|
||||
label: root.pluginApi?.tr("shortcuts.label.filter-colors")
|
||||
}
|
||||
|
||||
// Separator
|
||||
Rectangle {
|
||||
color: Qt.alpha(Color.mOnSurface, 0.1)
|
||||
height: 1
|
||||
width: shortcutColumn.width
|
||||
}
|
||||
|
||||
// View
|
||||
NText {
|
||||
color: Qt.alpha(Color.mOnSurface, 0.35)
|
||||
font.bold: true
|
||||
font.pointSize: Style.fontSizeXXS
|
||||
text: root.pluginApi?.tr("shortcuts.header.view")
|
||||
}
|
||||
ShortcutHint {
|
||||
keys: "T"
|
||||
label: root.pluginApi?.tr("shortcuts.label.top-bar")
|
||||
}
|
||||
ShortcutHint {
|
||||
keys: "P"
|
||||
label: root.pluginApi?.tr("shortcuts.label.live-preview")
|
||||
}
|
||||
|
||||
// Separator
|
||||
Rectangle {
|
||||
color: Qt.alpha(Color.mOnSurface, 0.1)
|
||||
height: 1
|
||||
width: shortcutColumn.width
|
||||
}
|
||||
|
||||
// Layout
|
||||
NText {
|
||||
color: Qt.alpha(Color.mOnSurface, 0.35)
|
||||
font.bold: true
|
||||
font.pointSize: Style.fontSizeXXS
|
||||
text: root.pluginApi?.tr("shortcuts.header.layout")
|
||||
}
|
||||
ShortcutHint {
|
||||
keys: "SHIFT + H / L"
|
||||
label: root.pluginApi?.tr("shortcuts.label.center-height")
|
||||
}
|
||||
ShortcutHint {
|
||||
keys: "SHIFT + J / K"
|
||||
label: root.pluginApi?.tr("shortcuts.label.center-width")
|
||||
}
|
||||
ShortcutHint {
|
||||
keys: "SHIFT + N / P"
|
||||
label: root.pluginApi?.tr("shortcuts.label.cards-shown")
|
||||
}
|
||||
ShortcutHint {
|
||||
keys: "CTRL + J / K"
|
||||
label: root.pluginApi?.tr("shortcuts.label.cards-spacing")
|
||||
}
|
||||
ShortcutHint {
|
||||
keys: "CTRL + H / L"
|
||||
label: root.pluginApi?.tr("shortcuts.label.cards-width")
|
||||
}
|
||||
|
||||
// Separator
|
||||
Rectangle {
|
||||
color: Qt.alpha(Color.mOnSurface, 0.1)
|
||||
height: 1
|
||||
width: shortcutColumn.width
|
||||
}
|
||||
|
||||
ShortcutHint {
|
||||
keys: "CTRL + S"
|
||||
label: root.pluginApi?.tr("shortcuts.label.save")
|
||||
}
|
||||
ShortcutHint {
|
||||
keys: "?"
|
||||
label: root.pluginApi?.tr("shortcuts.label.hide")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,275 @@
|
||||
import "Utils.js" as Utils
|
||||
import QtQuick
|
||||
import Quickshell.Io
|
||||
import Qt.labs.folderlistmodel
|
||||
|
||||
Item {
|
||||
id: service
|
||||
|
||||
property int maxThumbnailJobs: 4
|
||||
property var pendingJobs: []
|
||||
property int activeJobs: 0
|
||||
required property string cacheDir
|
||||
required property var imageFilter
|
||||
required property var videoFilter
|
||||
required property string wallpaperDir
|
||||
property var colorOrder: ["Red", "Orange", "Green", "Teal", "Blue", "Purple", "Pink", "Monochrome"]
|
||||
property var colorOrderColors: ["#FF4500", "#FFA500", "#32CD32", "#2EC4B6", "#1E90FF", "#8A2BE2", "#FF69B4", "#A9A9A9"]
|
||||
property int fileCount: files.length
|
||||
property var files: []
|
||||
property bool loading: true
|
||||
property int pendingProcesses: 0
|
||||
property int thumbnailRevision: 0
|
||||
|
||||
signal ready
|
||||
|
||||
function toLocalPath(urlStr) {
|
||||
return String(urlStr).replace(/^file:\/\//, "");
|
||||
}
|
||||
|
||||
FolderListModel {
|
||||
id: thumbnailModel
|
||||
|
||||
folder: service.wallpaperDir ? Qt.resolvedUrl("file://" + service.wallpaperDir) : ""
|
||||
nameFilters: Utils.nameFilters(service.imageFilter, service.videoFilter)
|
||||
showDirs: false
|
||||
sortField: FolderListModel.Name
|
||||
|
||||
onStatusChanged: {
|
||||
if (status === FolderListModel.Ready) {
|
||||
service.createThumbnails();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createThumbnails() {
|
||||
var proc = processComponent.createObject(null, {
|
||||
command: ["mkdir", "-p", cacheDir]
|
||||
});
|
||||
proc.running = true;
|
||||
|
||||
var items = [];
|
||||
var jobs = [];
|
||||
|
||||
for (var i = 0; i < thumbnailModel.count; i++) {
|
||||
(function (idx) {
|
||||
var filePath = toLocalPath(thumbnailModel.get(idx, "filePath"));
|
||||
var fileName = thumbnailModel.get(idx, "fileName");
|
||||
var isVid = Utils.isVideo(fileName, service.videoFilter);
|
||||
var thumbName = isVid ? fileName + ".jpg" : fileName;
|
||||
var thumbnailPath = cacheDir + "/" + thumbName;
|
||||
|
||||
var thumbnailCmd = isVid ? videoToThumbnailCmd(filePath, thumbnailPath) : imageToThumbnailCmd(filePath, thumbnailPath);
|
||||
var hexCmd = thumbnailHexValueCmd(thumbnailPath);
|
||||
|
||||
const script = `
|
||||
[ -f "${thumbnailPath}"* ] && exit 0
|
||||
${thumbnailCmd}
|
||||
mv "${thumbnailPath}" "${thumbnailPath}__x$(${hexCmd})"
|
||||
`;
|
||||
|
||||
jobs.push({
|
||||
script: script,
|
||||
thumbnailPath: thumbnailPath
|
||||
});
|
||||
|
||||
items.push({});
|
||||
})(i);
|
||||
}
|
||||
|
||||
pendingJobs = jobs;
|
||||
activeJobs = 0;
|
||||
processNextJob();
|
||||
|
||||
if (thumbnailModel.count === 0) {
|
||||
service.loading = false;
|
||||
}
|
||||
|
||||
files = items;
|
||||
}
|
||||
function processNextJob() {
|
||||
while (activeJobs < maxThumbnailJobs && pendingJobs.length > 0) {
|
||||
var job = pendingJobs.shift();
|
||||
activeJobs++;
|
||||
service.pendingProcesses++;
|
||||
createSingleThumbnail(job, function() {
|
||||
activeJobs--;
|
||||
processNextJob();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function createSingleThumbnail(job, onFinished) {
|
||||
var proc = processComponent.createObject(null, {
|
||||
command: ["bash", "-c", job.script]
|
||||
});
|
||||
|
||||
proc.exited.connect(function () {
|
||||
service.pendingProcesses--;
|
||||
service.thumbnailRevision++;
|
||||
|
||||
if (service.pendingProcesses === 0) {
|
||||
filesModel.running = true;
|
||||
}
|
||||
|
||||
proc.destroy();
|
||||
if (onFinished) onFinished();
|
||||
});
|
||||
|
||||
proc.running = true;
|
||||
}
|
||||
function imageToThumbnailCmd(filePath, thumbnailPath) {
|
||||
return `magick "${filePath}" \
|
||||
-resize x500 \
|
||||
-quality 95 \
|
||||
"${thumbnailPath}"
|
||||
`;
|
||||
}
|
||||
|
||||
function videoToThumbnailCmd(filePath, thumbnailPath) {
|
||||
return `ffmpeg -y -i \
|
||||
"${filePath}" \
|
||||
-vf "select=eq(n\\,0),scale=-1:1080" \
|
||||
-frames:v 1 \
|
||||
-q:v 2 \
|
||||
"${thumbnailPath}" </dev/null 2>/dev/null`;
|
||||
}
|
||||
|
||||
function thumbnailHexValueCmd(thumbnailPath) {
|
||||
return `magick "${thumbnailPath}" \
|
||||
-resize "1x1^" \
|
||||
-gravity center \
|
||||
-extent 1x1 \
|
||||
-depth 8 \
|
||||
-format "%[hex:p{0,0}]" info:- 2>/dev/null \
|
||||
| grep -oE '[0-9A-Fa-f]{6}' \
|
||||
| head -n 1`;
|
||||
}
|
||||
|
||||
FolderListModel {
|
||||
id: filesModel
|
||||
|
||||
nameFilters: ["*__x*"]
|
||||
showDirs: false
|
||||
sortField: FolderListModel.Name
|
||||
|
||||
property bool running: false
|
||||
|
||||
onRunningChanged: {
|
||||
if (running)
|
||||
folder = Qt.resolvedUrl("file://" + service.cacheDir);
|
||||
}
|
||||
|
||||
onStatusChanged: {
|
||||
if (status === FolderListModel.Ready && running) {
|
||||
service.buildFileList();
|
||||
running = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function buildFileList() {
|
||||
// Ground truth needed to avoid showing thumbnails for files
|
||||
// that are no longer in the wallpaper directory.
|
||||
var existingFiles = new Set();
|
||||
for (let j = 0; j < thumbnailModel.count; j++) {
|
||||
existingFiles.add(thumbnailModel.get(j, "fileName"));
|
||||
}
|
||||
|
||||
var items = [];
|
||||
|
||||
for (let i = 0; i < filesModel.count; i++) {
|
||||
const filePath = toLocalPath(filesModel.get(i, "filePath"));
|
||||
const fileName = filesModel.get(i, "fileName");
|
||||
|
||||
const idx = fileName.lastIndexOf("__x");
|
||||
if (idx === -1)
|
||||
continue;
|
||||
|
||||
const thumbBase = fileName.substring(0, idx);
|
||||
const hexColor = fileName.substring(idx + 3);
|
||||
|
||||
// Video thumbnails are named <original>.<vidext>.jpg__x<hex>
|
||||
// Strip trailing .jpg to recover the original video filename.
|
||||
var isVid = thumbBase.toLowerCase().endsWith(".jpg") && Utils.isVideo(thumbBase.substring(0, thumbBase.lastIndexOf(".")), service.videoFilter);
|
||||
var wallpaperName = isVid ? thumbBase.substring(0, thumbBase.lastIndexOf(".")) : thumbBase;
|
||||
|
||||
if (!existingFiles.has(wallpaperName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
items.push({
|
||||
fileName: wallpaperName,
|
||||
filePath: wallpaperDir + "/" + wallpaperName,
|
||||
thumbnail: filePath,
|
||||
hexCode: hexColor,
|
||||
filterColor: getFilterColor(hexColor),
|
||||
isVideo: isVid
|
||||
});
|
||||
}
|
||||
|
||||
items.sort((a, b) => colorOrder.indexOf(a.filterColor) - colorOrder.indexOf(b.filterColor));
|
||||
|
||||
files = items;
|
||||
service.loading = false;
|
||||
service.ready();
|
||||
}
|
||||
|
||||
function getFilterColor(hexColor) {
|
||||
if (!hexColor)
|
||||
return "Monochrome";
|
||||
|
||||
const cleaned = String(hexColor).trim().replace(/x/g, '').substring(0, 6);
|
||||
if (cleaned.length !== 6)
|
||||
return "Monochrome";
|
||||
|
||||
const r = parseInt(cleaned.substring(0, 2), 16) / 255;
|
||||
const g = parseInt(cleaned.substring(2, 4), 16) / 255;
|
||||
const b = parseInt(cleaned.substring(4, 6), 16) / 255;
|
||||
if ([r, g, b].some(isNaN))
|
||||
return "Monochrome";
|
||||
|
||||
const max = Math.max(r, g, b);
|
||||
const min = Math.min(r, g, b);
|
||||
const d = max - min;
|
||||
|
||||
let h = 0;
|
||||
let s = max === 0 ? 0 : d / max;
|
||||
let v = max;
|
||||
|
||||
if (d !== 0) {
|
||||
if (max === r)
|
||||
h = (g - b) / d + (g < b ? 6 : 0);
|
||||
else if (max === g)
|
||||
h = (b - r) / d + 2;
|
||||
else
|
||||
h = (r - g) / d + 4;
|
||||
h = (h / 6) * 360;
|
||||
}
|
||||
|
||||
if (s < 0.15 || v < 0.10)
|
||||
return "Monochrome";
|
||||
if (h >= 345 || h < 15)
|
||||
return "Red";
|
||||
if (h < 50)
|
||||
return "Orange";
|
||||
if (h < 160)
|
||||
return "Green";
|
||||
if (h < 200)
|
||||
return "Teal";
|
||||
if (h < 260)
|
||||
return "Blue";
|
||||
if (h < 315)
|
||||
return "Purple";
|
||||
if (h < 345)
|
||||
return "Pink";
|
||||
|
||||
return "Monochrome";
|
||||
}
|
||||
|
||||
Component {
|
||||
id: processComponent
|
||||
|
||||
Process {}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,418 @@
|
||||
import qs.Commons
|
||||
import qs.Widgets
|
||||
|
||||
import QtQuick
|
||||
|
||||
Rectangle {
|
||||
id: topBar
|
||||
|
||||
required property int animationDuration
|
||||
required property var availableColors
|
||||
required property var colorOrder
|
||||
required property var colorOrderColors
|
||||
required property string currentCardColor
|
||||
required property int currentIndex
|
||||
property real entryOffset: parent.width / 2
|
||||
required property int filteredCount
|
||||
required property bool livePreview
|
||||
required property var pluginApi
|
||||
required property string selectedColorFilter
|
||||
required property string selectedFilter
|
||||
required property real shearFactor
|
||||
|
||||
signal colorFilterSelected(string key)
|
||||
signal filterSelected(string key)
|
||||
signal livePreviewToggled
|
||||
signal shuffleRequested
|
||||
|
||||
function flashShuffle() {
|
||||
shuffleBtn.flash();
|
||||
}
|
||||
|
||||
color: Color.mSurface
|
||||
|
||||
Behavior on entryOffset {
|
||||
NumberAnimation {
|
||||
duration: topBar.animationDuration
|
||||
easing.overshoot: 1.0
|
||||
easing.type: Easing.OutBack
|
||||
}
|
||||
}
|
||||
|
||||
transform: Matrix4x4 {
|
||||
property real s: topBar.shearFactor
|
||||
|
||||
matrix: Qt.matrix4x4(1, s, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
|
||||
}
|
||||
|
||||
Component.onCompleted: entryOffset = 0
|
||||
|
||||
// ── Inline Components ──
|
||||
|
||||
component TButton: Rectangle {
|
||||
id: btn
|
||||
|
||||
property color accentColor: active ? Color.mOnSurface : Color.mOnSurfaceVariant
|
||||
property bool active: false
|
||||
property string hotkey: ""
|
||||
property string icon: ""
|
||||
property string label: ""
|
||||
property bool pulsing: false
|
||||
|
||||
signal clicked
|
||||
|
||||
border.color: active ? Qt.alpha(accentColor, Style.opacityMedium) : Qt.alpha(Color.mOutline, 0.3)
|
||||
border.width: Style.borderS
|
||||
color: active ? Qt.alpha(accentColor, 0.15) : Qt.alpha(Color.mOnSurface, 0.06)
|
||||
height: Style.margin2L
|
||||
radius: Style.radiusM
|
||||
width: btnRow.width + Style.margin2M
|
||||
|
||||
Behavior on border.color {
|
||||
ColorAnimation {
|
||||
duration: Style.animationFast
|
||||
}
|
||||
}
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Style.animationFast
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: btnRow
|
||||
|
||||
anchors.centerIn: parent
|
||||
spacing: Style.marginS
|
||||
|
||||
PulsingDot {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
pulsing: btn.pulsing
|
||||
visible: btn.pulsing
|
||||
}
|
||||
NIcon {
|
||||
color: btn.accentColor
|
||||
icon: btn.icon
|
||||
visible: btn.icon !== ""
|
||||
}
|
||||
NText {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
color: btn.accentColor
|
||||
font.pointSize: Style.fontSizeXS
|
||||
text: btn.label
|
||||
visible: btn.label !== ""
|
||||
}
|
||||
Rectangle {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
border.color: Qt.alpha(btn.accentColor, 0.35)
|
||||
border.width: Style.borderM
|
||||
color: Qt.alpha(btn.accentColor, 0.12)
|
||||
height: Style.marginL + 2
|
||||
opacity: 0.25
|
||||
radius: Style.radiusXS
|
||||
visible: btn.hotkey !== ""
|
||||
width: Style.marginL + 5
|
||||
|
||||
Rectangle {
|
||||
anchors.bottomMargin: 2
|
||||
anchors.fill: parent
|
||||
border.color: Qt.alpha(btn.accentColor, 0.25)
|
||||
border.width: Style.borderS
|
||||
color: Qt.alpha(btn.accentColor, 0.1)
|
||||
radius: Style.radiusXS
|
||||
|
||||
NText {
|
||||
anchors.centerIn: parent
|
||||
color: Qt.alpha(btn.accentColor, 0.7)
|
||||
font.bold: true
|
||||
font.pointSize: Style.fontSizeXXS
|
||||
text: btn.hotkey
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
|
||||
onClicked: btn.clicked()
|
||||
}
|
||||
}
|
||||
|
||||
component CButton: Rectangle {
|
||||
id: colorBtn
|
||||
|
||||
property bool active: false
|
||||
property bool available: true
|
||||
property bool current: false
|
||||
required property color faceColor
|
||||
|
||||
signal clicked
|
||||
|
||||
border.color: active ? Color.mOnSurface : Qt.alpha(Color.mOutline, 0.3)
|
||||
border.width: Style.borderS
|
||||
color: faceColor
|
||||
height: Style.margin2L
|
||||
opacity: active ? 1.0 : available ? 0.4 : 0.12
|
||||
radius: Style.radiusM
|
||||
width: height
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Style.animationFast
|
||||
}
|
||||
}
|
||||
Behavior on border.color {
|
||||
ColorAnimation {
|
||||
duration: Style.animationFast
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: -height - 2
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
color: colorBtn.current ? colorBtn.faceColor : "transparent"
|
||||
height: 3
|
||||
radius: height / 2
|
||||
width: colorBtn.current ? parent.width * 0.6 : 0
|
||||
|
||||
Behavior on width {
|
||||
NumberAnimation {
|
||||
duration: Style.animationFast
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Style.animationFast
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NText {
|
||||
anchors.centerIn: parent
|
||||
color: Color.mOnSurface
|
||||
font.bold: true
|
||||
font.pointSize: Style.fontSizeS
|
||||
text: topBar.pluginApi?.tr("buttons.color-na")
|
||||
visible: !colorBtn.available
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: colorBtn.available ? Qt.PointingHandCursor : Qt.ForbiddenCursor
|
||||
enabled: colorBtn.available
|
||||
|
||||
onClicked: colorBtn.clicked()
|
||||
}
|
||||
}
|
||||
|
||||
component SButton: Item {
|
||||
id: shuffleItem
|
||||
|
||||
property string hotkey: ""
|
||||
property string icon: ""
|
||||
property string label: ""
|
||||
|
||||
signal clicked
|
||||
|
||||
function flash() {
|
||||
flashAnim.restart();
|
||||
}
|
||||
|
||||
height: innerBtn.height
|
||||
width: innerBtn.width
|
||||
|
||||
TButton {
|
||||
id: innerBtn
|
||||
|
||||
hotkey: shuffleItem.hotkey
|
||||
icon: shuffleItem.icon
|
||||
label: shuffleItem.label
|
||||
|
||||
onClicked: {
|
||||
shuffleItem.clicked();
|
||||
shuffleItem.flash();
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: flashOverlay
|
||||
|
||||
anchors.fill: innerBtn
|
||||
color: Color.mPrimary
|
||||
opacity: 0
|
||||
radius: innerBtn.radius
|
||||
}
|
||||
|
||||
SequentialAnimation {
|
||||
id: flashAnim
|
||||
|
||||
NumberAnimation {
|
||||
duration: 80
|
||||
easing.type: Easing.OutCubic
|
||||
property: "opacity"
|
||||
target: flashOverlay
|
||||
to: 0.3
|
||||
}
|
||||
NumberAnimation {
|
||||
duration: 300
|
||||
easing.type: Easing.OutCubic
|
||||
property: "opacity"
|
||||
target: flashOverlay
|
||||
to: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component PulsingDot: Rectangle {
|
||||
id: root
|
||||
|
||||
property color dotColor: Color.mError
|
||||
property bool pulsing: false
|
||||
|
||||
color: dotColor
|
||||
height: Style.marginS
|
||||
radius: Style.marginXXXS
|
||||
width: Style.marginS
|
||||
|
||||
SequentialAnimation {
|
||||
id: pulseAnimation
|
||||
|
||||
loops: Animation.Infinite
|
||||
running: root.pulsing
|
||||
|
||||
onRunningChanged: {
|
||||
if (!running)
|
||||
root.opacity = 1.0;
|
||||
}
|
||||
|
||||
NumberAnimation {
|
||||
duration: 800
|
||||
easing.type: Easing.InOutSine
|
||||
from: 1.0
|
||||
property: "opacity"
|
||||
target: root
|
||||
to: 0.3
|
||||
}
|
||||
NumberAnimation {
|
||||
duration: 800
|
||||
easing.type: Easing.InOutSine
|
||||
from: 0.3
|
||||
property: "opacity"
|
||||
target: root
|
||||
to: 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Left ──
|
||||
|
||||
NText {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Style.marginL
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: (topBar.currentIndex + 1) + " / " + topBar.filteredCount
|
||||
}
|
||||
|
||||
// ── Center ──
|
||||
|
||||
Row {
|
||||
anchors.centerIn: parent
|
||||
spacing: Style.marginXS
|
||||
|
||||
Repeater {
|
||||
model: [
|
||||
{
|
||||
key: "all",
|
||||
label: topBar.pluginApi?.tr("buttons.all"),
|
||||
icon: "wallpaper",
|
||||
hotkey: "A"
|
||||
},
|
||||
{
|
||||
key: "images",
|
||||
label: topBar.pluginApi?.tr("buttons.images"),
|
||||
icon: "image",
|
||||
hotkey: "I"
|
||||
},
|
||||
{
|
||||
key: "videos",
|
||||
label: topBar.pluginApi?.tr("buttons.videos"),
|
||||
icon: "video",
|
||||
hotkey: "V"
|
||||
}
|
||||
]
|
||||
|
||||
TButton {
|
||||
required property var modelData
|
||||
|
||||
active: topBar.selectedFilter === modelData.key
|
||||
hotkey: modelData.hotkey
|
||||
icon: modelData.icon
|
||||
label: modelData.label || ""
|
||||
|
||||
onClicked: topBar.filterSelected(modelData.key)
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
color: Qt.alpha(Color.mOnSurface, 0.15)
|
||||
height: parent.height * 0.5
|
||||
width: 1
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: topBar.colorOrder
|
||||
|
||||
CButton {
|
||||
required property int index
|
||||
required property string modelData
|
||||
|
||||
active: topBar.selectedColorFilter === modelData
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
available: topBar.availableColors.indexOf(modelData) !== -1
|
||||
current: topBar.selectedColorFilter === "" && topBar.currentCardColor === modelData
|
||||
faceColor: topBar.colorOrderColors[index]
|
||||
|
||||
onClicked: {
|
||||
if (active)
|
||||
topBar.colorFilterSelected("");
|
||||
else
|
||||
topBar.colorFilterSelected(modelData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Right ──
|
||||
|
||||
Row {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Style.marginL
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Style.marginXS
|
||||
|
||||
SButton {
|
||||
id: shuffleBtn
|
||||
|
||||
hotkey: "R"
|
||||
icon: "arrows-random"
|
||||
label: topBar.pluginApi?.tr("buttons.shuffle")
|
||||
|
||||
onClicked: topBar.shuffleRequested()
|
||||
}
|
||||
|
||||
TButton {
|
||||
accentColor: topBar.livePreview ? Color.mTertiary : Color.mOnSurfaceVariant
|
||||
active: topBar.livePreview
|
||||
hotkey: "P"
|
||||
label: topBar.pluginApi?.tr("buttons.live-preview")
|
||||
pulsing: topBar.livePreview
|
||||
|
||||
onClicked: topBar.livePreviewToggled()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
function getExtension(fileName) {
|
||||
return fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
|
||||
}
|
||||
|
||||
function isVideo(fileName, filterVideos) {
|
||||
return filterVideos.indexOf(getExtension(fileName)) !== -1;
|
||||
}
|
||||
|
||||
function isImage(fileName, filterImages) {
|
||||
return filterImages.indexOf(getExtension(fileName)) !== -1;
|
||||
}
|
||||
|
||||
function nameFilters(filterImages, filterVideos) {
|
||||
return (filterImages || []).concat(filterVideos || []).map((ext) => "*." + ext);
|
||||
}
|
||||
|
||||
var mpvpaperKill = "killall -9 mpvpaper 2>/dev/null || true";
|
||||
|
||||
var mpvpaperOptions = [
|
||||
"loop",
|
||||
"--no-audio",
|
||||
"--hwdec=auto",
|
||||
"--profile=high-quality",
|
||||
"--video-sync=display-resample",
|
||||
"--interpolation",
|
||||
"--tscale=oversample"
|
||||
].join(" ");
|
||||
|
||||
function mpvpaperRun(filePath) {
|
||||
return "mpvpaper -o '" + mpvpaperOptions + "' '*' \"" + filePath + "\" >/dev/null 2>&1 & disown";
|
||||
}
|
||||
|
||||
function wallpaperCommand(entry) {
|
||||
if (entry.isVideo)
|
||||
return mpvpaperKill + "; " + mpvpaperRun(entry.filePath);
|
||||
return mpvpaperKill;
|
||||
}
|
||||
Reference in New Issue
Block a user