wasp-os/wasp/apps/musicplayer.py
Daniel Thompson 1670be2672 apps: music: Update the application icon
Switch from a headphone to music notation metaphor and take the (lazy?)
approach of using the watch chassis to frame the icon.

Signed-off-by: Daniel Thompson <daniel@redfelineninja.org.uk>
2021-01-10 15:17:27 +00:00

219 lines
7.3 KiB
Python

# SPDX-License-Identifier: LGPL-3.0-or-later
# Copyright (C) 2020 Daniel Thompson
# Copyright (C) 2020 Carlos Gil
"""Music Player for GadgetBridge
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. figure:: res/MusicApp.png
:width: 179
Screenshot of the Music Player application
Music Player Controller:
* Touch: play/pause
* Swipe UPDOWN: Volume down/up
* Swipe LEFTRIGHT: next/previous
"""
import wasp
import icons
import time
# 2-bit RLE, generated from res/music_icon.png, 358 bytes
icon = (
b'\x02'
b'`@'
b'\x1e\xa4<\xa4<\xa4;\xa6?X\xec2\xf0/\xf2-'
b'\xf4,\xc3@[n\xc3,\xc3n\xc3,\xc3n\xc3,'
b'\xc3n\xc3,\xc3b\xc7E\xc3,\xc3]\xccE\xc3,'
b'\xc3Z\xcfE\xc3,\xc3T\xd5E\xc3,\xc3Q\xd8E'
b'\xc3,\xc3Q\xd8E\xc3,\xc3Q\xd8E\xc3,\xc3Q'
b'\xd0E\xc3E\xc3,\xc3Q\xccI\xc3E\xc3,\xc3Q'
b'\xc9L\xc3E\xc3,\xc3Q\xc5P\xc3E\xc3,\xc3Q'
b'\xc3R\xc3E\xc3,\xc3Q\xc3R\xc3E\xc3,\xc3Q'
b'\xc3R\xc3E\xc3+\xc4Q\xc3R\xc3E\xc3*\xc5Q'
b'\xc3R\xc3E\xc3*\xc5Q\xc3R\xc3E\xc3*\xc5Q'
b'\xc3R\xc3E\xc3*\xc5Q\xc3R\xc3E\xc3*\xc5Q'
b'\xc3R\xc3E\xc3*\xc5Q\xc3R\xc3E\xc3*\xc5Q'
b'\xc3L\xc4B\xc3E\xc3+\xc4Q\xc3I\xccE\xc3,'
b'\xc3Q\xc3H\xcdE\xc3,\xc3Q\xc3G\xceE\xc3,'
b'\xc3K\xc3C\xc3F\xcfE\xc3,\xc3H\xccF\xcfE'
b'\xc3,\xc3G\xcdF\xcfE\xc3,\xc3F\xceF\xcfE'
b'\xc3,\xc3E\xcfF\xcfE\xc3,\xc3E\xcfG\xceE'
b'\xc3,\xc3D\xd0H\xccF\xc3,\xc3D\xd0I\xcaG'
b'\xc3,\xc3E\xcfK\xc5J\xc3,\xc3E\xce[\xc3,'
b'\xc3F\xcd[\xc3,\xc3G\xca]\xc3,\xc3I\xc7^'
b'\xc3,\xc3n\xc3,\xc3n\xc3,\xc3n\xc3,\xc3n'
b'\xc3,\xf4-\xf2/\xf02\xec?X\xa6;\xa4<\xa4'
b'<\xa4\x1e'
)
class MusicPlayerApp(object):
""" Music Player Controller application."""
NAME = 'Music'
ICON = icon
def __init__(self):
self._play_icon = icons.play
self._pause_icon = icons.pause
self._play_state = False
self._icon_state = self._play_icon
self._max_display = 240
self._icon_size = 72
self._center_at = int((self._max_display - self._icon_size)/2)
self._musicstate = 'pause'
self._artist = ''
self._track = ''
self._state_changed = True
self._track_changed = True
self._artist_changed = True
def _send_cmd(self, cmd):
print('\r')
for i in range(1):
for i in range(0, len(cmd), 20):
print(cmd[i: i + 20], end='')
time.sleep(0.2)
print(' ')
print(' ')
def _fill_space(self, key):
if key == 'top':
wasp.watch.drawable.fill(
x=0, y=0, w=self._max_display, h=self._center_at)
elif key == 'mid':
wasp.watch.drawable.fill(x=self._center_at, y=self._center_at,
w=self._icon_size, h=self._icon_size)
elif key == 'down':
wasp.watch.drawable.fill(x=0, y=self._center_at + self._icon_size,
w=self._max_display,
h=self._max_display - (self._center_at + self._icon_size))
def foreground(self):
"""Activate the application."""
state = wasp.system.musicstate.get('state')
artist = wasp.system.musicinfo.get('artist')
track = wasp.system.musicinfo.get('track')
if state:
self._musicstate = state
if self._musicstate == 'play':
self._play_state = True
self._icon_state = self._pause_icon
elif self._musicstate == 'pause':
self._play_state = False
self._icon_state = self._play_icon
if artist:
self._artist = artist
if track:
self._track = track
wasp.watch.drawable.fill()
self.draw()
wasp.system.request_tick(1000)
wasp.system.request_event(wasp.EventMask.SWIPE_UPDOWN |
wasp.EventMask.SWIPE_LEFTRIGHT |
wasp.EventMask.TOUCH)
def background(self):
"""De-activate the application (without losing state)."""
self._state_changed = True
self._track_changed = True
self._artist_changed = True
def tick(self, ticks):
wasp.system.keep_awake()
music_state_now = wasp.system.musicstate.get('state')
music_artist_now = wasp.system.musicinfo.get('artist')
music_track_now = wasp.system.musicinfo.get('track')
if music_state_now:
if music_state_now != self._musicstate:
self._musicstate = music_state_now
self._state_changed = True
else:
self._state_changed = False
wasp.system.musicstate = {}
if music_track_now:
if music_track_now != self._track:
self._track = music_track_now
self._track_changed = True
else:
self._track_changed = False
if music_artist_now:
if music_artist_now != self._artist:
self._artist = music_artist_now
self._artist_changed = True
else:
self._artist_changed = False
wasp.system.musicinfo = {}
self._update()
def swipe(self, event):
"""
Notify the application of a touchscreen swipe event.
"""
if event[0] == wasp.EventType.UP:
self._send_cmd('{"t":"music", "n":"volumeup"} ')
elif event[0] == wasp.EventType.DOWN:
self._send_cmd('{"t":"music", "n":"volumedown"} ')
elif event[0] == wasp.EventType.LEFT:
self._send_cmd('{"t":"music", "n":"next"} ')
elif event[0] == wasp.EventType.RIGHT:
self._send_cmd('{"t":"music", "n":"previous"} ')
def touch(self, event):
self._play_state = not self._play_state
if self._play_state:
self._musicstate = 'play'
self._icon_state = self._pause_icon
self._draw_button()
self._send_cmd('{"t":"music", "n":"play"} ')
else:
self._musicstate = 'pause'
self._icon_state = self._play_icon
self._draw_button()
self._send_cmd('{"t":"music", "n":"pause"} ')
def draw(self):
"""Redraw the display from scratch."""
self._draw()
def _draw(self):
"""Redraw the updated zones."""
if self._state_changed:
self._draw_button()
if self._track_changed:
self._draw_label(self._track, 24 + 144)
if self._artist_changed:
self._draw_label(self._artist, 12)
def _draw_button(self):
"""Redraw player button"""
self._fill_space('mid')
wasp.watch.drawable.blit(self._icon_state, self._center_at,
self._center_at)
def _draw_label(self, label, pos):
"""Redraw label info"""
if label:
draw = wasp.watch.drawable
chunks = draw.wrap(label, 240)
self._fill_space(pos)
for i in range(len(chunks)-1):
sub = label[chunks[i]:chunks[i+1]].rstrip()
draw.string(sub, 0, pos + 24 * i, 240)
def _update(self):
if self._musicstate == 'play':
self._play_state = True
self._icon_state = self._pause_icon
elif self._musicstate == 'pause':
self._play_state = False
self._icon_state = self._play_icon
self._draw()
def update(self):
pass