Skip to content

Commit

Permalink
feat: custom sound renaming
Browse files Browse the repository at this point in the history
Adds feature requested in rafaelmardojai#337.
  • Loading branch information
BlurOne-GIT committed Jan 28, 2025
1 parent d95a837 commit 838e2a9
Show file tree
Hide file tree
Showing 11 changed files with 220 additions and 31 deletions.
27 changes: 23 additions & 4 deletions blanket/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from blanket.settings import Settings
from blanket.widgets import PresetDialog
from blanket.window import BlanketWindow
from blanket.widgets.sound_rename_dialog import SoundRenameDialog


class Application(Adw.Application):
Expand Down Expand Up @@ -130,11 +131,16 @@ def setup_actions(self):
action.connect('activate', self.on_open)
self.add_action(action)

# Add sound file
action = Gio.SimpleAction.new('remove-sound', GLib.VariantType('s'))
# Remove sound file
action = Gio.SimpleAction.new('remove-sound', GLib.VariantType('u'))
action.connect('activate', self.on_remove_sound)
self.add_action(action)

# Rename sound file
action = Gio.SimpleAction.new('rename-sound', GLib.VariantType('u'))
action.connect('activate', self.on_rename_sound)
self.add_action(action)

# Setup accelerator
self.set_accels_for_action('app.quit', ['<Ctl>q'])
self.set_accels_for_action('app.preferences', ['<Ctl>comma'])
Expand Down Expand Up @@ -207,13 +213,26 @@ def on_add_preset(self, _action, _param):
dialog = PresetDialog()
dialog.present(self.window)

def on_remove_sound(self, _action, name: GLib.Variant):
sound, index = MainPlayer.get().get_by_name(name.get_string())
def on_remove_sound(self, _action, index_variant: GLib.Variant):
index = index_variant.get_uint32()
sound = MainPlayer.get().get_by_index(index)

if sound and index:
sound.remove() # type: ignore
MainPlayer.get().remove(index)

def on_rename_sound(self, _action, index_variant: GLib.Variant):
# Open edit dialog
app = Gio.Application.get_default()
if app:
window = app.get_active_window() # type: ignore
if window:
index = index_variant.get_uint32()
sound = MainPlayer.get().get_by_index(index)
if sound and index:
dialog = SoundRenameDialog(sound, index)
dialog.present(window)

def on_background(self, action, value):
action.set_state(value)
Settings.get().background = value
Expand Down
6 changes: 6 additions & 0 deletions blanket/main_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,9 @@ def get_by_name(self, name: str) -> tuple[GObject.Object, int] | tuple[None, Non
return (sound, position)

return (None, None)

def get_index(self, name: str) -> int | None:
return self.get_by_name(name)[1]

def get_by_index(self, index: int) -> GObject.Object:
return self._sounds[index]
14 changes: 14 additions & 0 deletions blanket/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,20 @@ def remove_custom_audio(self, name: str):
del self.volume[name]
"""

def rename_custom_audio(self, old_name: str, new_name: str):
if old_name not in self.custom_audios:
return

if new_name in self.custom_audios:
# TODO: Do something if True
return

saved_audios = self.custom_audios
uri = saved_audios[old_name]
del saved_audios[old_name]
saved_audios[new_name] = uri
self.custom_audios = saved_audios

""" Presets """

@property
Expand Down
21 changes: 14 additions & 7 deletions blanket/widgets/sound_context_menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,34 @@
from gi.repository import Gio, GObject, GLib, Gtk

from blanket.define import RES_PATH

from blanket.sound import Sound
from blanket.main_player import MainPlayer

@Gtk.Template(resource_path=f'{RES_PATH}/sound-context-menu.ui')
class SoundContextMenu(Gtk.PopoverMenu):
__gtype_name__ = 'SoundContextMenu'

volume: Gtk.Scale = Gtk.Template.Child() # type: ignore

def __init__(self, sound):
def __init__(self, sound: Sound):
super().__init__()

self.sound = sound
self.sound: Sound = sound

if self.sound.custom:
index = MainPlayer.get().get_index(sound.name)
# Set remove menu item
custom_section = Gio.Menu()
remove_item = Gio.MenuItem.new(_('Remove'), None)
remove_item.set_action_and_target_value(
'app.remove-sound', GLib.Variant.new_string(self.sound.name)
self.rename_item = Gio.MenuItem.new(_('Rename'), None)
self.rename_item.set_action_and_target_value(
'app.rename-sound', GLib.Variant.new_uint32(index)
)
custom_section.append_item(self.rename_item)
self.remove_item = Gio.MenuItem.new(_('Remove'), None)
self.remove_item.set_action_and_target_value(
'app.remove-sound', GLib.Variant.new_uint32(index)
)
custom_section.insert_item(-1, remove_item)
custom_section.append_item(self.remove_item)

self.props.menu_model.append_section(None, custom_section) # type: ignore

Expand Down
20 changes: 11 additions & 9 deletions blanket/widgets/sound_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,17 @@ def _on_secondary_click(self, _ctrl, _n, x: int, y: int):
self._context_popover(x, y)

def _context_popover(self, x: int, y: int):
if self.sound is not None:
if self._menu is None:
self._menu = SoundContextMenu(self.sound)
if self.sound is None:
return

rec = Gdk.Rectangle()
rec.x = x
rec.y = y
if self._menu is None:
self._menu = SoundContextMenu(self.sound)

self._menu.set_parent(self)
self._menu.set_pointing_to(rec)
rec = Gdk.Rectangle()
rec.x = x
rec.y = y

self._menu.popup()
self._menu.set_parent(self)
self._menu.set_pointing_to(rec)

self._menu.popup()
75 changes: 75 additions & 0 deletions blanket/widgets/sound_rename_dialog.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Copyright 2025 Rafael Mardojai CM
# SPDX-License-Identifier: GPL-3.0-or-later

from gettext import gettext as _
from gi.repository import Gio, Gtk, Adw

from blanket.define import RES_PATH
from blanket.sound import Sound
from blanket.settings import Settings

@Gtk.Template(resource_path=f'{RES_PATH}/sound-rename-dialog.ui')
class SoundRenameDialog(Adw.Dialog):
__gtype_name__ = 'SoundRenameDialog'

headerbar: Adw.HeaderBar = Gtk.Template.Child() # type: ignore
title_widget: Adw.WindowTitle = Gtk.Template.Child() # type: ignore
accept_btn: Gtk.Button = Gtk.Template.Child() # type: ignore
name_entry: Adw.EntryRow = Gtk.Template.Child() # type: ignore

def __init__(self, sound: Sound, index: int, **kwargs):
super().__init__()

self.sound = sound
self.index = index
app = Gio.Application.get_default()
self.window = app.get_active_window() # type: ignore

self.set_title(_('Rename Sound'))
self.title_widget.set_subtitle(self.sound.name)
self.name_entry.set_text(self.sound.name)
# Wire buttons
self.accept_btn.connect('clicked', self._on_rename_sound)

@Gtk.Template.Callback()
def _on_cancel_clicked(self, _button):
self.close()

@Gtk.Template.Callback()
def _on_entry_changed(self, _entry):
name = self.__get_name()

if self.sound is not None and self.sound.name == name:
self.accept_btn.set_sensitive(False)
return

if name:
self.accept_btn.set_sensitive(True)
else:
self.accept_btn.set_sensitive(False)

def _on_rename_sound(self, _button):
new_name = self.__get_name()

if new_name == self.sound.name:
self.close()
return

if not new_name or new_name in Settings.get().custom_audios:
self.__invalid_name()
return

Settings.get().rename_custom_audio(self.sound.name, new_name)
self.sound.name = new_name
self.sound.title = new_name

self.close()

def __get_name(self):
name = self.name_entry.get_text()
name = name.strip() # Strip name

return name

def __invalid_name(self):
pass
1 change: 1 addition & 0 deletions data/resources/blanket.gresource.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<file>volume-row.ui</file>
<file>sound-item.ui</file>
<file>sound-context-menu.ui</file>
<file>sound-rename-dialog.ui</file>

<!-- CSS -->
<file>style.css</file>
Expand Down
1 change: 1 addition & 0 deletions data/resources/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ blueprints = custom_target('blueprints',
'sound-item.blp',
'volume-row.blp',
'window.blp',
'sound-rename-dialog.blp',
),
output: '.',
command: [blueprint, 'batch-compile', '@OUTPUT@', '@CURRENT_SOURCE_DIR@', '@INPUT@'],
Expand Down
48 changes: 48 additions & 0 deletions data/resources/sound-rename-dialog.blp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using Gtk 4.0;
using Adw 1;

template $SoundRenameDialog : Adw.Dialog {
width-request: 360;
height-request: 148;
focus-widget: name_entry;

Adw.ToolbarView {

[top]
Adw.HeaderBar headerbar {
show-end-title-buttons: false;
show-start-title-buttons: false;

title-widget: Adw.WindowTitle title_widget {
title: bind template.title;
};

Button {
label: _("Cancel");

clicked => $_on_cancel_clicked();
}

[end]
Button accept_btn {
sensitive: false;
label: _("Save");

styles [
"suggested-action"
]
}
}

Adw.PreferencesPage {
Adw.PreferencesGroup {
Adw.EntryRow name_entry {
title: _("Sound Name");
selectable: false;

changed => $_on_entry_changed();
}
}
}
}
}
2 changes: 2 additions & 0 deletions po/POTFILES
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ data/resources/preset-dialog.blp
data/resources/preset-row.blp
data/resources/shortcuts.blp
data/resources/sound-context-menu.blp
data/resources/sound-rename-dialog.blp
data/resources/sound-item.blp
data/resources/volume-row.blp
data/resources/window.blp
Expand All @@ -27,5 +28,6 @@ blanket/widgets/preset_chooser.py
blanket/widgets/preset_dialog.py
blanket/widgets/preset_row.py
blanket/widgets/sound_context_menu.py
blanket/widgets/sound_rename_dialog.py
blanket/widgets/sound_item.py
blanket/widgets/volume_row.py
Loading

0 comments on commit 838e2a9

Please sign in to comment.