mirror of
https://github.com/vale981/clay
synced 2025-03-04 09:11:37 -05:00
Cleanups
This commit is contained in:
parent
77e3f44fa5
commit
5b88ae681a
7 changed files with 160 additions and 51 deletions
31
.flake8
Normal file
31
.flake8
Normal file
|
@ -0,0 +1,31 @@
|
|||
[flake8]
|
||||
# ignore = D203
|
||||
max-line-length=120
|
||||
|
||||
ignore =
|
||||
# blank line at end of file
|
||||
W391
|
||||
|
||||
exclude =
|
||||
# Generated stuff
|
||||
gen,
|
||||
# Coverage HTML report
|
||||
htmlcov,
|
||||
# Logs
|
||||
log,
|
||||
# Requirements
|
||||
requirements,
|
||||
# Temporary stuff
|
||||
tmp,
|
||||
# Virtual envs
|
||||
.env,
|
||||
.env2,
|
||||
.env3,
|
||||
.env36,
|
||||
.venv,
|
||||
.git,
|
||||
wsgi.py,
|
||||
utils,
|
||||
# VLC bindings
|
||||
vlc.py
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
from clay.app import main
|
||||
|
99
clay/app.py
99
clay/app.py
|
@ -1,23 +1,26 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# pylint: disable=wrong-import-position
|
||||
# pylint: disable=too-many-instance-attributes
|
||||
"""
|
||||
Main app entrypoint.
|
||||
"""
|
||||
|
||||
import sys
|
||||
sys.path.append('.')
|
||||
sys.path.append('.') # noqa
|
||||
|
||||
import urwid
|
||||
|
||||
from clay.player import player
|
||||
from clay.widgets import PlayProgress
|
||||
from clay.pages import StartUp, Error
|
||||
from clay.pages import StartUp
|
||||
from clay.mylibrary import MyLibrary
|
||||
from clay.myplaylists import MyPlaylists
|
||||
from clay.playerqueue import Queue
|
||||
from clay.settings import Settings
|
||||
from clay.notifications import NotificationArea
|
||||
# from clay import hotkeys
|
||||
|
||||
|
||||
loop = None
|
||||
|
||||
PALETTE = [
|
||||
('logo', '', '', '', '#F54', ''),
|
||||
|
||||
|
@ -45,24 +48,39 @@ PALETTE = [
|
|||
|
||||
('flag', '', '', '', '#AAA', ''),
|
||||
('flag-active', '', '', '', '#F54', ''),
|
||||
|
||||
('notification', '', '', '', '#F54', '#222'),
|
||||
]
|
||||
|
||||
|
||||
class AppWidget(urwid.Frame):
|
||||
"""
|
||||
Root widget.
|
||||
|
||||
Handles tab switches, global keypresses etc.
|
||||
"""
|
||||
class Tab(urwid.Text):
|
||||
"""
|
||||
Represents a single tab in header tabbar.
|
||||
"""
|
||||
def __init__(self, page):
|
||||
self.page = page
|
||||
# self.attrwrap = urwid.AttrWrap(urwid.Text(), 'panel')
|
||||
super(AppWidget.Tab, self).__init__(
|
||||
self.get_title()
|
||||
)
|
||||
|
||||
def set_active(self, active):
|
||||
"""
|
||||
Mark tab visually as active.
|
||||
"""
|
||||
self.set_text(
|
||||
[('panel_focus' if active else 'panel', self.get_title())]
|
||||
)
|
||||
|
||||
def get_title(self):
|
||||
"""
|
||||
Render tab title.
|
||||
"""
|
||||
return ' {} {} '.format(
|
||||
self.page.key,
|
||||
self.page.name
|
||||
|
@ -71,7 +89,6 @@ class AppWidget(urwid.Frame):
|
|||
def __init__(self):
|
||||
self.pages = [
|
||||
StartUp(self),
|
||||
Error(self),
|
||||
MyLibrary(self),
|
||||
MyPlaylists(self),
|
||||
Queue(self),
|
||||
|
@ -83,6 +100,7 @@ class AppWidget(urwid.Frame):
|
|||
in self.pages
|
||||
if hasattr(page, 'key')
|
||||
]
|
||||
NotificationArea.set_app(self)
|
||||
self.header = urwid.Pile([
|
||||
# urwid.Divider('\u2500'),
|
||||
urwid.AttrWrap(urwid.Columns([
|
||||
|
@ -90,6 +108,7 @@ class AppWidget(urwid.Frame):
|
|||
for tab
|
||||
in self.tabs
|
||||
], dividechars=1), 'panel'),
|
||||
NotificationArea.get()
|
||||
# urwid.Divider('\u2500')
|
||||
])
|
||||
self.seekbar = PlayProgress(
|
||||
|
@ -116,27 +135,48 @@ class AppWidget(urwid.Frame):
|
|||
body=self.current_page
|
||||
)
|
||||
|
||||
self.loop = None
|
||||
|
||||
player.media_position_changed += self.media_position_changed
|
||||
player.media_state_changed += self.media_state_changed
|
||||
player.track_changed += self.track_changed
|
||||
player.playback_flags_changed += self.playback_flags_changed
|
||||
|
||||
def set_loop(self, loop):
|
||||
"""
|
||||
Assign a MainLoop to this app.
|
||||
"""
|
||||
self.loop = loop
|
||||
|
||||
def media_position_changed(self, progress):
|
||||
"""
|
||||
Update slider in seekbar.
|
||||
Called when current play position changes.
|
||||
"""
|
||||
if progress < 0:
|
||||
progress = 0
|
||||
self.seekbar.set_completion(progress * 100)
|
||||
loop.draw_screen()
|
||||
# sleep(0.2)
|
||||
self.loop.draw_screen()
|
||||
|
||||
# self.set_page(MyLibrary())
|
||||
|
||||
def media_state_changed(self, is_playing):
|
||||
def media_state_changed(self, _):
|
||||
"""
|
||||
Update seekbar.
|
||||
Called when playback is paused/unpaused.
|
||||
"""
|
||||
self.seekbar.update()
|
||||
|
||||
def track_changed(self, track):
|
||||
"""
|
||||
Update displayed track in seekbar.
|
||||
Called when current track changes.
|
||||
"""
|
||||
self.seekbar.set_track(track)
|
||||
|
||||
def playback_flags_changed(self):
|
||||
"""
|
||||
Update seekbar flags.
|
||||
Called when random/repeat flags change.
|
||||
"""
|
||||
self.shuffle_el.attr = 'flag-active' \
|
||||
if player.get_is_random() \
|
||||
else 'flag'
|
||||
|
@ -145,15 +185,10 @@ class AppWidget(urwid.Frame):
|
|||
else 'flag'
|
||||
self.seekbar.update()
|
||||
|
||||
def set_page(self, classname, *args):
|
||||
# if isinstance(page_class, str):
|
||||
# page_class = [
|
||||
# page
|
||||
# for page
|
||||
# in self.pages
|
||||
# if page.__name__ == page_class
|
||||
# ][0]
|
||||
# self.current_page = page_class(self, *args)
|
||||
def set_page(self, classname):
|
||||
"""
|
||||
Switch to a different tab.
|
||||
"""
|
||||
page = [page for page in self.pages if page.__class__.__name__ == classname][0]
|
||||
self.current_page = page
|
||||
self.contents['body'] = (page, None)
|
||||
|
@ -169,12 +204,18 @@ class AppWidget(urwid.Frame):
|
|||
page.start()
|
||||
|
||||
def redraw(self):
|
||||
if loop:
|
||||
loop.draw_screen()
|
||||
"""
|
||||
Redraw screen.
|
||||
Needs to be called by other widgets if UI was changed from a different thread.
|
||||
"""
|
||||
if self.loop:
|
||||
self.loop.draw_screen()
|
||||
|
||||
def keypress(self, size, key):
|
||||
if isinstance(self.current_page, StartUp):
|
||||
return
|
||||
"""
|
||||
Handle keypress.
|
||||
Can switch tabs, control playbackm, flags, notifications and app state.
|
||||
"""
|
||||
for tab in self.tabs:
|
||||
if 'meta {}'.format(tab.page.key) == key:
|
||||
self.set_page(tab.page.__class__.__name__)
|
||||
|
@ -196,18 +237,22 @@ class AppWidget(urwid.Frame):
|
|||
player.set_repeat_one(not player.get_is_repeat_one())
|
||||
elif key == 'ctrl q':
|
||||
sys.exit(0)
|
||||
elif key == 'esc':
|
||||
NotificationArea.close_all()
|
||||
else:
|
||||
super(AppWidget, self).keypress(size, key)
|
||||
|
||||
|
||||
def main():
|
||||
global loop
|
||||
"""
|
||||
Application entrypoint.
|
||||
"""
|
||||
app_widget = AppWidget()
|
||||
loop = urwid.MainLoop(app_widget, PALETTE)
|
||||
app_widget.set_loop(loop)
|
||||
loop.screen.set_terminal_properties(256)
|
||||
loop.run()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@ def async(fn):
|
|||
result = fn(*args, **kwargs)
|
||||
except Exception as e:
|
||||
callback(None, e, **extra)
|
||||
raise
|
||||
else:
|
||||
callback(result, None, **extra)
|
||||
|
||||
|
@ -147,5 +146,6 @@ class GP(object):
|
|||
def is_authenticated(self):
|
||||
return self.mc.is_authenticated()
|
||||
|
||||
|
||||
gp = GP()
|
||||
|
||||
|
|
50
clay/notifications.py
Normal file
50
clay/notifications.py
Normal file
|
@ -0,0 +1,50 @@
|
|||
import urwid
|
||||
|
||||
|
||||
class NotificationArea(urwid.Pile):
|
||||
instance = None
|
||||
app = None
|
||||
|
||||
TEMPLATE = ' \u26A1 {}'
|
||||
|
||||
def __init__(self):
|
||||
super().__init__([])
|
||||
|
||||
@classmethod
|
||||
def get(cls):
|
||||
if cls.instance is None:
|
||||
cls.instance = NotificationArea()
|
||||
|
||||
return cls.instance
|
||||
|
||||
@classmethod
|
||||
def set_app(cls, app):
|
||||
cls.app = app
|
||||
|
||||
@classmethod
|
||||
def notify(cls, message):
|
||||
cls.instance._notify(message)
|
||||
|
||||
@classmethod
|
||||
def close_all(cls):
|
||||
cls.instance._close_all()
|
||||
|
||||
def _notify(self, message):
|
||||
text = urwid.Text(self.__class__.TEMPLATE.format(message))
|
||||
self.contents.append(
|
||||
(
|
||||
urwid.AttrWrap(
|
||||
urwid.Columns([
|
||||
text,
|
||||
('pack', urwid.Text('[Hit ESC to close] '))
|
||||
]),
|
||||
'notification'
|
||||
),
|
||||
('weight', 1)
|
||||
)
|
||||
)
|
||||
self.__class__.app.redraw()
|
||||
|
||||
def _close_all(self):
|
||||
self.contents[:] = []
|
||||
|
|
@ -2,6 +2,7 @@ import urwid
|
|||
from clay.settings import Settings
|
||||
from clay.gp import gp
|
||||
from clay.meta import VERSION
|
||||
from clay.notifications import NotificationArea
|
||||
|
||||
|
||||
class StartUp(urwid.Filler):
|
||||
|
@ -29,14 +30,11 @@ class StartUp(urwid.Filler):
|
|||
|
||||
def on_login(self, success, error):
|
||||
if error:
|
||||
self.app.set_page(
|
||||
'Error',
|
||||
'Failed to log in: {}'.format(str(error))
|
||||
)
|
||||
NotificationArea.notify('Failed to log in: {}'.format(str(error)))
|
||||
return
|
||||
|
||||
if not success:
|
||||
self.app.set_page(
|
||||
'Error',
|
||||
NotificationArea.notify(
|
||||
'Google Play Music login failed '
|
||||
'(API returned false)'
|
||||
)
|
||||
|
@ -54,20 +52,7 @@ class StartUp(urwid.Filler):
|
|||
callback=self.on_login
|
||||
)
|
||||
else:
|
||||
self.app.set_page(
|
||||
'Error',
|
||||
NotificationArea.notify(
|
||||
'Please set your credentials on the settings page.'
|
||||
)
|
||||
|
||||
|
||||
class Error(urwid.Filler):
|
||||
def __init__(self, app):
|
||||
self.text = urwid.Text('Error'),
|
||||
super(Error, self).__init__(
|
||||
self.text,
|
||||
valign='top'
|
||||
)
|
||||
|
||||
def set_error(self, error):
|
||||
self.text = 'Error:\n\n{}'.format(str(error))
|
||||
|
||||
|
|
2
setup.py
2
setup.py
|
@ -12,7 +12,7 @@ setup(
|
|||
packages=find_packages(),
|
||||
entry_points={
|
||||
'console_scripts': [
|
||||
'clay=clay.__main__:main'
|
||||
'clay=clay.app:main'
|
||||
]
|
||||
}
|
||||
)
|
||||
|
|
Loading…
Add table
Reference in a new issue