2020-04-11 21:14:30 +02:00
|
|
|
# SPDX-License-Identifier: LGPL-3.0-or-later
|
|
|
|
# Copyright (C) 2020 Daniel Thompson
|
|
|
|
|
2020-05-14 23:29:35 +02:00
|
|
|
"""Pager applications
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
The pager is used to present text based information to the user. It is
|
|
|
|
primarily intended for notifications but is also used to provide debugging
|
|
|
|
information when applications crash.
|
|
|
|
"""
|
|
|
|
|
2020-04-11 21:14:30 +02:00
|
|
|
import wasp
|
|
|
|
import icons
|
|
|
|
|
|
|
|
import io
|
|
|
|
import sys
|
|
|
|
|
|
|
|
class PagerApp():
|
2020-05-14 23:29:35 +02:00
|
|
|
"""Show a long text message in a pager."""
|
2020-04-11 21:14:30 +02:00
|
|
|
NAME = 'Pager'
|
|
|
|
ICON = icons.app
|
|
|
|
|
|
|
|
def __init__(self, msg):
|
|
|
|
self._msg = msg
|
|
|
|
self._scroll = wasp.widgets.ScrollIndicator()
|
|
|
|
|
|
|
|
def foreground(self):
|
|
|
|
"""Activate the application."""
|
|
|
|
wasp.system.request_event(wasp.EventMask.SWIPE_UPDOWN)
|
2020-07-19 21:50:33 +02:00
|
|
|
self._redraw()
|
2020-04-11 21:14:30 +02:00
|
|
|
|
|
|
|
def background(self):
|
2020-05-14 23:29:35 +02:00
|
|
|
"""De-activate the application."""
|
2020-07-19 21:50:33 +02:00
|
|
|
self._chunks = None
|
|
|
|
self._numpages = None
|
2020-04-11 21:14:30 +02:00
|
|
|
|
|
|
|
def swipe(self, event):
|
2020-05-14 23:29:35 +02:00
|
|
|
"""Swipe to page up/down."""
|
2020-04-11 21:14:30 +02:00
|
|
|
mute = wasp.watch.display.mute
|
|
|
|
|
|
|
|
if event[0] == wasp.EventType.UP:
|
|
|
|
if self._page >= self._numpages:
|
|
|
|
wasp.system.navigate(wasp.EventType.BACK)
|
|
|
|
return
|
|
|
|
self._page += 1
|
|
|
|
else:
|
|
|
|
if self._page <= 0:
|
|
|
|
wasp.watch.vibrator.pulse()
|
|
|
|
return
|
|
|
|
self._page -= 1
|
|
|
|
mute(True)
|
|
|
|
self._draw()
|
|
|
|
mute(False)
|
|
|
|
|
2020-07-19 21:50:33 +02:00
|
|
|
def _redraw(self):
|
|
|
|
"""Redraw from scratch (jump to the first page)"""
|
|
|
|
self._page = 0
|
|
|
|
self._chunks = wasp.watch.drawable.wrap(self._msg, 240)
|
|
|
|
self._numpages = (len(self._chunks) - 2) // 9
|
|
|
|
self._draw()
|
|
|
|
|
2020-04-11 21:14:30 +02:00
|
|
|
def _draw(self):
|
2020-07-19 21:50:33 +02:00
|
|
|
"""Draw a page from scratch."""
|
2020-04-11 21:14:30 +02:00
|
|
|
draw = wasp.watch.drawable
|
|
|
|
draw.fill()
|
|
|
|
|
|
|
|
page = self._page
|
|
|
|
i = page * 9
|
|
|
|
j = i + 11
|
|
|
|
chunks = self._chunks[i:j]
|
|
|
|
for i in range(len(chunks)-1):
|
|
|
|
sub = self._msg[chunks[i]:chunks[i+1]].rstrip()
|
|
|
|
draw.string(sub, 0, 24*i)
|
|
|
|
|
|
|
|
scroll = self._scroll
|
|
|
|
scroll.up = page > 0
|
|
|
|
scroll.down = page < self._numpages
|
|
|
|
scroll.draw()
|
|
|
|
|
2020-07-19 21:50:33 +02:00
|
|
|
class NotificationApp(PagerApp):
|
|
|
|
NAME = 'Notifications'
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
super().__init__('')
|
2020-10-31 21:51:28 +01:00
|
|
|
self.confirmation_view = wasp.widgets.ConfirmationView()
|
2020-07-19 21:50:33 +02:00
|
|
|
|
|
|
|
def foreground(self):
|
|
|
|
notes = wasp.system.notifications
|
2020-10-31 21:51:28 +01:00
|
|
|
note = notes.pop(next(iter(notes)))
|
2020-10-10 12:28:25 +02:00
|
|
|
title = note['title'] if 'title' in note else 'Untitled'
|
|
|
|
body = note['body'] if 'body' in note else ''
|
|
|
|
self._msg = '{}\n\n{}'.format(title, body)
|
2020-07-19 21:50:33 +02:00
|
|
|
|
2020-10-31 21:51:28 +01:00
|
|
|
wasp.system.request_event(wasp.EventMask.TOUCH)
|
2020-07-19 21:50:33 +02:00
|
|
|
super().foreground()
|
|
|
|
|
2020-11-29 10:03:30 +01:00
|
|
|
def background(self):
|
|
|
|
self.confirmation_view.active = False
|
|
|
|
super().background()
|
|
|
|
|
2020-10-31 21:51:28 +01:00
|
|
|
def swipe(self, event):
|
2020-11-29 10:07:49 +01:00
|
|
|
if self.confirmation_view.active:
|
|
|
|
if event[0] == wasp.EventType.UP:
|
|
|
|
self.confirmation_view.active = False
|
|
|
|
self._draw()
|
|
|
|
return
|
|
|
|
else:
|
|
|
|
if event[0] == wasp.EventType.DOWN and self._page == 0:
|
|
|
|
self.confirmation_view.active = True
|
|
|
|
self._draw()
|
|
|
|
return
|
2020-10-31 21:51:28 +01:00
|
|
|
|
2020-11-29 10:07:49 +01:00
|
|
|
super().swipe(event)
|
2020-10-31 21:51:28 +01:00
|
|
|
|
|
|
|
def _draw(self):
|
|
|
|
if self.confirmation_view.active:
|
2020-11-29 09:53:58 +01:00
|
|
|
self.confirmation_view.draw('Clear notifications?')
|
2020-10-31 21:51:28 +01:00
|
|
|
else:
|
|
|
|
super()._draw()
|
|
|
|
|
|
|
|
def touch(self, event):
|
|
|
|
if self.confirmation_view.active:
|
|
|
|
is_confirmed = self.confirmation_view.touch(event)
|
|
|
|
if is_confirmed:
|
|
|
|
wasp.system.notifications = {}
|
2020-11-29 10:01:08 +01:00
|
|
|
wasp.system.navigate(wasp.EventType.BACK)
|
|
|
|
elif is_confirmed != None:
|
|
|
|
self._draw()
|
2020-10-31 21:51:28 +01:00
|
|
|
|
|
|
|
|
2020-04-11 21:14:30 +02:00
|
|
|
class CrashApp():
|
|
|
|
"""Crash handler application.
|
|
|
|
|
|
|
|
This application is launched automatically whenever another
|
|
|
|
application crashes. Our main job it to indicate as loudly as
|
|
|
|
possible that the system is no longer running correctly. This
|
|
|
|
app deliberately enables inverted video mode in order to deliver
|
|
|
|
that message as strongly as possible.
|
|
|
|
"""
|
|
|
|
def __init__(self, exc):
|
|
|
|
"""Capture the exception information.
|
|
|
|
|
|
|
|
This app does not actually display the exception information
|
|
|
|
but we need to capture the exception info before we leave
|
|
|
|
the except block.
|
|
|
|
"""
|
|
|
|
msg = io.StringIO()
|
|
|
|
sys.print_exception(exc, msg)
|
|
|
|
self._msg = msg.getvalue()
|
|
|
|
msg.close()
|
|
|
|
|
|
|
|
def foreground(self):
|
|
|
|
"""Indicate the system has crashed by drawing a couple of bomb icons.
|
|
|
|
|
|
|
|
If you owned an Atari ST back in the mid-eighties then I hope you
|
|
|
|
recognise this as a tribute a long forgotten home computer!
|
|
|
|
"""
|
|
|
|
wasp.watch.display.invert(False)
|
|
|
|
draw = wasp.watch.drawable
|
|
|
|
draw.blit(icons.bomb, 0, 104)
|
|
|
|
draw.blit(icons.bomb, 32, 104)
|
|
|
|
|
|
|
|
wasp.system.request_event(wasp.EventMask.SWIPE_UPDOWN |
|
|
|
|
wasp.EventMask.SWIPE_LEFTRIGHT)
|
|
|
|
|
|
|
|
def background(self):
|
|
|
|
"""Restore a normal display mode.
|
|
|
|
|
|
|
|
Conceal the display before the transition otherwise the inverted
|
|
|
|
bombs get noticed by the user.
|
|
|
|
"""
|
|
|
|
wasp.watch.display.mute(True)
|
|
|
|
wasp.watch.display.invert(True)
|
|
|
|
|
|
|
|
def swipe(self, event):
|
2020-05-14 23:29:35 +02:00
|
|
|
"""Show the exception message in a pager."""
|
2020-04-11 21:14:30 +02:00
|
|
|
wasp.system.switch(PagerApp(self._msg))
|