something-x-dev 1.9.0.dev29__py3-none-any.whl → 1.9.0.dev30__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
nothing_app/_version.py CHANGED
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '1.9.0.dev29'
22
- __version_tuple__ = version_tuple = (1, 9, 0, 'dev29')
21
+ __version__ = version = '1.9.0.dev30'
22
+ __version_tuple__ = version_tuple = (1, 9, 0, 'dev30')
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -9,7 +9,7 @@ import gi
9
9
  gi.require_version("Gtk", "4.0")
10
10
  gi.require_version("Pango", "1.0")
11
11
  gi.require_version("PangoCairo", "1.0")
12
- from gi.repository import Gtk, GLib, PangoCairo, Gio
12
+ from gi.repository import Gtk, GLib, PangoCairo
13
13
 
14
14
  from ..bluetooth import BluetoothDevice, BluetoothManager
15
15
  from ..protocol import NothingDevice, ANCMode, EQ_PRESETS
@@ -477,12 +477,15 @@ class DevicePage(Gtk.Box):
477
477
  )
478
478
 
479
479
  self._auto_pause_switch = Gtk.Switch()
480
- self._auto_pause_switch.set_active(True)
480
+ self._auto_pause_switch.set_active(
481
+ profiles.get_notify_prefs(self._bt_device.address).get("wear_mpris", False)
482
+ )
481
483
  self._auto_pause_switch.set_valign(Gtk.Align.CENTER)
484
+ self._auto_pause_switch.connect("state-set", self._on_auto_pause_toggled)
482
485
  settings_group.append(
483
486
  _settings_row(
484
487
  "Auto-Pause",
485
- "Pause media on removal",
488
+ "Pause/resume media with wear detection",
486
489
  self._auto_pause_switch,
487
490
  )
488
491
  )
@@ -712,6 +715,10 @@ class DevicePage(Gtk.Box):
712
715
  if not entry.has_focus():
713
716
  self._save_nickname()
714
717
 
718
+ def _on_auto_pause_toggled(self, _switch, state: bool):
719
+ profiles.set_notify_prefs(self._bt_device.address, {"wear_mpris": state})
720
+ return False
721
+
715
722
  def _on_notif_battery_toggled(self, _switch, state: bool):
716
723
  profiles.set_notify_prefs(self._bt_device.address, {"battery_low": state})
717
724
  return False
@@ -1,10 +1,10 @@
1
1
  import math
2
- from typing import Callable
2
+ from collections.abc import Callable
3
3
 
4
4
  import gi
5
5
 
6
6
  gi.require_version("Gtk", "4.0")
7
- from gi.repository import Gdk, GLib, Gtk
7
+ from gi.repository import Gdk, Gtk
8
8
 
9
9
  from ..theme import ACCENT_PRESETS, BG_PRESETS, FONT_PRESETS, TEXTURES, Theme, hex_to_rgb
10
10
 
@@ -345,11 +345,8 @@ class ThemePage(Gtk.Box):
345
345
 
346
346
  def _on_accent_color_set(self, btn: Gtk.ColorButton):
347
347
  rgba = btn.get_rgba()
348
- self._theme.accent = "#{:02x}{:02x}{:02x}".format(
349
- int(rgba.red * 255),
350
- int(rgba.green * 255),
351
- int(rgba.blue * 255),
352
- )
348
+ r, g, b = int(rgba.red * 255), int(rgba.green * 255), int(rgba.blue * 255)
349
+ self._theme.accent = f"#{r:02x}{g:02x}{b:02x}"
353
350
  self._update_accent_swatches()
354
351
  self._emit()
355
352
 
@@ -368,11 +365,8 @@ class ThemePage(Gtk.Box):
368
365
 
369
366
  def _on_bg_color_set(self, btn: Gtk.ColorButton):
370
367
  rgba = btn.get_rgba()
371
- self._theme.bg_color = "#{:02x}{:02x}{:02x}".format(
372
- int(rgba.red * 255),
373
- int(rgba.green * 255),
374
- int(rgba.blue * 255),
375
- )
368
+ r, g, b = int(rgba.red * 255), int(rgba.green * 255), int(rgba.blue * 255)
369
+ self._theme.bg_color = f"#{r:02x}{g:02x}{b:02x}"
376
370
  self._update_bg_swatches()
377
371
  self._emit()
378
372
 
@@ -419,8 +413,6 @@ class ThemePage(Gtk.Box):
419
413
  self._emit()
420
414
 
421
415
  def _on_reset(self, _btn):
422
- import dataclasses
423
-
424
416
  self._theme = Theme()
425
417
  self._reload_controls()
426
418
  self._emit()
@@ -428,11 +420,11 @@ class ThemePage(Gtk.Box):
428
420
  # ── Internal helpers ──────────────────────────────────────────────────────
429
421
 
430
422
  def _update_accent_swatches(self):
431
- for sw, (color, _) in zip(self._accent_swatches, ACCENT_PRESETS):
423
+ for sw, (color, _) in zip(self._accent_swatches, ACCENT_PRESETS, strict=False):
432
424
  sw.set_active(color.lower() == self._theme.accent.lower())
433
425
 
434
426
  def _update_bg_swatches(self):
435
- for sw, (color, _) in zip(self._bg_swatches, BG_PRESETS):
427
+ for sw, (color, _) in zip(self._bg_swatches, BG_PRESETS, strict=False):
436
428
  sw.set_active(color.lower() == self._theme.bg_color.lower())
437
429
 
438
430
  def _reload_controls(self):
nothing_app/profiles.py CHANGED
@@ -5,7 +5,7 @@ _DIR = os.path.expanduser("~/.config/something-x")
5
5
  _PROFILES_FILE = os.path.join(_DIR, "profiles.json")
6
6
  _LAST_DEV_FILE = os.path.join(_DIR, "last_device")
7
7
 
8
- _NOTIFY_DEFAULTS: dict = {"battery_low": True, "connect": True, "disconnect": True}
8
+ _NOTIFY_DEFAULTS: dict = {"battery_low": True, "connect": True, "disconnect": True, "wear_mpris": False}
9
9
  _ALLOWED_IMPORT_KEYS = frozenset({"anc", "eq", "nickname", "notify"})
10
10
 
11
11
 
nothing_app/protocol.py CHANGED
@@ -152,6 +152,8 @@ class NothingDevice(GObject.Object):
152
152
  self._thread: threading.Thread | None = None
153
153
  self._low_bat_notified: dict[str, set[int]] = {}
154
154
  self._low_bat_seen: set[str] = set()
155
+ self._wear_both_removed: bool = False
156
+ self._wear_paused: bool = False
155
157
 
156
158
  # ── Public API ────────────────────────────────────────────────────────────
157
159
 
@@ -545,9 +547,8 @@ class NothingDevice(GObject.Object):
545
547
  else:
546
548
  modes = frozenset([ANCMode.OFF, ANCMode.TRANSPARENCY])
547
549
  self.state.supported_anc_modes = modes
548
- _log(
549
- f"[protocol] supported ANC modes detected: {[ANCMode.LABELS.get(m, m) for m in sorted(modes)]}"
550
- )
550
+ labels = [ANCMode.LABELS.get(m, m) for m in sorted(modes)]
551
+ _log(f"[protocol] supported ANC modes detected: {labels}")
551
552
  changed = True
552
553
 
553
554
  return changed
@@ -579,6 +580,7 @@ class NothingDevice(GObject.Object):
579
580
  changed = True
580
581
  if changed:
581
582
  _log(f"[protocol] wearing L={self.state.left_wearing} R={self.state.right_wearing}")
583
+ self._check_wear_mpris()
582
584
  return changed
583
585
 
584
586
  # ── Legacy 0x03 frame handling (status-only fallback) ────────────────────
@@ -681,6 +683,36 @@ class NothingDevice(GObject.Object):
681
683
  ).start()
682
684
  break
683
685
 
686
+ def _check_wear_mpris(self):
687
+ from . import profiles
688
+
689
+ if not profiles.get_notify_prefs(self.address).get("wear_mpris", False):
690
+ self._wear_both_removed = False
691
+ self._wear_paused = False
692
+ return
693
+
694
+ both_removed = not self.state.left_wearing and not self.state.right_wearing
695
+
696
+ if both_removed and not self._wear_both_removed:
697
+ self._wear_both_removed = True
698
+ self._wear_paused = True
699
+ threading.Thread(
700
+ target=subprocess.run,
701
+ args=(["playerctl", "pause"],),
702
+ kwargs={"capture_output": True},
703
+ daemon=True,
704
+ ).start()
705
+ elif not both_removed and self._wear_both_removed:
706
+ self._wear_both_removed = False
707
+ if self._wear_paused:
708
+ self._wear_paused = False
709
+ threading.Thread(
710
+ target=subprocess.run,
711
+ args=(["playerctl", "play"],),
712
+ kwargs={"capture_output": True},
713
+ daemon=True,
714
+ ).start()
715
+
684
716
  def _poll_earphone_status(self):
685
717
  # The firmware only computes a fresh per-bud snapshot when asked; the
686
718
  # pushed EVT frames carry stale placeholder entries for the bud that
nothing_app/tray.py CHANGED
@@ -4,7 +4,7 @@ import dbus.service
4
4
  import dbus.mainloop.glib
5
5
  from gi.repository import GLib, GObject
6
6
 
7
- from .bluetooth import BluetoothManager, BluetoothDevice, device_icon_name
7
+ from .bluetooth import BluetoothManager, device_icon_name
8
8
 
9
9
  _ITEM_IFACE = "org.kde.StatusNotifierItem"
10
10
  _WATCHER_IFACE = "org.kde.StatusNotifierWatcher"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: something-x-dev
3
- Version: 1.9.0.dev29
3
+ Version: 1.9.0.dev30
4
4
  Summary: Something X device manager for Omarchy / Linux
5
5
  Author: Raphael
6
6
  License: MIT
@@ -1,23 +1,23 @@
1
1
  nothing_app/__init__.py,sha256=zN7vSxhfKFzKNDhoeRzP638S46sET39MWhlljtk0vP0,540
2
- nothing_app/_version.py,sha256=uJvqayn-mkMQQtgKyUMpSzxwrA8eQpoL1SeOgUbArn4,535
2
+ nothing_app/_version.py,sha256=PPLVrnyxRQnpFwUz0909dcjj-Haq3TqcfQACTaT8k20,535
3
3
  nothing_app/application.py,sha256=c6B0raU5gBPu5la1v01w6oH7c6lmYpCwTY57ISZOY3Y,9599
4
4
  nothing_app/bluetooth.py,sha256=MQeF0u_13SZ1GAY2UeadW4bMvGpu5UbgIR912M81dBs,12824
5
- nothing_app/profiles.py,sha256=vqx0Cm3xXhXyUjtNu0F20xySQ7yPGu1v2urMtX_JJw8,4364
6
- nothing_app/protocol.py,sha256=lh2N7Lfi63qU1g-IMbfZRniaLhNrzoSA4AJzP4n3Uyc,29159
5
+ nothing_app/profiles.py,sha256=LrTgYdDICLA0dlmyftD3hNVmiruDrGz5DDumPk5M5NQ,4385
6
+ nothing_app/protocol.py,sha256=IgkRAArMlAiw2EXFFb1IyAySaRBwYmNBQOnn95AWRNg,30387
7
7
  nothing_app/splash.py,sha256=8GhwQ4F2B9tsxu23VpragjLgxdMKVsg3ZQIlzRC2dY8,6811
8
8
  nothing_app/theme.py,sha256=UwGO2LYuBdA9_3o3EwhI7D90wIUEpGw6RQ-4RKQO2QM,9727
9
- nothing_app/tray.py,sha256=GCM77zm8Y-OzodvriwWhTaxvE-KfUTNjVRQNzZ3f_ic,5918
9
+ nothing_app/tray.py,sha256=VqerKxC9SqvbzRdqAIRJo-rJT_h-2_ASxoDdSHNyhlI,5901
10
10
  nothing_app/window.py,sha256=VijJo-wcLVNkeiWQZaofQ51qX3C2Z5IkxTACc1OPB5s,6911
11
11
  nothing_app/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
12
  nothing_app/data/com.something.x.omarchy.desktop,sha256=Uet1FGwgMDvHlejxNuhR8cTWNrYEqnJlTvipl2ztFp8,362
13
13
  nothing_app/data/style.css,sha256=OPbBi_kkCSZhCr0pMcRzdbMzVV46jOJtCuEz0wLHkNI,21535
14
14
  nothing_app/pages/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
- nothing_app/pages/device.py,sha256=Knt-9pUMXcVFXubNz3YeMEX0mku1NtrbgJ2BjqtrqVE,30837
15
+ nothing_app/pages/device.py,sha256=wlUDfo3In2wS2jtL-yTAtrQd-2NnCRtl_yoaFjY0UNA,31187
16
16
  nothing_app/pages/home.py,sha256=LvARz9Gcwcn_jEV75NwYnhL9EoKYs_bKghjdtLmP21I,8600
17
- nothing_app/pages/theme.py,sha256=4orknXNcCNmR5T9drqH4zJ07dqZDU89px3Gk01X2vqw,18900
18
- something_x_dev-1.9.0.dev29.dist-info/licenses/LICENSE,sha256=f82aGY-Qd4Huw5T9EsynF6CJhVPdcnsTSuuaskxc1ak,1064
19
- something_x_dev-1.9.0.dev29.dist-info/METADATA,sha256=y2AIcmzSpeW_Qr2z8m0CSzaRB_k_ovq3ErFqCFRuGlA,7576
20
- something_x_dev-1.9.0.dev29.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
21
- something_x_dev-1.9.0.dev29.dist-info/entry_points.txt,sha256=HpMQVOiNSmzNKoa2Fb65XtbK7NWTfxMDBrBNlk9WHi8,65
22
- something_x_dev-1.9.0.dev29.dist-info/top_level.txt,sha256=yERYCJXvIBXR40iWxixVVZI3z-B4gNYXEdXFiiWa7KI,12
23
- something_x_dev-1.9.0.dev29.dist-info/RECORD,,
17
+ nothing_app/pages/theme.py,sha256=2mDj80unCvNxpJpRy3xl8hc1JjCSovZHSlTwKSI_ACM,18837
18
+ something_x_dev-1.9.0.dev30.dist-info/licenses/LICENSE,sha256=f82aGY-Qd4Huw5T9EsynF6CJhVPdcnsTSuuaskxc1ak,1064
19
+ something_x_dev-1.9.0.dev30.dist-info/METADATA,sha256=Q8VRauVr1adb1enM8QsL_jicd4LnnOisIe3VCwa3IZ0,7576
20
+ something_x_dev-1.9.0.dev30.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
21
+ something_x_dev-1.9.0.dev30.dist-info/entry_points.txt,sha256=HpMQVOiNSmzNKoa2Fb65XtbK7NWTfxMDBrBNlk9WHi8,65
22
+ something_x_dev-1.9.0.dev30.dist-info/top_level.txt,sha256=yERYCJXvIBXR40iWxixVVZI3z-B4gNYXEdXFiiWa7KI,12
23
+ something_x_dev-1.9.0.dev30.dist-info/RECORD,,