mirror of
https://github.com/arabianq/pipewire-soundpad.git
synced 2026-06-19 20:23:33 +00:00
Compare commits
4 Commits
v1.9.0
..
78960cdc10
| Author | SHA1 | Date | |
|---|---|---|---|
| 78960cdc10 | |||
| 0439cf815e | |||
| 5ae82ef28c | |||
| 5f69345d45 |
+35
-2
@@ -13,6 +13,7 @@ zh = "播放文件"
|
|||||||
ar = "تشغيل الملف"
|
ar = "تشغيل الملف"
|
||||||
kz = "Файлды ойнату"
|
kz = "Файлды ойнату"
|
||||||
he = "נגן קובץ"
|
he = "נגן קובץ"
|
||||||
|
pt-BR = "Reproduzir arquivo"
|
||||||
|
|
||||||
[gui.choose_mic_select]
|
[gui.choose_mic_select]
|
||||||
en = "Select microphone"
|
en = "Select microphone"
|
||||||
@@ -23,6 +24,7 @@ zh = "选择麦克风"
|
|||||||
ar = "اختر الميكروفون"
|
ar = "اختر الميكروفون"
|
||||||
kz = "Микрофонды таңдау"
|
kz = "Микрофонды таңдау"
|
||||||
he = "בחר מיקרופון"
|
he = "בחר מיקרופון"
|
||||||
|
pt-BR = "Selecionar microfone"
|
||||||
|
|
||||||
[gui.search_placeholder]
|
[gui.search_placeholder]
|
||||||
en = "Search files..."
|
en = "Search files..."
|
||||||
@@ -33,6 +35,7 @@ zh = "搜索文件..."
|
|||||||
ar = "البحث عن ملفات..."
|
ar = "البحث عن ملفات..."
|
||||||
kz = "Файлдарды іздеу..."
|
kz = "Файлдарды іздеу..."
|
||||||
he = "חפש קבצים..."
|
he = "חפש קבצים..."
|
||||||
|
pt-BR = "Buscar arquivos..."
|
||||||
|
|
||||||
[gui.context.dirs.open]
|
[gui.context.dirs.open]
|
||||||
en = "Open"
|
en = "Open"
|
||||||
@@ -43,6 +46,7 @@ zh = "打开"
|
|||||||
ar = "فتح"
|
ar = "فتح"
|
||||||
kz = "Ашу"
|
kz = "Ашу"
|
||||||
he = "פתח"
|
he = "פתח"
|
||||||
|
pt-BR = "Abrir"
|
||||||
|
|
||||||
[gui.context.dirs.open_in_fm]
|
[gui.context.dirs.open_in_fm]
|
||||||
en = "Open in File Manager"
|
en = "Open in File Manager"
|
||||||
@@ -53,6 +57,7 @@ zh = "在文件管理器中打开"
|
|||||||
ar = "فتح في مدير الملفات"
|
ar = "فتح في مدير الملفات"
|
||||||
kz = "Файл менеджерінде ашу"
|
kz = "Файл менеджерінде ашу"
|
||||||
he = "פתח במנהל הקבצים"
|
he = "פתח במנהל הקבצים"
|
||||||
|
pt-BR = "Abrir no gestor de arquivos"
|
||||||
|
|
||||||
[gui.context.dirs.remove]
|
[gui.context.dirs.remove]
|
||||||
en = "Remove"
|
en = "Remove"
|
||||||
@@ -63,6 +68,7 @@ zh = "移除"
|
|||||||
ar = "إزالة"
|
ar = "إزالة"
|
||||||
kz = "Жою"
|
kz = "Жою"
|
||||||
he = "הסר"
|
he = "הסר"
|
||||||
|
pt-BR = "Remover"
|
||||||
|
|
||||||
[gui.context.files.play_solo]
|
[gui.context.files.play_solo]
|
||||||
en = "Play Solo"
|
en = "Play Solo"
|
||||||
@@ -73,6 +79,7 @@ zh = "单独播放"
|
|||||||
ar = "تشغيل منفرد"
|
ar = "تشغيل منفرد"
|
||||||
kz = "Жалғыз ойнату"
|
kz = "Жалғыз ойнату"
|
||||||
he = "נגן סולו"
|
he = "נגן סולו"
|
||||||
|
pt-BR = "Reproduzir"
|
||||||
|
|
||||||
[gui.context.files.add_new]
|
[gui.context.files.add_new]
|
||||||
en = "Add New"
|
en = "Add New"
|
||||||
@@ -83,6 +90,7 @@ zh = "添加新项"
|
|||||||
ar = "إضافة جديد"
|
ar = "إضافة جديد"
|
||||||
kz = "Жаңасын қосу"
|
kz = "Жаңасын қосу"
|
||||||
he = "הוסף חדש"
|
he = "הוסף חדש"
|
||||||
|
pt-BR = "Adicionar"
|
||||||
|
|
||||||
[gui.context.files.replace_last]
|
[gui.context.files.replace_last]
|
||||||
en = "Replace Last"
|
en = "Replace Last"
|
||||||
@@ -93,6 +101,7 @@ zh = "替换上一个"
|
|||||||
ar = "استبدال الأخير"
|
ar = "استبدال الأخير"
|
||||||
kz = "Соңғысын ауыстыру"
|
kz = "Соңғысын ауыстыру"
|
||||||
he = "החלף אחרון"
|
he = "החלף אחרון"
|
||||||
|
pt-BR = "Substituir"
|
||||||
|
|
||||||
[gui.context.files.show_in_fm]
|
[gui.context.files.show_in_fm]
|
||||||
en = "Show in File Manager"
|
en = "Show in File Manager"
|
||||||
@@ -103,9 +112,10 @@ zh = "在文件管理器中显示"
|
|||||||
ar = "عرض في مدير الملفات"
|
ar = "عرض في مدير الملفات"
|
||||||
kz = "Файл менеджерінде көрсету"
|
kz = "Файл менеджерінде көрсету"
|
||||||
he = "הצג במנהל הקבצים"
|
he = "הצג במנהל הקבצים"
|
||||||
|
pt-BR = "Mostrar no gestor de arquivos"
|
||||||
|
|
||||||
[gui.context.files.asign_hotkey]
|
[gui.context.files.asign_hotkey]
|
||||||
en = "Asign Hotkey"
|
en = "Assign Hotkey"
|
||||||
ru = "Назначить Горячую Клавишу"
|
ru = "Назначить Горячую Клавишу"
|
||||||
es = "Asignar atajo"
|
es = "Asignar atajo"
|
||||||
fr = "Assigner un raccourci"
|
fr = "Assigner un raccourci"
|
||||||
@@ -113,6 +123,7 @@ zh = "分配快捷键"
|
|||||||
ar = "تعيين مفتاح اختصار"
|
ar = "تعيين مفتاح اختصار"
|
||||||
kz = "Ыстық пернені тағайындау"
|
kz = "Ыстық пернені тағайындау"
|
||||||
he = "הקצה מקש קיצור"
|
he = "הקצה מקש קיצור"
|
||||||
|
pt-BR = "Definir tecla de atalho"
|
||||||
|
|
||||||
# ----------------
|
# ----------------
|
||||||
# Settings
|
# Settings
|
||||||
@@ -127,6 +138,7 @@ zh = "设置"
|
|||||||
ar = "الإعدادات"
|
ar = "الإعدادات"
|
||||||
kz = "Баптаулар"
|
kz = "Баптаулар"
|
||||||
he = "הגדרות"
|
he = "הגדרות"
|
||||||
|
pt-BR = "Configurações"
|
||||||
|
|
||||||
[gui.settings.remember_volume]
|
[gui.settings.remember_volume]
|
||||||
en = "Always remember volume"
|
en = "Always remember volume"
|
||||||
@@ -137,6 +149,7 @@ zh = "始终记住音量"
|
|||||||
ar = "تذكر مستوى الصوت دائمًا"
|
ar = "تذكر مستوى الصوت دائمًا"
|
||||||
kz = "Әрқашан дыбыс деңгейін есте сақтау"
|
kz = "Әрқашан дыбыс деңгейін есте сақтау"
|
||||||
he = "זכור תמיד עוצמת קול"
|
he = "זכור תמיד עוצמת קול"
|
||||||
|
pt-BR = "Lembrar volume"
|
||||||
|
|
||||||
[gui.settings.remember_mic]
|
[gui.settings.remember_mic]
|
||||||
en = "Always remember microphone"
|
en = "Always remember microphone"
|
||||||
@@ -147,6 +160,7 @@ zh = "始终记住麦克风"
|
|||||||
ar = "تذكر الميكروفون دائمًا"
|
ar = "تذكر الميكروفون دائمًا"
|
||||||
kz = "Әрқашан микрофонды есте сақтау"
|
kz = "Әрқашан микрофонды есте сақтау"
|
||||||
he = "זכור תמיד מיקרופון"
|
he = "זכור תמיד מיקרופון"
|
||||||
|
pt-BR = "Lembrar microfone"
|
||||||
|
|
||||||
[gui.settings.remember_ui_scale]
|
[gui.settings.remember_ui_scale]
|
||||||
en = "Always remember UI scale factor"
|
en = "Always remember UI scale factor"
|
||||||
@@ -157,6 +171,7 @@ zh = "始终记住界面缩放比例"
|
|||||||
ar = "تذكر عامل تكبير الواجهة دائمًا"
|
ar = "تذكر عامل تكبير الواجهة دائمًا"
|
||||||
kz = "Әрқашан интерфейс масштабын есте сақтау"
|
kz = "Әрқашан интерфейс масштабын есте сақтау"
|
||||||
he = "זכור תמיד קנה מידה של ממשק משתמש"
|
he = "זכור תמיד קנה מידה של ממשק משתמש"
|
||||||
|
pt-BR = "Lembrar fator de escala da interface"
|
||||||
|
|
||||||
[gui.settings.pause_on_window_close]
|
[gui.settings.pause_on_window_close]
|
||||||
en = "Pause audio playback when the window is closed"
|
en = "Pause audio playback when the window is closed"
|
||||||
@@ -167,6 +182,7 @@ zh = "关闭窗口时暂停音频播放"
|
|||||||
ar = "إيقاف الصوت مؤقتًا عند إغلاق النافذة"
|
ar = "إيقاف الصوت مؤقتًا عند إغلاق النافذة"
|
||||||
kz = "Терезе жабылған кезде дыбысты ойнатуды кідірту"
|
kz = "Терезе жабылған кезде дыбысты ойнатуды кідірту"
|
||||||
he = "השהה השמעת שמע כאשר החלון נסגר"
|
he = "השהה השמעת שמע כאשר החלון נסגר"
|
||||||
|
pt-BR = "Pausar reprodução de aúdio ao fechar a janela"
|
||||||
|
|
||||||
[gui.settings.version]
|
[gui.settings.version]
|
||||||
en = "GUI version: %{version}"
|
en = "GUI version: %{version}"
|
||||||
@@ -177,6 +193,7 @@ zh = "GUI 版本: %{version}"
|
|||||||
ar = "إصدار الواجهة: %{version}"
|
ar = "إصدار الواجهة: %{version}"
|
||||||
kz = "GUI нұсқасы: %{version}"
|
kz = "GUI нұсқасы: %{version}"
|
||||||
he = "גרסת ממשק משתמש: %{version}"
|
he = "גרסת ממשק משתמש: %{version}"
|
||||||
|
pt-BR = "Versão da GUI: %{version}"
|
||||||
|
|
||||||
# ----------------
|
# ----------------
|
||||||
# Hotkeys
|
# Hotkeys
|
||||||
@@ -191,6 +208,7 @@ zh = "快捷键"
|
|||||||
ar = "اختصارات لوحة المفاتيح"
|
ar = "اختصارات لوحة المفاتيح"
|
||||||
kz = "Ыстық пернелер"
|
kz = "Ыстық пернелер"
|
||||||
he = "מקשי קיצור"
|
he = "מקשי קיצור"
|
||||||
|
pt-BR = "Atalhos"
|
||||||
|
|
||||||
[gui.hotkeys.search_placeholder]
|
[gui.hotkeys.search_placeholder]
|
||||||
en = "Search hotkeys..."
|
en = "Search hotkeys..."
|
||||||
@@ -201,6 +219,7 @@ zh = "搜索快捷键..."
|
|||||||
ar = "البحث عن الاختصارات..."
|
ar = "البحث عن الاختصارات..."
|
||||||
kz = "Ыстық пернелерді іздеу..."
|
kz = "Ыстық пернелерді іздеу..."
|
||||||
he = "חפש מקשי קיצור..."
|
he = "חפש מקשי קיצור..."
|
||||||
|
pt-BR = "Buscar atalhos..."
|
||||||
|
|
||||||
[gui.hotkeys.add_command_select]
|
[gui.hotkeys.add_command_select]
|
||||||
en = "Add Command"
|
en = "Add Command"
|
||||||
@@ -211,6 +230,7 @@ zh = "添加命令"
|
|||||||
ar = "إضافة أمر"
|
ar = "إضافة أمر"
|
||||||
kz = "Команда қосу"
|
kz = "Команда қосу"
|
||||||
he = "הוסף פקודה"
|
he = "הוסף פקודה"
|
||||||
|
pt-BR = "Adicionar comando"
|
||||||
|
|
||||||
[gui.hotkeys.toggle_pause_command]
|
[gui.hotkeys.toggle_pause_command]
|
||||||
en = "Toggle Pause"
|
en = "Toggle Pause"
|
||||||
@@ -221,6 +241,7 @@ zh = "切换暂停"
|
|||||||
ar = "تبديل الإيقاف المؤقت"
|
ar = "تبديل الإيقاف المؤقت"
|
||||||
kz = "Кідіртуді ауыстыру"
|
kz = "Кідіртуді ауыстыру"
|
||||||
he = "הפעל/השהה"
|
he = "הפעל/השהה"
|
||||||
|
pt-BR = "Alternar reprodução"
|
||||||
|
|
||||||
[gui.hotkeys.stop_playback_command]
|
[gui.hotkeys.stop_playback_command]
|
||||||
en = "Stop Playback"
|
en = "Stop Playback"
|
||||||
@@ -231,6 +252,7 @@ zh = "停止播放"
|
|||||||
ar = "إيقاف التشغيل"
|
ar = "إيقاف التشغيل"
|
||||||
kz = "Ойнатуды тоқтату"
|
kz = "Ойнатуды тоқтату"
|
||||||
he = "עצור השמעה"
|
he = "עצור השמעה"
|
||||||
|
pt-BR = "Parar reprodução"
|
||||||
|
|
||||||
[gui.hotkeys.pause_playback_command]
|
[gui.hotkeys.pause_playback_command]
|
||||||
en = "Pause Playback"
|
en = "Pause Playback"
|
||||||
@@ -241,6 +263,7 @@ zh = "暂停播放"
|
|||||||
ar = "إيقاف التشغيل مؤقتاً"
|
ar = "إيقاف التشغيل مؤقتاً"
|
||||||
kz = "Ойнатуды кідірту"
|
kz = "Ойнатуды кідірту"
|
||||||
he = "השהה השמעה"
|
he = "השהה השמעה"
|
||||||
|
pt-BR = "Pausar reprodução"
|
||||||
|
|
||||||
[gui.hotkeys.resume_playback_command]
|
[gui.hotkeys.resume_playback_command]
|
||||||
en = "Resume Playback"
|
en = "Resume Playback"
|
||||||
@@ -251,6 +274,7 @@ zh = "恢复播放"
|
|||||||
ar = "استئناف التشغيل"
|
ar = "استئناف التشغيل"
|
||||||
kz = "Ойнатуды жалғастыру"
|
kz = "Ойнатуды жалғастыру"
|
||||||
he = "המשך השמעה"
|
he = "המשך השמעה"
|
||||||
|
pt-BR = "Resumir reprodução"
|
||||||
|
|
||||||
[gui.hotkeys.toggle_loop_command]
|
[gui.hotkeys.toggle_loop_command]
|
||||||
en = "Toggle Loop"
|
en = "Toggle Loop"
|
||||||
@@ -261,6 +285,7 @@ zh = "切换循环"
|
|||||||
ar = "تبديل التكرار"
|
ar = "تبديل التكرار"
|
||||||
kz = "Қайталауды ауыстыру"
|
kz = "Қайталауды ауыстыру"
|
||||||
he = "הפעל/כבה לולאה"
|
he = "הפעל/כבה לולאה"
|
||||||
|
pt-BR = "Alternar loop"
|
||||||
|
|
||||||
[gui.hotkeys.column_slot]
|
[gui.hotkeys.column_slot]
|
||||||
en = "Slot"
|
en = "Slot"
|
||||||
@@ -271,6 +296,7 @@ zh = "插槽"
|
|||||||
ar = "الخانة"
|
ar = "الخانة"
|
||||||
kz = "Ұяшық"
|
kz = "Ұяшық"
|
||||||
he = "משבצת"
|
he = "משבצת"
|
||||||
|
pt-BR = "Slot"
|
||||||
|
|
||||||
[gui.hotkeys.column_sound]
|
[gui.hotkeys.column_sound]
|
||||||
en = "Sound"
|
en = "Sound"
|
||||||
@@ -281,6 +307,7 @@ zh = "声音"
|
|||||||
ar = "الصوت"
|
ar = "الصوت"
|
||||||
kz = "Дыбыс"
|
kz = "Дыбыс"
|
||||||
he = "צליל"
|
he = "צליל"
|
||||||
|
pt-BR = "Som"
|
||||||
|
|
||||||
[gui.hotkeys.column_key_chord]
|
[gui.hotkeys.column_key_chord]
|
||||||
en = "Key Chord"
|
en = "Key Chord"
|
||||||
@@ -291,6 +318,7 @@ zh = "组合键"
|
|||||||
ar = "تركيبة المفاتيح"
|
ar = "تركيبة المفاتيح"
|
||||||
kz = "Пернелер тіркесімі"
|
kz = "Пернелер тіркесімі"
|
||||||
he = "צירוף מקשים"
|
he = "צירוף מקשים"
|
||||||
|
pt-BR = "Combinação de teclas"
|
||||||
|
|
||||||
[gui.hotkeys.column_actions]
|
[gui.hotkeys.column_actions]
|
||||||
en = "Actions"
|
en = "Actions"
|
||||||
@@ -301,6 +329,7 @@ zh = "操作"
|
|||||||
ar = "الإجراءات"
|
ar = "الإجراءات"
|
||||||
kz = "Әрекеттер"
|
kz = "Әрекеттер"
|
||||||
he = "פעולות"
|
he = "פעולות"
|
||||||
|
pt-BR = "Ações"
|
||||||
|
|
||||||
[gui.hotkeys.no_hotkeys_configured]
|
[gui.hotkeys.no_hotkeys_configured]
|
||||||
en = "No hotkeys configured"
|
en = "No hotkeys configured"
|
||||||
@@ -311,6 +340,7 @@ zh = "未配置快捷键"
|
|||||||
ar = "لا توجد اختصارات معينة"
|
ar = "لا توجد اختصارات معينة"
|
||||||
kz = "Ыстық пернелер бапталмаған"
|
kz = "Ыстық пернелер бапталмаған"
|
||||||
he = "לא הוגדרו מקשי קיצור"
|
he = "לא הוגדרו מקשי קיצור"
|
||||||
|
pt-BR = "Nenhum atalho configurado"
|
||||||
|
|
||||||
[gui.hotkeys.capture.header]
|
[gui.hotkeys.capture.header]
|
||||||
en = "Press a key combination (e.g. Ctrl+Alt+1)"
|
en = "Press a key combination (e.g. Ctrl+Alt+1)"
|
||||||
@@ -321,6 +351,7 @@ zh = "按下一个组合键 (例如 Ctrl+Alt+1)"
|
|||||||
ar = "اضغط على تركيبة مفاتيح (مثلاً Ctrl+Alt+1)"
|
ar = "اضغط على تركيبة مفاتيح (مثلاً Ctrl+Alt+1)"
|
||||||
kz = "Пернелер тіркесімін басыңыз (мысалы, Ctrl+Alt+1)"
|
kz = "Пернелер тіркесімін басыңыз (мысалы, Ctrl+Alt+1)"
|
||||||
he = "לחץ על צירוף מקשים (למשל Ctrl+Alt+1)"
|
he = "לחץ על צירוף מקשים (למשל Ctrl+Alt+1)"
|
||||||
|
pt-BR = "Pressione uma combinação de tecla (ex: Ctrl+Alt+1)"
|
||||||
|
|
||||||
[gui.hotkeys.capture.for]
|
[gui.hotkeys.capture.for]
|
||||||
en = "for"
|
en = "for"
|
||||||
@@ -331,9 +362,10 @@ zh = "用于"
|
|||||||
ar = "لـ"
|
ar = "لـ"
|
||||||
kz = "үшін"
|
kz = "үшін"
|
||||||
he = "עבור"
|
he = "עבור"
|
||||||
|
pt-BR = "para"
|
||||||
|
|
||||||
[gui.hotkeys.capture.cancel]
|
[gui.hotkeys.capture.cancel]
|
||||||
en = "Press Escape to canel"
|
en = "Press Escape to cancel"
|
||||||
ru = "Нажмите Escape для отмены"
|
ru = "Нажмите Escape для отмены"
|
||||||
es = "Presione Escape para cancelar"
|
es = "Presione Escape para cancelar"
|
||||||
fr = "Appuyez sur Échap pour annuler"
|
fr = "Appuyez sur Échap pour annuler"
|
||||||
@@ -341,3 +373,4 @@ zh = "按 Escape 取消"
|
|||||||
ar = "اضغط Esc للإلغاء"
|
ar = "اضغط Esc للإلغاء"
|
||||||
kz = "Болдырмау үшін Escape пернесін басыңыз"
|
kz = "Болдырмау үшін Escape пернесін басыңыз"
|
||||||
he = "לחץ על Escape לביטול"
|
he = "לחץ על Escape לביטול"
|
||||||
|
pt-BR = "Pressione Esc para cancelar"
|
||||||
|
|||||||
+256
-225
@@ -673,10 +673,11 @@ impl SoundpadGui {
|
|||||||
ScrollArea::vertical().id_salt(0).show(ui, |ui| {
|
ScrollArea::vertical().id_salt(0).show(ui, |ui| {
|
||||||
ui.set_min_width(area_size.x);
|
ui.set_min_width(area_size.x);
|
||||||
|
|
||||||
let mut dirs = self.app_state.dirs.clone();
|
let mut dirs = std::mem::take(&mut self.app_state.dirs);
|
||||||
|
let mut dir_to_open = None;
|
||||||
|
|
||||||
dnd(ui, "dnd_directories").show_vec(&mut dirs, |ui, item, handle, _state| {
|
dnd(ui, "dnd_directories").show_vec(&mut dirs, |ui, item, handle, _state| {
|
||||||
let path = item.clone();
|
let path = item;
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
handle.ui(ui, |ui| {
|
handle.ui(ui, |ui| {
|
||||||
ui.label(ICON_DRAG_INDICATOR.codepoint);
|
ui.label(ICON_DRAG_INDICATOR.codepoint);
|
||||||
@@ -688,7 +689,7 @@ impl SoundpadGui {
|
|||||||
|
|
||||||
let mut dir_button_text = RichText::new(name.clone());
|
let mut dir_button_text = RichText::new(name.clone());
|
||||||
if let Some(current_dir) = &self.app_state.current_dir
|
if let Some(current_dir) = &self.app_state.current_dir
|
||||||
&& current_dir.eq(&path)
|
&& current_dir.eq(&*path)
|
||||||
{
|
{
|
||||||
dir_button_text = dir_button_text.color(Color32::WHITE);
|
dir_button_text = dir_button_text.color(Color32::WHITE);
|
||||||
}
|
}
|
||||||
@@ -698,7 +699,7 @@ impl SoundpadGui {
|
|||||||
|
|
||||||
let dir_button_response = ui.add(dir_button);
|
let dir_button_response = ui.add(dir_button);
|
||||||
if dir_button_response.clicked() {
|
if dir_button_response.clicked() {
|
||||||
self.open_dir(&path);
|
dir_to_open = Some(path.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
let delete_dir_button = Button::new(ICON_DELETE).frame(false);
|
let delete_dir_button = Button::new(ICON_DELETE).frame(false);
|
||||||
@@ -718,7 +719,7 @@ impl SoundpadGui {
|
|||||||
))
|
))
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
self.open_dir(&path);
|
dir_to_open = Some(path.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
if ui
|
if ui
|
||||||
@@ -750,6 +751,10 @@ impl SoundpadGui {
|
|||||||
});
|
});
|
||||||
self.app_state.dirs = dirs;
|
self.app_state.dirs = dirs;
|
||||||
|
|
||||||
|
if let Some(path) = dir_to_open {
|
||||||
|
self.open_dir(&path);
|
||||||
|
}
|
||||||
|
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
let add_dirs_button = Button::new(ICON_ADD).frame(false);
|
let add_dirs_button = Button::new(ICON_ADD).frame(false);
|
||||||
let add_dirs_button_response = ui.add_sized([18.0, 18.0], add_dirs_button);
|
let add_dirs_button_response = ui.add_sized([18.0, 18.0], add_dirs_button);
|
||||||
@@ -769,56 +774,259 @@ impl SoundpadGui {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_files(&mut self, ui: &mut Ui, area_size: Vec2) {
|
fn draw_files_search_field(&mut self, ui: &mut Ui) {
|
||||||
ui.vertical(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.horizontal(|ui| {
|
let search_field_response = ui.add_sized(
|
||||||
let search_field_response = ui.add_sized(
|
[ui.available_width(), 22.0],
|
||||||
[ui.available_width(), 22.0],
|
TextEdit::singleline(&mut self.app_state.search_query)
|
||||||
TextEdit::singleline(&mut self.app_state.search_query)
|
.hint_text(t!("gui.search_placeholder")),
|
||||||
.hint_text(t!("gui.search_placeholder")),
|
);
|
||||||
);
|
|
||||||
|
|
||||||
if self.app_state.force_focus_search {
|
if self.app_state.force_focus_search {
|
||||||
search_field_response.request_focus();
|
search_field_response.request_focus();
|
||||||
self.app_state.force_focus_search = false;
|
self.app_state.force_focus_search = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.app_state.search_field_id = Some(search_field_response.id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_files_list(&mut self, ui: &mut Ui, area_size: Vec2) {
|
||||||
|
ScrollArea::vertical().id_salt(1).show(ui, |ui| {
|
||||||
|
ui.set_min_width(area_size.x);
|
||||||
|
ui.set_min_height(area_size.y);
|
||||||
|
|
||||||
|
ui.vertical(|ui| {
|
||||||
|
let mut actions = Vec::new();
|
||||||
|
let files = self.get_filtered_files();
|
||||||
|
for entry_path in files {
|
||||||
|
Self::draw_tree_node(
|
||||||
|
ui,
|
||||||
|
entry_path,
|
||||||
|
&mut self.app_state,
|
||||||
|
&self.audio_player_state,
|
||||||
|
&mut actions,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.app_state.search_field_id = Some(search_field_response.id);
|
for action in actions {
|
||||||
});
|
match action {
|
||||||
|
FileAction::Play(path, concurrent) => self.play_file(&path, concurrent),
|
||||||
ui.separator();
|
FileAction::StopAndPlay(id, path, concurrent) => {
|
||||||
|
self.stop(Some(id));
|
||||||
ScrollArea::vertical().id_salt(1).show(ui, |ui| {
|
self.play_file(&path, concurrent);
|
||||||
ui.set_min_width(area_size.x);
|
}
|
||||||
ui.set_min_height(area_size.y);
|
FileAction::AssignHotkey(path) => {
|
||||||
|
self.app_state.assigning_hotkey_for_file = Some(path);
|
||||||
ui.vertical(|ui| {
|
self.app_state.hotkey_capture_active = true;
|
||||||
let mut actions = Vec::new();
|
}
|
||||||
let files = self.get_filtered_files();
|
|
||||||
for entry_path in files {
|
|
||||||
Self::draw_tree_node(
|
|
||||||
ui,
|
|
||||||
entry_path,
|
|
||||||
&mut self.app_state,
|
|
||||||
&self.audio_player_state,
|
|
||||||
&mut actions,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
for action in actions {
|
fn draw_files(&mut self, ui: &mut Ui, area_size: Vec2) {
|
||||||
match action {
|
ui.vertical(|ui| {
|
||||||
FileAction::Play(path, concurrent) => self.play_file(&path, concurrent),
|
self.draw_files_search_field(ui);
|
||||||
FileAction::StopAndPlay(id, path, concurrent) => {
|
ui.separator();
|
||||||
self.stop(Some(id));
|
self.draw_files_list(ui, area_size);
|
||||||
self.play_file(&path, concurrent);
|
});
|
||||||
}
|
}
|
||||||
FileAction::AssignHotkey(path) => {
|
|
||||||
self.app_state.assigning_hotkey_for_file = Some(path);
|
fn draw_tree_node_dir(
|
||||||
self.app_state.hotkey_capture_active = true;
|
ui: &mut Ui,
|
||||||
|
path: std::path::PathBuf,
|
||||||
|
app_state: &mut AppState,
|
||||||
|
audio_player_state: &AudioPlayerState,
|
||||||
|
actions: &mut Vec<FileAction>,
|
||||||
|
) {
|
||||||
|
let dir_name = path
|
||||||
|
.file_name()
|
||||||
|
.unwrap_or_default()
|
||||||
|
.to_string_lossy()
|
||||||
|
.to_string();
|
||||||
|
CollapsingHeader::new(dir_name)
|
||||||
|
.id_salt(&path)
|
||||||
|
.show(ui, |ui| {
|
||||||
|
let children = if let Some(cached) = app_state.dir_cache.get(&path) {
|
||||||
|
cached.clone()
|
||||||
|
} else {
|
||||||
|
let mut read = Vec::new();
|
||||||
|
if let Ok(entries) = std::fs::read_dir(&path) {
|
||||||
|
for entry in entries.filter_map(|e| e.ok()) {
|
||||||
|
read.push(entry.path());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
read.sort_by(|a, b| {
|
||||||
|
let a_is_dir = a.is_dir();
|
||||||
|
let b_is_dir = b.is_dir();
|
||||||
|
if a_is_dir && !b_is_dir {
|
||||||
|
Ordering::Less
|
||||||
|
} else if !a_is_dir && b_is_dir {
|
||||||
|
Ordering::Greater
|
||||||
|
} else {
|
||||||
|
a.cmp(b)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
app_state.dir_cache.insert(path.clone(), read.clone());
|
||||||
|
read
|
||||||
|
};
|
||||||
|
|
||||||
|
let search_query = app_state.search_query.to_lowercase();
|
||||||
|
let search_query = search_query.trim();
|
||||||
|
|
||||||
|
for child in children {
|
||||||
|
if !child.is_dir() {
|
||||||
|
if !crate::gui::SUPPORTED_EXTENSIONS.contains(
|
||||||
|
&child
|
||||||
|
.extension()
|
||||||
|
.unwrap_or_default()
|
||||||
|
.to_str()
|
||||||
|
.unwrap_or_default(),
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if !search_query.is_empty() {
|
||||||
|
let file_name = child
|
||||||
|
.file_name()
|
||||||
|
.unwrap_or_default()
|
||||||
|
.to_string_lossy()
|
||||||
|
.to_string();
|
||||||
|
if !file_name.to_lowercase().contains(search_query) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Self::draw_tree_node(ui, child, app_state, audio_player_state, actions);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_tree_node_file(
|
||||||
|
ui: &mut Ui,
|
||||||
|
path: std::path::PathBuf,
|
||||||
|
app_state: &mut AppState,
|
||||||
|
audio_player_state: &AudioPlayerState,
|
||||||
|
actions: &mut Vec<FileAction>,
|
||||||
|
) {
|
||||||
|
let file_name = path
|
||||||
|
.file_name()
|
||||||
|
.unwrap_or_default()
|
||||||
|
.to_string_lossy()
|
||||||
|
.to_string();
|
||||||
|
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
// Hotkey badge
|
||||||
|
let mut hotkey_badge = None;
|
||||||
|
for slot in &app_state.hotkey_config.slots {
|
||||||
|
if slot.action.name == "play"
|
||||||
|
&& let Some(file_path_str) = slot.action.args.get("file_path")
|
||||||
|
&& Path::new(file_path_str) == path
|
||||||
|
{
|
||||||
|
if let Some(chord) = &slot.key_chord {
|
||||||
|
hotkey_badge = Some(format!("[{}]", chord));
|
||||||
|
} else {
|
||||||
|
hotkey_badge = Some(format!("[{}]", slot.slot));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(badge) = &hotkey_badge {
|
||||||
|
ui.label(
|
||||||
|
RichText::new(badge)
|
||||||
|
.small()
|
||||||
|
.monospace()
|
||||||
|
.color(Color32::from_rgb(100, 200, 100)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let file_button_text = RichText::new(&file_name);
|
||||||
|
|
||||||
|
let file_button = Button::new(file_button_text).frame(false).truncate();
|
||||||
|
let file_button_response = ui.add(file_button);
|
||||||
|
if file_button_response.clicked() {
|
||||||
|
ui.input(|i| {
|
||||||
|
if i.modifiers.ctrl {
|
||||||
|
actions.push(FileAction::Play(path.clone(), true));
|
||||||
|
} else if i.modifiers.shift
|
||||||
|
&& let Some(last_track) = audio_player_state.tracks.last()
|
||||||
|
{
|
||||||
|
actions.push(FileAction::StopAndPlay(
|
||||||
|
last_track.id,
|
||||||
|
path.clone(),
|
||||||
|
true,
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
actions.push(FileAction::Play(path.clone(), false));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Context menu
|
||||||
|
file_button_response.context_menu(|ui| {
|
||||||
|
if ui
|
||||||
|
.button(format!(
|
||||||
|
"{} {}",
|
||||||
|
ICON_BOLT.codepoint,
|
||||||
|
t!("gui.context.files.play_solo")
|
||||||
|
))
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
|
actions.push(FileAction::Play(path.clone(), false));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ui
|
||||||
|
.button(format!(
|
||||||
|
"{} {}",
|
||||||
|
ICON_ADD.codepoint,
|
||||||
|
t!("gui.context.files.add_new")
|
||||||
|
))
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
|
actions.push(FileAction::Play(path.clone(), true));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ui
|
||||||
|
.button(format!(
|
||||||
|
"{} {}",
|
||||||
|
ICON_SWAP_HORIZ.codepoint,
|
||||||
|
t!("gui.context.files.replace_last")
|
||||||
|
))
|
||||||
|
.clicked()
|
||||||
|
&& let Some(last_track) = audio_player_state.tracks.last()
|
||||||
|
{
|
||||||
|
actions.push(FileAction::StopAndPlay(last_track.id, path.clone(), true));
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.separator();
|
||||||
|
|
||||||
|
if ui
|
||||||
|
.button(format!(
|
||||||
|
"{} {}",
|
||||||
|
ICON_OPEN_IN_BROWSER.codepoint,
|
||||||
|
t!("gui.context.files.show_in_fm")
|
||||||
|
))
|
||||||
|
.clicked()
|
||||||
|
&& let Err(e) = opener::reveal(&path)
|
||||||
|
{
|
||||||
|
eprintln!("Failed to open file manager: {}", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.separator();
|
||||||
|
|
||||||
|
if ui
|
||||||
|
.button(format!(
|
||||||
|
"{} {}",
|
||||||
|
ICON_KEYBOARD.codepoint,
|
||||||
|
t!("gui.context.files.asign_hotkey")
|
||||||
|
))
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
|
actions.push(FileAction::AssignHotkey(path.clone()));
|
||||||
|
ui.close();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -831,186 +1039,9 @@ impl SoundpadGui {
|
|||||||
actions: &mut Vec<FileAction>,
|
actions: &mut Vec<FileAction>,
|
||||||
) {
|
) {
|
||||||
if path.is_dir() {
|
if path.is_dir() {
|
||||||
let dir_name = path
|
Self::draw_tree_node_dir(ui, path, app_state, audio_player_state, actions);
|
||||||
.file_name()
|
|
||||||
.unwrap_or_default()
|
|
||||||
.to_string_lossy()
|
|
||||||
.to_string();
|
|
||||||
CollapsingHeader::new(dir_name)
|
|
||||||
.id_salt(&path)
|
|
||||||
.show(ui, |ui| {
|
|
||||||
let children = if let Some(cached) = app_state.dir_cache.get(&path) {
|
|
||||||
cached.clone()
|
|
||||||
} else {
|
|
||||||
let mut read = Vec::new();
|
|
||||||
if let Ok(entries) = std::fs::read_dir(&path) {
|
|
||||||
for entry in entries.filter_map(|e| e.ok()) {
|
|
||||||
read.push(entry.path());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
read.sort_by(|a, b| {
|
|
||||||
let a_is_dir = a.is_dir();
|
|
||||||
let b_is_dir = b.is_dir();
|
|
||||||
if a_is_dir && !b_is_dir {
|
|
||||||
Ordering::Less
|
|
||||||
} else if !a_is_dir && b_is_dir {
|
|
||||||
Ordering::Greater
|
|
||||||
} else {
|
|
||||||
a.cmp(b)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
app_state.dir_cache.insert(path.clone(), read.clone());
|
|
||||||
read
|
|
||||||
};
|
|
||||||
|
|
||||||
let search_query = app_state.search_query.to_lowercase();
|
|
||||||
let search_query = search_query.trim();
|
|
||||||
|
|
||||||
for child in children {
|
|
||||||
if !child.is_dir() {
|
|
||||||
if !crate::gui::SUPPORTED_EXTENSIONS.contains(
|
|
||||||
&child
|
|
||||||
.extension()
|
|
||||||
.unwrap_or_default()
|
|
||||||
.to_str()
|
|
||||||
.unwrap_or_default(),
|
|
||||||
) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if !search_query.is_empty() {
|
|
||||||
let file_name = child
|
|
||||||
.file_name()
|
|
||||||
.unwrap_or_default()
|
|
||||||
.to_string_lossy()
|
|
||||||
.to_string();
|
|
||||||
if !file_name.to_lowercase().contains(search_query) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Self::draw_tree_node(ui, child, app_state, audio_player_state, actions);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
let file_name = path
|
Self::draw_tree_node_file(ui, path, app_state, audio_player_state, actions);
|
||||||
.file_name()
|
|
||||||
.unwrap_or_default()
|
|
||||||
.to_string_lossy()
|
|
||||||
.to_string();
|
|
||||||
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
// Hotkey badge
|
|
||||||
let mut hotkey_badge = None;
|
|
||||||
for slot in &app_state.hotkey_config.slots {
|
|
||||||
if slot.action.name == "play"
|
|
||||||
&& let Some(file_path_str) = slot.action.args.get("file_path")
|
|
||||||
&& Path::new(file_path_str) == path
|
|
||||||
{
|
|
||||||
if let Some(chord) = &slot.key_chord {
|
|
||||||
hotkey_badge = Some(format!("[{}]", chord));
|
|
||||||
} else {
|
|
||||||
hotkey_badge = Some(format!("[{}]", slot.slot));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(badge) = &hotkey_badge {
|
|
||||||
ui.label(
|
|
||||||
RichText::new(badge)
|
|
||||||
.small()
|
|
||||||
.monospace()
|
|
||||||
.color(Color32::from_rgb(100, 200, 100)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let file_button_text = RichText::new(&file_name);
|
|
||||||
|
|
||||||
let file_button = Button::new(file_button_text).frame(false).truncate();
|
|
||||||
let file_button_response = ui.add(file_button);
|
|
||||||
if file_button_response.clicked() {
|
|
||||||
ui.input(|i| {
|
|
||||||
if i.modifiers.ctrl {
|
|
||||||
actions.push(FileAction::Play(path.clone(), true));
|
|
||||||
} else if i.modifiers.shift
|
|
||||||
&& let Some(last_track) = audio_player_state.tracks.last()
|
|
||||||
{
|
|
||||||
actions.push(FileAction::StopAndPlay(
|
|
||||||
last_track.id,
|
|
||||||
path.clone(),
|
|
||||||
true,
|
|
||||||
));
|
|
||||||
} else {
|
|
||||||
actions.push(FileAction::Play(path.clone(), false));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Context menu
|
|
||||||
file_button_response.context_menu(|ui| {
|
|
||||||
if ui
|
|
||||||
.button(format!(
|
|
||||||
"{} {}",
|
|
||||||
ICON_BOLT.codepoint,
|
|
||||||
t!("gui.context.files.play_solo")
|
|
||||||
))
|
|
||||||
.clicked()
|
|
||||||
{
|
|
||||||
actions.push(FileAction::Play(path.clone(), false));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ui
|
|
||||||
.button(format!(
|
|
||||||
"{} {}",
|
|
||||||
ICON_ADD.codepoint,
|
|
||||||
t!("gui.context.files.add_new")
|
|
||||||
))
|
|
||||||
.clicked()
|
|
||||||
{
|
|
||||||
actions.push(FileAction::Play(path.clone(), true));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ui
|
|
||||||
.button(format!(
|
|
||||||
"{} {}",
|
|
||||||
ICON_SWAP_HORIZ.codepoint,
|
|
||||||
t!("gui.context.files.replace_last")
|
|
||||||
))
|
|
||||||
.clicked()
|
|
||||||
&& let Some(last_track) = audio_player_state.tracks.last()
|
|
||||||
{
|
|
||||||
actions.push(FileAction::StopAndPlay(last_track.id, path.clone(), true));
|
|
||||||
}
|
|
||||||
|
|
||||||
ui.separator();
|
|
||||||
|
|
||||||
if ui
|
|
||||||
.button(format!(
|
|
||||||
"{} {}",
|
|
||||||
ICON_OPEN_IN_BROWSER.codepoint,
|
|
||||||
t!("gui.context.files.show_in_fm")
|
|
||||||
))
|
|
||||||
.clicked()
|
|
||||||
&& let Err(e) = opener::reveal(&path)
|
|
||||||
{
|
|
||||||
eprintln!("Failed to open file manager: {}", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
ui.separator();
|
|
||||||
|
|
||||||
if ui
|
|
||||||
.button(format!(
|
|
||||||
"{} {}",
|
|
||||||
ICON_KEYBOARD.codepoint,
|
|
||||||
t!("gui.context.files.asign_hotkey")
|
|
||||||
))
|
|
||||||
.clicked()
|
|
||||||
{
|
|
||||||
actions.push(FileAction::AssignHotkey(path.clone()));
|
|
||||||
ui.close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -95,7 +95,9 @@ impl AudioPlayer {
|
|||||||
sink.log_on_drop(false);
|
sink.log_on_drop(false);
|
||||||
self.stream_handle = Some(sink);
|
self.stream_handle = Some(sink);
|
||||||
}
|
}
|
||||||
Ok(self.stream_handle.as_ref().unwrap())
|
self.stream_handle
|
||||||
|
.as_ref()
|
||||||
|
.ok_or_else(|| anyhow!("Failed to initialize stream_handle"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn drop_stream(&mut self) {
|
fn drop_stream(&mut self) {
|
||||||
|
|||||||
Reference in New Issue
Block a user