Compare commits

..

17 Commits

Author SHA1 Message Date
arabianq e67f174a59 change version to 1.12.0 2026-06-04 20:18:56 +03:00
arabianq 6545431ac2 deps: update cargo-sources.json 2026-06-04 20:17:27 +03:00
arabianq 026ef97a72 deps: cargo update 2026-06-04 20:16:59 +03:00
arabianq 9f833cc30b deps: update rodio 2026-06-04 20:16:35 +03:00
Tarasov Aleksandr 410a2c7959 feat(gui): sorting options (#134)
* feat(gui): added an ability to copy ```pwsp-cli action play``` command for every sound

* feat(gui): added files sorting options
2026-06-04 20:14:28 +03:00
Tarasov Aleksandr c173e602ad feat(gui): added an ability to copy ``pwsp-cli action play`` command for every sound (#133) 2026-06-04 20:06:35 +03:00
arabianq 3576c634fd packages(rpm): update version macro to use git describe for accurate versioning 2026-06-03 22:35:33 +03:00
arabianq 5747f39ace packages(rpm): fix version macro in spec file 2026-06-03 22:27:03 +03:00
arabianq c501033834 packages(rpm): fix source and setup macros in spec file 2026-06-03 21:26:16 +03:00
arabianq c0a27e0c3b packages(rpm): fix VCS macro in spec file 2026-06-03 21:23:55 +03:00
arabianq 3c2882ef1f packages(rpm): update version and changelog macros 2026-06-03 21:20:18 +03:00
arabianq 36aed3f55d packages(rpm): add copr-cli installation and trigger build step 2026-06-03 21:18:17 +03:00
arabianq c48a425bb0 packages(rpm): update version and source macros 2026-06-03 21:07:07 +03:00
arabianq 9a5436cd35 packages(rpm): add gcc 13 as BuildRequires for openSUSE compatibility 2026-06-03 20:01:54 +03:00
arabianq 2ce243e896 packages(rpm): replace pkgconf-pkg-config with pkgconfig in BuildRequires 2026-06-03 19:49:55 +03:00
arabianq 57fb3fd7a3 packages(rpm): unify BuildRequires for openSUSE compatibility 2026-06-03 18:48:17 +03:00
arabianq 82b02bf520 packages(rpm): fix builds for opensuse (maybe) 2026-06-03 18:26:29 +03:00
15 changed files with 337 additions and 54 deletions
+16
View File
@@ -244,3 +244,19 @@ jobs:
files: | files: |
./dist/pwsp-*.zip ./dist/pwsp-*.zip
./dist/*.deb ./dist/*.deb
- name: Install copr-cli
run: pip install copr-cli
- name: Trigger Copr Build
env:
COPR_CONFIG: ${{ secrets.COPR_CONFIG }}
run: |
mkdir -p ~/.config
echo "$COPR_CONFIG" > ~/.config/copr
copr-cli buildscm --clone-url https://github.com/arabianq/pipewire-soundpad.git \
--commit ${{ needs.prepare.outputs.tag }} \
--spec packages/rpm/pwsp.spec \
--name pwsp \
arabianq/pipewire-soundpad
Generated
+10 -10
View File
@@ -776,7 +776,7 @@ dependencies = [
[[package]] [[package]]
name = "cpal" name = "cpal"
version = "0.18.0" version = "0.18.0"
source = "git+https://github.com/RustAudio/cpal#d2a268839bf9ada7c2477c8a5f9483c28aa12d0c" source = "git+https://github.com/RustAudio/cpal#004897773f17fa15afbc3270b7cca37cfbbdef2a"
dependencies = [ dependencies = [
"alsa", "alsa",
"block2 0.6.2", "block2 0.6.2",
@@ -2306,9 +2306,9 @@ dependencies = [
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.31" version = "0.4.32"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "113b30b4cd05f7c06868fdb2854f66a7b9fece9a48425351cd532e810d74024f" checksum = "953f07c43838f8e6f9758cab68bf5bed85465e7587ebe0b823f1bcd81978ad3a"
[[package]] [[package]]
name = "lru-slab" name = "lru-slab"
@@ -3280,7 +3280,7 @@ checksum = "3d595e54a326bc53c1c197b32d295e14b169e3cfeaa8dc82b529f947fba6bcf5"
[[package]] [[package]]
name = "pwsp-cli" name = "pwsp-cli"
version = "1.11.0" version = "1.12.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"clap", "clap",
@@ -3291,7 +3291,7 @@ dependencies = [
[[package]] [[package]]
name = "pwsp-daemon" name = "pwsp-daemon"
version = "1.11.0" version = "1.12.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"clap", "clap",
@@ -3303,7 +3303,7 @@ dependencies = [
[[package]] [[package]]
name = "pwsp-gui" name = "pwsp-gui"
version = "1.11.0" version = "1.12.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"eframe", "eframe",
@@ -3327,7 +3327,7 @@ dependencies = [
[[package]] [[package]]
name = "pwsp-lib" name = "pwsp-lib"
version = "1.11.0" version = "1.12.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@@ -3686,7 +3686,7 @@ checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422"
[[package]] [[package]]
name = "rodio" name = "rodio"
version = "0.22.2" version = "0.22.2"
source = "git+https://github.com/arabianq/rodio.git?rev=a634dd471e9d59196e19bf01323fb45f2f899821#a634dd471e9d59196e19bf01323fb45f2f899821" source = "git+https://github.com/arabianq/rodio.git?rev=c6a81b5a46e00a6a682c0c431dff62e86f57d819#c6a81b5a46e00a6a682c0c431dff62e86f57d819"
dependencies = [ dependencies = [
"cpal", "cpal",
"dasp_sample", "dasp_sample",
@@ -5967,9 +5967,9 @@ checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f"
[[package]] [[package]]
name = "yoke" name = "yoke"
version = "0.8.2" version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5"
dependencies = [ dependencies = [
"stable_deref_trait", "stable_deref_trait",
"yoke-derive", "yoke-derive",
+2 -2
View File
@@ -8,7 +8,7 @@ members = [
resolver = "2" resolver = "2"
[workspace.package] [workspace.package]
version = "1.11.0" version = "1.12.0"
edition = "2024" edition = "2024"
authors = ["arabian"] authors = ["arabian"]
homepage = "https://pwsp.arabianq.ru" homepage = "https://pwsp.arabianq.ru"
@@ -52,7 +52,7 @@ rustix = { version = "1.1.4", features = ["process"] }
rust-i18n = "4.0.0" rust-i18n = "4.0.0"
sys-locale = "0.3.2" sys-locale = "0.3.2"
rodio = { git = "https://github.com/arabianq/rodio.git", rev = "a634dd471e9d59196e19bf01323fb45f2f899821", default-features = false, features = [ rodio = { git = "https://github.com/arabianq/rodio.git", rev = "c6a81b5a46e00a6a682c0c431dff62e86f57d819", default-features = false, features = [
"symphonia-all", "symphonia-all",
"symphonia-libopus", "symphonia-libopus",
"playback", "playback",
+4 -4
View File
@@ -1,6 +1,6 @@
pkgbase = pwsp-bin pkgbase = pwsp-bin
pkgdesc = Lets you play audio files through your microphone (Pre-built binaries) pkgdesc = Lets you play audio files through your microphone (Pre-built binaries)
pkgver = 1.11.0 pkgver = 1.12.0
pkgrel = 1 pkgrel = 1
url = https://github.com/arabianq/pipewire-soundpad url = https://github.com/arabianq/pipewire-soundpad
arch = x86_64 arch = x86_64
@@ -10,11 +10,11 @@ pkgbase = pwsp-bin
depends = alsa-lib depends = alsa-lib
provides = pwsp provides = pwsp
conflicts = pwsp conflicts = pwsp
source = pipewire-soundpad-1.11.0.tar.gz :: https://github.com/arabianq/pipewire-soundpad/archive/refs/tags/v1.11.0.tar.gz source = pipewire-soundpad-1.12.0.tar.gz :: https://github.com/arabianq/pipewire-soundpad/archive/refs/tags/v1.12.0.tar.gz
sha256sums = SKIP sha256sums = SKIP
source_x86_64 = pwsp-1.11.0-x86_64.zip :: https://github.com/arabianq/pipewire-soundpad/releases/download/v1.11.0/pwsp-v1.11.0-linux-x64.zip source_x86_64 = pwsp-1.12.0-x86_64.zip :: https://github.com/arabianq/pipewire-soundpad/releases/download/v1.12.0/pwsp-v1.12.0-linux-x64.zip
sha256sums_x86_64 = SKIP sha256sums_x86_64 = SKIP
source_aarch64 = pwsp-1.11.0-aarch64.zip :: https://github.com/arabianq/pipewire-soundpad/releases/download/v1.11.0/pwsp-v1.11.0-linux-arm64.zip source_aarch64 = pwsp-1.12.0-aarch64.zip :: https://github.com/arabianq/pipewire-soundpad/releases/download/v1.12.0/pwsp-v1.12.0-linux-arm64.zip
sha256sums_aarch64 = SKIP sha256sums_aarch64 = SKIP
pkgname = pwsp-bin pkgname = pwsp-bin
+1 -1
View File
@@ -1,7 +1,7 @@
# Maintainer: Alexander Tarasov <a.tevg@ya.ru> # Maintainer: Alexander Tarasov <a.tevg@ya.ru>
pkgname=pwsp-bin pkgname=pwsp-bin
_pkgname=pipewire-soundpad _pkgname=pipewire-soundpad
pkgver=1.11.0 pkgver=1.12.0
pkgrel=1 pkgrel=1
pkgdesc="Lets you play audio files through your microphone (Pre-built binaries)" pkgdesc="Lets you play audio files through your microphone (Pre-built binaries)"
arch=('x86_64' 'aarch64') arch=('x86_64' 'aarch64')
+2 -2
View File
@@ -1,6 +1,6 @@
pkgbase = pwsp pkgbase = pwsp
pkgdesc = Lets you play audio files through your microphone pkgdesc = Lets you play audio files through your microphone
pkgver = 1.11.0 pkgver = 1.12.0
pkgrel = 1 pkgrel = 1
url = https://github.com/arabianq/pipewire-soundpad url = https://github.com/arabianq/pipewire-soundpad
arch = x86_64 arch = x86_64
@@ -12,7 +12,7 @@ pkgbase = pwsp
makedepends = cmake makedepends = cmake
makedepends = pipewire makedepends = pipewire
makedepends = alsa-lib makedepends = alsa-lib
source = https://github.com/arabianq/pipewire-soundpad/archive/refs/tags/v1.11.0.tar.gz source = https://github.com/arabianq/pipewire-soundpad/archive/refs/tags/v1.12.0.tar.gz
sha256sums = SKIP sha256sums = SKIP
pkgname = pwsp pkgname = pwsp
+1 -1
View File
@@ -1,7 +1,7 @@
# Maintainer: Alexander Tarasov <a.tevg@ya.ru> # Maintainer: Alexander Tarasov <a.tevg@ya.ru>
pkgsubn=pwsp pkgsubn=pwsp
pkgname=pwsp pkgname=pwsp
pkgver=1.11.0 pkgver=1.12.0
pkgrel=1 pkgrel=1
pkgdesc="Lets you play audio files through your microphone" pkgdesc="Lets you play audio files through your microphone"
arch=('x86_64' 'aarch64') arch=('x86_64' 'aarch64')
File diff suppressed because one or more lines are too long
@@ -25,7 +25,7 @@
<name>arabian</name> <name>arabian</name>
</developer> </developer>
<releases> <releases>
<release version="1.11.0" date="2026-06-02" /> <release version="1.12.0" date="2026-06-04" />
</releases> </releases>
<content_rating type="oars-1.1" /> <content_rating type="oars-1.1" />
</component> </component>
+23 -5
View File
@@ -6,7 +6,7 @@
%global debug_package %{nil} %global debug_package %{nil}
Name: pwsp-git Name: pwsp-git
Version: {{{ git_dir_version }}} Version: {{{ git describe --tags --always | sed 's/^v//' | sed -E 's/-([0-9]+)-(g[0-9a-f]+)/^git.\1.\2/' }}}
Release: 1%{?dist} Release: 1%{?dist}
Summary: Lets you play audio files through your microphone (git version) Summary: Lets you play audio files through your microphone (git version)
@@ -14,16 +14,27 @@ License: MIT
URL: https://github.com/arabianq/pipewire-soundpad URL: https://github.com/arabianq/pipewire-soundpad
VCS: {{{ git_dir_vcs }}} VCS: {{{ git_dir_vcs }}}
Source: {{{ git_dir_pack }}} Source: {{{ git_cwd_pack }}}
BuildRequires: rust BuildRequires: rust
BuildRequires: cargo BuildRequires: cargo
BuildRequires: pipewire-devel BuildRequires: pipewire-devel
%if 0%{?suse_version}
BuildRequires: alsa-devel
BuildRequires: dbus-1-devel
%else
BuildRequires: alsa-lib-devel BuildRequires: alsa-lib-devel
BuildRequires: dbus-devel
%endif
BuildRequires: clang-devel BuildRequires: clang-devel
BuildRequires: cmake BuildRequires: cmake
BuildRequires: dbus-devel BuildRequires: pkgconfig
BuildRequires: pkgconf-pkg-config %if 0%{?suse_version} && 0%{?suse_version} <= 1500
BuildRequires: gcc13-c++
%endif
# Declare compatibility and conflicts with the stable package # Declare compatibility and conflicts with the stable package
Provides: pwsp = %{version}-%{release} Provides: pwsp = %{version}-%{release}
@@ -36,11 +47,17 @@ GUI clients. This is the latest development (git) version.}
%description %{_description} %description %{_description}
%prep %prep
{{{ git_dir_setup_macro }}} {{{ git_cwd_setup_macro }}}
%build %build
%if 0%{?suse_version} && 0%{?suse_version} <= 1500
export CC=gcc-13
export CXX=g++-13
%endif
cargo build --release --locked cargo build --release --locked
%install %install
install -Dm755 target/release/pwsp-cli %{buildroot}%{_bindir}/pwsp-cli install -Dm755 target/release/pwsp-cli %{buildroot}%{_bindir}/pwsp-cli
install -Dm755 target/release/pwsp-daemon %{buildroot}%{_bindir}/pwsp-daemon install -Dm755 target/release/pwsp-daemon %{buildroot}%{_bindir}/pwsp-daemon
@@ -63,3 +80,4 @@ install -Dm644 pwsp-gui/assets/pwsp-daemon.service %{buildroot}/usr/lib/systemd/
%changelog %changelog
{{{ git_dir_changelog }}} {{{ git_dir_changelog }}}
+21 -4
View File
@@ -3,7 +3,9 @@
# Fallback macros for systems without rpmautospec (e.g. openSUSE) # Fallback macros for systems without rpmautospec (e.g. openSUSE)
%{!?autorelease: %global autorelease 1} %{!?autorelease: %global autorelease 1}
%{!?autochangelog: %global autochangelog * Tue Jun 02 2026 Arabian <arabianq@github> - %{version}-%{release}\n- Release build} %{!?autochangelog: %global autochangelog \
* Tue Jun 02 2026 Arabian <arabianq@github> - %{version}-%{release}\
- Release build}
# disable debuginfo package generation (debugsourcefiles.list is empty for Rust) # disable debuginfo package generation (debugsourcefiles.list is empty for Rust)
@@ -11,7 +13,7 @@
Name: pwsp Name: pwsp
Version: 1.11.0 Version: 1.12.0
Release: %autorelease Release: %autorelease
Summary: Lets you play audio files through your microphone Summary: Lets you play audio files through your microphone
@@ -23,11 +25,21 @@ Source: https://github.com/arabianq/pipewire-soundpad/archive/refs/tags
BuildRequires: rust BuildRequires: rust
BuildRequires: cargo BuildRequires: cargo
BuildRequires: pipewire-devel BuildRequires: pipewire-devel
%if 0%{?suse_version}
BuildRequires: alsa-devel
BuildRequires: dbus-1-devel
%else
BuildRequires: alsa-lib-devel BuildRequires: alsa-lib-devel
BuildRequires: dbus-devel
%endif
BuildRequires: clang-devel BuildRequires: clang-devel
BuildRequires: cmake BuildRequires: cmake
BuildRequires: dbus-devel BuildRequires: pkgconfig
BuildRequires: pkgconf-pkg-config %if 0%{?suse_version} && 0%{?suse_version} <= 1500
BuildRequires: gcc13-c++
%endif
%global _description %{expand: %global _description %{expand:
PWSP lets you play audio files through your microphone. Has both CLI and PWSP lets you play audio files through your microphone. Has both CLI and
@@ -39,8 +51,13 @@ GUI clients.}
%autosetup -n pipewire-soundpad-%{version} -p1 %autosetup -n pipewire-soundpad-%{version} -p1
%build %build
%if 0%{?suse_version} && 0%{?suse_version} <= 1500
export CC=gcc-13
export CXX=g++-13
%endif
cargo build --release --locked cargo build --release --locked
%install %install
install -Dm755 target/release/pwsp-cli %{buildroot}%{_bindir}/pwsp-cli install -Dm755 target/release/pwsp-cli %{buildroot}%{_bindir}/pwsp-cli
install -Dm755 target/release/pwsp-daemon %{buildroot}%{_bindir}/pwsp-daemon install -Dm755 target/release/pwsp-daemon %{buildroot}%{_bindir}/pwsp-daemon
+66
View File
@@ -70,6 +70,61 @@ kz = "Жою"
he = "הסר" he = "הסר"
pt-BR = "Remover" pt-BR = "Remover"
[gui.context.dirs.sort_by]
en = "Sort by"
ru = "Сортировка"
es = "Ordenar por"
fr = "Trier par"
zh = "排序方式"
ar = "ترتيب حسب"
kz = "Сұрыптау"
he = "מיין לפי"
pt-BR = "Ordenar por"
[gui.sort.alpha_asc]
en = "Alphabetical (A-Z)"
ru = "По алфавиту (А-Я)"
es = "Alfabético (A-Z)"
fr = "Alphabétique (A-Z)"
zh = "字母顺序 (A-Z)"
ar = "أبجدي (A-Z)"
kz = "Әліпби бойынша (А-Я)"
he = "אלפביתי (A-Z)"
pt-BR = "Alfabético (A-Z)"
[gui.sort.alpha_desc]
en = "Alphabetical (Z-A)"
ru = "По алфавиту (Я-А)"
es = "Alfabético (Z-A)"
fr = "Alphabétique (Z-A)"
zh = "字母顺序 (Z-A)"
ar = "أبجدي (Z-A)"
kz = "Әліпби бойынша (Я-А)"
he = "אלפביתי (Z-A)"
pt-BR = "Alfabético (Z-A)"
[gui.sort.date_newest]
en = "Date modified (Newest first)"
ru = "Дата изменения (Сначала новые)"
es = "Fecha de modificación (Más nuevo primero)"
fr = "Date de modification (Plus récent en premier)"
zh = "修改日期 (最新优先)"
ar = "تاريخ التعديل (الأحدث أولاً)"
kz = "Өзгертілген күні (Жаңалары бірінші)"
he = "תאריך שינוי (החדש ביותר ראשון)"
pt-BR = "Data de modificação (Mais novo primeiro)"
[gui.sort.date_oldest]
en = "Date modified (Oldest first)"
ru = "Дата изменения (Сначала старые)"
es = "Fecha de modificación (Más antiguo primero)"
fr = "Date de modification (Plus ancien en premier)"
zh = "修改日期 (最旧优先)"
ar = "تاريخ التعديل (الأقدم أولاً)"
kz = "Өзгертілген күні (Ескілері бірінші)"
he = "תאריך שינוי (הישן ביותר ראשון)"
pt-BR = "Data de modificação (Mais antigo primeiro)"
[gui.context.files.play_solo] [gui.context.files.play_solo]
en = "Play Solo" en = "Play Solo"
ru = "Играть" ru = "Играть"
@@ -125,6 +180,17 @@ kz = "Ыстық пернені тағайындау"
he = "הקצה מקש קיצור" he = "הקצה מקש קיצור"
pt-BR = "Definir tecla de atalho" pt-BR = "Definir tecla de atalho"
[gui.context.files.copy_cli_command]
en = "Copy PWSP-CLI command"
ru = "Скопировать команду для PWSP-CLI"
es = "Copiar comando de PWSP-CLI"
fr = "Copier la commande PWSP-CLI"
zh = "复制 PWSP-CLI 命令"
ar = "نسخ أمر PWSP-CLI"
kz = "PWSP-CLI командасын көшіру"
he = "העתק פקודת PWSP-CLI"
pt-BR = "Copiar comando PWSP-CLI"
# ---------------- # ----------------
# Settings # Settings
# ---------------- # ----------------
+22 -1
View File
@@ -159,6 +159,13 @@ impl SoundpadGui {
pub fn get_filtered_files(&self) -> Vec<PathBuf> { pub fn get_filtered_files(&self) -> Vec<PathBuf> {
let mut files: Vec<PathBuf> = self.app_state.listed_files.iter().cloned().collect(); let mut files: Vec<PathBuf> = self.app_state.listed_files.iter().cloned().collect();
let sort_order = self
.app_state
.current_dir
.as_ref()
.map(|d| self.config.get_sort_order(d))
.unwrap_or_default();
files.sort_by(|a, b| { files.sort_by(|a, b| {
let a_is_dir = a.is_dir(); let a_is_dir = a.is_dir();
let b_is_dir = b.is_dir(); let b_is_dir = b.is_dir();
@@ -167,7 +174,7 @@ impl SoundpadGui {
} else if !a_is_dir && b_is_dir { } else if !a_is_dir && b_is_dir {
Ordering::Greater Ordering::Greater
} else { } else {
a.cmp(b) sort_order.compare(a, b)
} }
}); });
@@ -334,5 +341,19 @@ mod tests {
let filtered_search = gui.get_filtered_files(); let filtered_search = gui.get_filtered_files();
assert_eq!(filtered_search.len(), 1); assert_eq!(filtered_search.len(), 1);
assert_eq!(filtered_search[0], file_c); assert_eq!(filtered_search[0], file_c);
// Test sort order descending
gui.app_state.current_dir = Some(PathBuf::from("dummy_dir"));
gui.config.dirs_settings.insert(
PathBuf::from("dummy_dir"),
pwsp_lib::types::config::DirSettings {
sort_order: pwsp_lib::types::config::SortOrder::AlphabeticalDesc,
},
);
gui.app_state.search_query = String::new();
let filtered_desc = gui.get_filtered_files();
assert_eq!(filtered_desc.len(), 2);
assert_eq!(filtered_desc[0], file_c);
assert_eq!(filtered_desc[1], file_b);
} }
} }
+88 -4
View File
@@ -5,7 +5,10 @@ use egui::{
}; };
use egui_dnd::dnd; use egui_dnd::dnd;
use egui_material_icons::icons::*; use egui_material_icons::icons::*;
use pwsp_lib::types::{gui::AppState, gui::AudioPlayerState}; use pwsp_lib::types::{
config::{GuiConfig, SortOrder},
gui::{AppState, AudioPlayerState},
};
use rust_i18n::t; use rust_i18n::t;
use std::{cmp::Ordering, path::Path, path::PathBuf}; use std::{cmp::Ordering, path::Path, path::PathBuf};
@@ -135,6 +138,65 @@ impl SoundpadGui {
{ {
self.app_state.dirs_to_remove.insert(path.clone()); self.app_state.dirs_to_remove.insert(path.clone());
} }
ui.separator();
ui.label(t!("gui.context.dirs.sort_by"));
let current_order = self
.config
.dirs_settings
.get(path)
.map(|s| s.sort_order)
.unwrap_or_default();
let mut new_order = None;
if ui
.radio(
current_order == SortOrder::AlphabeticalAsc,
t!("gui.sort.alpha_asc"),
)
.clicked()
{
new_order = Some(SortOrder::AlphabeticalAsc);
}
if ui
.radio(
current_order == SortOrder::AlphabeticalDesc,
t!("gui.sort.alpha_desc"),
)
.clicked()
{
new_order = Some(SortOrder::AlphabeticalDesc);
}
if ui
.radio(
current_order == SortOrder::DateModifiedNewest,
t!("gui.sort.date_newest"),
)
.clicked()
{
new_order = Some(SortOrder::DateModifiedNewest);
}
if ui
.radio(
current_order == SortOrder::DateModifiedOldest,
t!("gui.sort.date_oldest"),
)
.clicked()
{
new_order = Some(SortOrder::DateModifiedOldest);
}
if let Some(order) = new_order {
self.config
.dirs_settings
.entry(path.clone())
.or_default()
.sort_order = order;
self.config.save_to_file().ok();
self.app_state.dir_cache.remove(path);
self.open_dir(path);
}
}); });
}); });
}); });
@@ -192,6 +254,7 @@ impl SoundpadGui {
Self::draw_tree_node( Self::draw_tree_node(
ui, ui,
entry_path, entry_path,
&self.config,
&mut self.app_state, &mut self.app_state,
&self.audio_player_state, &self.audio_player_state,
&mut actions, &mut actions,
@@ -226,6 +289,7 @@ impl SoundpadGui {
fn draw_tree_node_dir( fn draw_tree_node_dir(
ui: &mut Ui, ui: &mut Ui,
path: std::path::PathBuf, path: std::path::PathBuf,
config: &GuiConfig,
app_state: &mut AppState, app_state: &mut AppState,
audio_player_state: &AudioPlayerState, audio_player_state: &AudioPlayerState,
actions: &mut Vec<FileAction>, actions: &mut Vec<FileAction>,
@@ -247,6 +311,7 @@ impl SoundpadGui {
read.push(entry.path()); read.push(entry.path());
} }
} }
let sort_order = config.get_sort_order(&path);
read.sort_by(|a, b| { read.sort_by(|a, b| {
let a_is_dir = a.is_dir(); let a_is_dir = a.is_dir();
let b_is_dir = b.is_dir(); let b_is_dir = b.is_dir();
@@ -255,7 +320,7 @@ impl SoundpadGui {
} else if !a_is_dir && b_is_dir { } else if !a_is_dir && b_is_dir {
Ordering::Greater Ordering::Greater
} else { } else {
a.cmp(b) sort_order.compare(a, b)
} }
}); });
app_state.dir_cache.insert(path.clone(), read.clone()); app_state.dir_cache.insert(path.clone(), read.clone());
@@ -287,7 +352,7 @@ impl SoundpadGui {
} }
} }
} }
Self::draw_tree_node(ui, child, app_state, audio_player_state, actions); Self::draw_tree_node(ui, child, config, app_state, audio_player_state, actions);
} }
}); });
} }
@@ -412,6 +477,24 @@ impl SoundpadGui {
actions.push(FileAction::AssignHotkey(path.clone())); actions.push(FileAction::AssignHotkey(path.clone()));
ui.close(); ui.close();
} }
ui.separator();
if ui
.button(format!(
"{} {}",
ICON_FILE_COPY.codepoint,
t!("gui.context.files.copy_cli_command")
))
.clicked()
{
ui.ctx().copy_text(format!(
"pwsp-cli action play \"{}\"",
path.to_string_lossy()
.replace('\\', "\\\\")
.replace('"', "\\\"")
));
}
}); });
}); });
} }
@@ -419,12 +502,13 @@ impl SoundpadGui {
fn draw_tree_node( fn draw_tree_node(
ui: &mut Ui, ui: &mut Ui,
path: std::path::PathBuf, path: std::path::PathBuf,
config: &GuiConfig,
app_state: &mut AppState, app_state: &mut AppState,
audio_player_state: &AudioPlayerState, audio_player_state: &AudioPlayerState,
actions: &mut Vec<FileAction>, actions: &mut Vec<FileAction>,
) { ) {
if path.is_dir() { if path.is_dir() {
Self::draw_tree_node_dir(ui, path, app_state, audio_player_state, actions); Self::draw_tree_node_dir(ui, path, config, app_state, audio_player_state, actions);
} else { } else {
Self::draw_tree_node_file(ui, path, app_state, audio_player_state, actions); Self::draw_tree_node_file(ui, path, app_state, audio_player_state, actions);
} }
+62 -1
View File
@@ -4,7 +4,13 @@ use crate::{
}; };
use anyhow::Result; use anyhow::Result;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{collections::HashMap, fs, path::PathBuf}; use std::{
cmp::Ordering,
collections::HashMap,
fs,
path::{Path, PathBuf},
time::SystemTime,
};
#[derive(Default, Clone, Serialize, Deserialize)] #[derive(Default, Clone, Serialize, Deserialize)]
#[serde(default)] #[serde(default)]
@@ -45,6 +51,21 @@ pub enum PreferredTheme {
Dark, Dark,
} }
#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
pub enum SortOrder {
#[default]
AlphabeticalAsc,
AlphabeticalDesc,
DateModifiedNewest,
DateModifiedOldest,
}
#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(default)]
pub struct DirSettings {
pub sort_order: SortOrder,
}
#[derive(Clone, Serialize, Deserialize)] #[derive(Clone, Serialize, Deserialize)]
#[serde(default)] #[serde(default)]
pub struct GuiConfig { pub struct GuiConfig {
@@ -57,10 +78,38 @@ pub struct GuiConfig {
pub pause_on_exit: bool, pub pause_on_exit: bool,
pub dirs: Vec<PathBuf>, pub dirs: Vec<PathBuf>,
pub dirs_settings: HashMap<PathBuf, DirSettings>,
pub preferred_theme: PreferredTheme, pub preferred_theme: PreferredTheme,
} }
impl SortOrder {
pub fn compare(&self, a: &Path, b: &Path) -> Ordering {
match self {
SortOrder::AlphabeticalAsc => a.cmp(b),
SortOrder::AlphabeticalDesc => b.cmp(a),
SortOrder::DateModifiedNewest => {
let a_time = fs::metadata(a)
.and_then(|m| m.modified())
.unwrap_or(SystemTime::UNIX_EPOCH);
let b_time = fs::metadata(b)
.and_then(|m| m.modified())
.unwrap_or(SystemTime::UNIX_EPOCH);
b_time.cmp(&a_time)
}
SortOrder::DateModifiedOldest => {
let a_time = fs::metadata(a)
.and_then(|m| m.modified())
.unwrap_or(SystemTime::UNIX_EPOCH);
let b_time = fs::metadata(b)
.and_then(|m| m.modified())
.unwrap_or(SystemTime::UNIX_EPOCH);
a_time.cmp(&b_time)
}
}
}
}
impl Default for GuiConfig { impl Default for GuiConfig {
fn default() -> Self { fn default() -> Self {
GuiConfig { GuiConfig {
@@ -75,11 +124,23 @@ impl Default for GuiConfig {
dirs: vec![ensure_pwsp_audio_dir()], dirs: vec![ensure_pwsp_audio_dir()],
preferred_theme: PreferredTheme::System, preferred_theme: PreferredTheme::System,
dirs_settings: HashMap::new(),
} }
} }
} }
impl GuiConfig { impl GuiConfig {
pub fn get_sort_order(&self, path: &Path) -> SortOrder {
let mut current = Some(path);
while let Some(p) = current {
if let Some(settings) = self.dirs_settings.get(p) {
return settings.sort_order;
}
current = p.parent();
}
SortOrder::default()
}
pub fn save_to_file(&mut self) -> Result<()> { pub fn save_to_file(&mut self) -> Result<()> {
let config_path = get_config_path()?.join("gui.json"); let config_path = get_config_path()?.join("gui.json");