and3rson/clay

View on GitHub
clay/pages/settings.py

Summary

Maintainability
A
0 mins
Test Coverage
"""
Components for "Settings" page.
"""
import urwid

from clay.pages.page import AbstractPage
from clay.settings import settings
from clay.player import player
from clay.hotkeys import hotkey_manager


class Slider(urwid.Widget):
    """
    Represents a (TODO: vertical) slider for equalizer band modification.
    TODO: Save equalizer settings in config file.
    """
    _sizing = frozenset([urwid.FLOW])

    CHARS = [
        u'\u2584',
        u'\u25A0',
        u'\u2580',
    ]
    ZERO_CHAR = u'\u2500'

    def selectable(self):
        return True

    def __init__(self, index, freq):
        self.index = index
        if int(freq) == freq:
            freq = int(freq)
        self.freq = freq
        if freq >= 1000:
            self.freq_str = str(freq // 1000) + '\nKHz'
        else:
            self.freq_str = str(freq) + '\nHz'
        self.value = 0
        self.slider_height = 13
        self.max_value = 20
        super(Slider, self).__init__()

    def rows(self, *_):
        """
        Return count of rows required to render this widget.
        """
        return self.slider_height + 3

    def render(self, size, focus=None):
        """
        Render widget.
        """
        rows = [('+' if self.value > 0 else '') + str(self.value) + ' dB']

        chars = [' '] * self.slider_height

        if self.value == 0:
            chars[self.slider_height // 2] = Slider.ZERO_CHAR
        else:
            k = ((float(self.value) / (self.max_value + 1)) + 1) / 2  # Convert value to [0;1] range
            section_index = int(k * self.slider_height)
            char_index = int(k * self.slider_height * len(Slider.CHARS)) % len(Slider.CHARS)
            chars[section_index] = Slider.CHARS[char_index]

        rows.extend([
            (
                u'\u2524{}\u251C'
                if i == self.slider_height // 2
                else u'\u2502{}\u2502'
            ).format(x)
            for i, x
            in enumerate(reversed(chars))
        ])
        rows.append(self.freq_str)
        text = urwid.AttrMap(urwid.Text('\n'.join(
            rows
        ), align=urwid.CENTER), 'default', 'panel_focus')
        return text.render(size, focus)

    def keypress(self, _, key):
        """
        Handle equalizer band modification.
        """
        return hotkey_manager.keypress("settings_page", self, None, None, key)

    def equalizer_up(self):
        """
        Turn the equalizer band up
        """
        if self.value < self.max_value:
            self.value += 1
            self.update()

    def equalizer_down(self):
        """
        Turn the equalizer band down
        """
        if self.value > -self.max_value:
            self.value -= 1
            self.update()

    def update(self):
        """
        Update player equalizer & toggle redraw.
        """
        player.set_equalizer_value(self.index, self.value)
        self._invalidate()


class Equalizer(urwid.Columns):
    """
    Represents an equalizer.
    """
    def __init__(self):
        self.bands = [
            Slider(index, freq)
            for index, freq
            in enumerate(player.get_equalizer_freqs())
        ]
        super(Equalizer, self).__init__(
            self.bands
        )


class SettingsPage(urwid.Columns, AbstractPage):
    """
    Settings page.
    """
    @property
    def name(self):
        return 'Settings'

    @property
    def key(self):
        return 9

    @property
    def slug(self):
        """
        Return page ID (str).
        """
        return "settings"

    def __init__(self, app):
        self.app = app
        self.username = urwid.Edit(
            edit_text=settings.get('username', 'play_settings') or ''
        )
        self.password = urwid.Edit(
            mask='*', edit_text=settings.get('password', 'play_settings') or ''
        )
        self.device_id = urwid.Edit(
            edit_text=settings.get('device_id', 'play_settings') or ''
        )
        self.download_tracks = urwid.CheckBox(
            'Download tracks before playback',
            state=settings.get('download_tracks', 'play_settings') or False
        )
        self.equalizer = Equalizer()
        super(SettingsPage, self).__init__([urwid.ListBox(urwid.SimpleListWalker([
            urwid.Text('Settings'),
            urwid.Divider(' '),
            urwid.Text('Username'),
            urwid.AttrWrap(self.username, 'input', 'input_focus'),
            urwid.Divider(' '),
            urwid.Text('Password'),
            urwid.AttrWrap(self.password, 'input', 'input_focus'),
            urwid.Divider(' '),
            urwid.Text('Device ID'),
            urwid.AttrWrap(self.device_id, 'input', 'input_focus'),
            urwid.Divider(' '),
            self.download_tracks,
            urwid.Divider(' '),
            urwid.AttrWrap(urwid.Button(
                'Save', on_press=self.on_save
            ), 'input', 'input_focus'),
            urwid.Divider(u'\u2500'),
            self.equalizer,
        ]))])

    def on_save(self, *_):
        """
        Called when "Save" button is pressed.
        """
        with settings.edit() as config:
            if 'play_settings' not in config:
                config['play_settings'] = {}
            config['play_settings']['username'] = self.username.edit_text
            config['play_settings']['password'] = self.password.edit_text
            config['play_settings']['device_id'] = self.device_id.edit_text
            config['play_settings']['download_tracks'] = self.download_tracks.state

        self.app.set_page('MyLibraryPage')
        self.app.log_in()

    def activate(self):
        pass