mirror of
https://github.com/arabianq/pipewire-soundpad.git
synced 2026-04-28 06:21:23 +00:00
feat(gui): now directories can be reordered using drag and drop
This commit is contained in:
+13
-7
@@ -3,10 +3,11 @@ use egui::{
|
||||
Align, AtomExt, Button, CollapsingHeader, Color32, ComboBox, CursorIcon, FontFamily, Label,
|
||||
Layout, RichText, ScrollArea, Sense, Slider, TextEdit, Ui, Vec2,
|
||||
};
|
||||
use egui_dnd::dnd;
|
||||
use egui_material_icons::icons;
|
||||
use pwsp::types::audio_player::TrackInfo;
|
||||
use pwsp::utils::gui::format_time_pair;
|
||||
use std::{error::Error, path::PathBuf, time::Instant};
|
||||
use std::{error::Error, time::Instant};
|
||||
|
||||
use pwsp::types::gui::AppState;
|
||||
|
||||
@@ -301,10 +302,14 @@ impl SoundpadGui {
|
||||
ScrollArea::vertical().id_salt(0).show(ui, |ui| {
|
||||
ui.set_min_width(area_size.x);
|
||||
|
||||
let mut dirs: Vec<PathBuf> = self.app_state.dirs.iter().cloned().collect();
|
||||
dirs.sort();
|
||||
for path in dirs.iter() {
|
||||
let mut dirs = self.app_state.dirs.clone();
|
||||
|
||||
dnd(ui, "dnd_directories").show_vec(&mut dirs, |ui, item, handle, _state| {
|
||||
let path = item.clone();
|
||||
ui.horizontal(|ui| {
|
||||
handle.ui(ui, |ui| {
|
||||
ui.label(icons::ICON_DRAG_INDICATOR);
|
||||
});
|
||||
let name = path
|
||||
.file_name()
|
||||
.map(|s| s.to_string_lossy().to_string())
|
||||
@@ -312,7 +317,7 @@ impl SoundpadGui {
|
||||
|
||||
let mut dir_button_text = RichText::new(name.clone());
|
||||
if let Some(current_dir) = &self.app_state.current_dir {
|
||||
if current_dir.eq(path) {
|
||||
if current_dir.eq(&path) {
|
||||
dir_button_text = dir_button_text.color(Color32::WHITE);
|
||||
}
|
||||
}
|
||||
@@ -322,7 +327,7 @@ impl SoundpadGui {
|
||||
|
||||
let dir_button_response = ui.add(dir_button);
|
||||
if dir_button_response.clicked() {
|
||||
self.open_dir(path);
|
||||
self.open_dir(&path);
|
||||
}
|
||||
|
||||
let delete_dir_button = Button::new(icons::ICON_DELETE).frame(false);
|
||||
@@ -332,7 +337,8 @@ impl SoundpadGui {
|
||||
self.remove_dir(&path.clone());
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
self.app_state.dirs = dirs;
|
||||
|
||||
ui.horizontal(|ui| {
|
||||
let add_dirs_button = Button::new(icons::ICON_ADD).frame(false);
|
||||
|
||||
+4
-2
@@ -4,6 +4,7 @@ mod update;
|
||||
|
||||
use eframe::{HardwareAcceleration, NativeOptions, icon_data::from_png_bytes, run_native};
|
||||
use egui::{Context, Vec2, ViewportBuilder};
|
||||
use itertools::Itertools;
|
||||
use pwsp::{
|
||||
types::{
|
||||
audio_player::PlayerState,
|
||||
@@ -87,15 +88,16 @@ impl SoundpadGui {
|
||||
let file_dialog = FileDialog::new();
|
||||
if let Some(paths) = file_dialog.pick_folders() {
|
||||
for path in paths {
|
||||
self.app_state.dirs.insert(path);
|
||||
self.app_state.dirs.push(path);
|
||||
}
|
||||
self.app_state.dirs = self.app_state.dirs.iter().unique().cloned().collect();
|
||||
self.config.dirs = self.app_state.dirs.clone();
|
||||
self.config.save_to_file().ok();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove_dir(&mut self, path: &PathBuf) {
|
||||
self.app_state.dirs.remove(path);
|
||||
self.app_state.dirs.retain(|x| x != path);
|
||||
if let Some(current_dir) = &self.app_state.current_dir
|
||||
&& current_dir == path
|
||||
{
|
||||
|
||||
@@ -9,6 +9,13 @@ use std::time::{Duration, Instant};
|
||||
|
||||
impl App for SoundpadGui {
|
||||
fn update(&mut self, ctx: &Context, _frame: &mut EFrame) {
|
||||
// Save directories if changed
|
||||
if !self.config.dirs.eq(&self.app_state.dirs) {
|
||||
self.config.dirs = self.app_state.dirs.clone();
|
||||
self.config.save_to_file().ok();
|
||||
}
|
||||
|
||||
// Seek and volume requests
|
||||
let mut seek_requests = vec![];
|
||||
let mut volume_requests = vec![];
|
||||
|
||||
@@ -57,11 +64,13 @@ impl App for SoundpadGui {
|
||||
}
|
||||
}
|
||||
|
||||
// Sync audio player state
|
||||
{
|
||||
let guard = self.audio_player_state_shared.lock().unwrap();
|
||||
self.audio_player_state = guard.clone();
|
||||
}
|
||||
|
||||
// Handle scale factor changes
|
||||
let old_scale_factor = self.config.scale_factor;
|
||||
let new_scale_factor = ctx.zoom_factor().clamp(0.5, 2.0);
|
||||
|
||||
@@ -72,8 +81,10 @@ impl App for SoundpadGui {
|
||||
self.config.save_to_file().ok();
|
||||
}
|
||||
|
||||
// Handle input
|
||||
self.handle_input(ctx);
|
||||
|
||||
// Draw UI
|
||||
CentralPanel::default().show(ctx, |ui| {
|
||||
if !self.audio_player_state.is_daemon_running {
|
||||
self.draw_waiting_for_daemon(ui);
|
||||
@@ -88,6 +99,7 @@ impl App for SoundpadGui {
|
||||
self.draw(ui).ok();
|
||||
});
|
||||
|
||||
// Request repaint
|
||||
ctx.request_repaint_after_secs(1.0 / 60.0);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
use crate::utils::config::get_config_path;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{collections::HashSet, error::Error, fs, path::PathBuf};
|
||||
use std::{error::Error, fs, path::PathBuf};
|
||||
|
||||
#[derive(Default, Clone, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
@@ -41,7 +41,7 @@ pub struct GuiConfig {
|
||||
pub save_scale_factor: bool,
|
||||
pub pause_on_exit: bool,
|
||||
|
||||
pub dirs: HashSet<PathBuf>,
|
||||
pub dirs: Vec<PathBuf>,
|
||||
}
|
||||
|
||||
impl Default for GuiConfig {
|
||||
@@ -55,7 +55,7 @@ impl Default for GuiConfig {
|
||||
save_scale_factor: false,
|
||||
pause_on_exit: false,
|
||||
|
||||
dirs: HashSet::default(),
|
||||
dirs: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ pub struct AppState {
|
||||
pub ignore_volume_update_until: Option<Instant>,
|
||||
|
||||
pub current_dir: Option<PathBuf>,
|
||||
pub dirs: HashSet<PathBuf>,
|
||||
pub dirs: Vec<PathBuf>,
|
||||
|
||||
pub selected_file: Option<PathBuf>,
|
||||
pub files: HashSet<PathBuf>,
|
||||
|
||||
Reference in New Issue
Block a user