Source code for sublime_music.ui.state

from dataclasses import dataclass, field
from datetime import timedelta
from enum import Enum
from typing import Any, Callable, Dict, Optional, Set, Tuple, Type

from ..adapters import AlbumSearchQuery
from ..adapters.api_objects import Genre, Song
from ..util import this_decade


[docs]class RepeatType(Enum): NO_REPEAT = 0 REPEAT_QUEUE = 1 REPEAT_SONG = 2 @property def icon(self) -> str: """ Get the icon for the repeat type. >>> RepeatType.NO_REPEAT.icon, RepeatType.REPEAT_QUEUE.icon ('media-playlist-repeat-symbolic', 'media-playlist-repeat-symbolic') >>> RepeatType.REPEAT_SONG.icon 'media-playlist-repeat-song-symbolic' """ song_str = "-song" if self == RepeatType.REPEAT_SONG else "" return f"media-playlist-repeat{song_str}-symbolic"
[docs] def as_mpris_loop_status(self) -> str: return ["None", "Playlist", "Track"][self.value]
[docs] @staticmethod def from_mpris_loop_status(loop_status: str) -> "RepeatType": return { "None": RepeatType.NO_REPEAT, "Track": RepeatType.REPEAT_SONG, "Playlist": RepeatType.REPEAT_QUEUE, }[loop_status]
[docs]@dataclass class UIState: """Represents the UI state of the application."""
[docs] @dataclass(unsafe_hash=True) class UINotification: markup: str actions: Tuple[Tuple[str, Callable[[], None]], ...] = field(default_factory=tuple) icon: Optional[str] = None
version: int = 1 # Play state playing: bool = False current_song_index: int = -1 play_queue: Tuple[str, ...] = field(default_factory=tuple) old_play_queue: Tuple[str, ...] = field(default_factory=tuple) _volume: Dict[str, float] = field(default_factory=lambda: {"this device": 100.0}) is_muted: bool = False repeat_type: RepeatType = RepeatType.NO_REPEAT shuffle_on: bool = False song_progress: timedelta = timedelta() song_stream_cache_progress: Optional[timedelta] = timedelta() current_device: str = "this device" connecting_to_device: bool = False connected_device_name: Optional[str] = None available_players: Dict[Type, Set[Tuple[str, str]]] = field(default_factory=dict) # UI state current_tab: str = "albums" selected_album_id: Optional[str] = None selected_artist_id: Optional[str] = None selected_browse_element_id: Optional[str] = None selected_playlist_id: Optional[str] = None album_sort_direction: str = "ascending" album_page_size: int = 30 album_page: int = 0 current_notification: Optional[UINotification] = None playlist_details_expanded: bool = True artist_details_expanded: bool = True loading_play_queue: bool = False # State for Album sort. class _DefaultGenre(Genre): def __init__(self): self.name = "Rock" current_album_search_query: AlbumSearchQuery = field( default_factory=lambda: AlbumSearchQuery( AlbumSearchQuery.Type.RANDOM, genre=UIState._DefaultGenre(), year_range=this_decade(), ) ) active_playlist_id: Optional[str] = None def __getstate__(self): state = self.__dict__.copy() del state["song_stream_cache_progress"] del state["current_notification"] del state["playing"] del state["available_players"] return state def __setstate__(self, state: Dict[str, Any]): self.__dict__.update(state) self.song_stream_cache_progress = None self.current_notification = None self.playing = False def __init_available_players__(self): from sublime_music.players import PlayerManager self.available_players = {pt: set() for pt in PlayerManager.available_player_types}
[docs] def migrate(self): pass
_current_song: Optional[Song] = None @property def current_song(self) -> Optional[Song]: if not self.play_queue or self.current_song_index < 0: return None from sublime_music.adapters import AdapterManager current_song_id = self.play_queue[self.current_song_index] if not self._current_song or self._current_song.id != current_song_id: self._current_song = AdapterManager.get_song_details(current_song_id).result() return self._current_song @property def next_song_index(self) -> Optional[int]: # If nothing is playing there is no next song if self.current_song_index < 0: return None if self.repeat_type == RepeatType.REPEAT_SONG: return self.current_song_index # If we are at the end of the play queue if self.current_song_index == len(self.play_queue) - 1: # If we are repeating the queue, jump back to the beginning if self.repeat_type == RepeatType.REPEAT_QUEUE: return 0 # Otherwise, there isn't a next song return None # In all other cases, it's the song after the current one return self.current_song_index + 1 @property def volume(self) -> float: return self._volume.get(self.current_device, 100.0) @volume.setter def volume(self, value: float): self._volume[self.current_device] = value