Skip to content
Snippets Groups Projects
Commit 3e11f698 authored by Anon's avatar Anon Committed by schneider
Browse files

py/gr33nhouse: create initial version of app store

parent c2cac44c
Branches
No related tags found
No related merge requests found
from st3m.application import Application, ApplicationContext
from st3m.input import InputController, InputState
from st3m.ui import colours
from st3m.ui.view import ViewManager
from ctx import Context
from .applist import AppList
from .background import Flow3rView
from .record import RecordView
from .manual import ManualInputView
class Gr33nhouseApp(Application):
items = ["Browse apps", "Record App Seed", "Enter App Seed"]
selection = 0
input: InputController
background: Flow3rView
def __init__(self, app_ctx: ApplicationContext) -> None:
super().__init__(app_ctx=app_ctx)
self.input = InputController()
self.background = Flow3rView()
def on_enter(self, vm: ViewManager | None) -> None:
super().on_enter(vm)
if self.vm is None:
raise RuntimeError("vm is None")
def draw(self, ctx: Context) -> None:
self.background.draw(ctx)
ctx.save()
ctx.gray(1.0)
ctx.rectangle(
-120.0,
-15.0,
240.0,
30.0,
).fill()
ctx.translate(0, -30 * self.selection)
offset = 0
ctx.font = "Camp Font 3"
ctx.font_size = 24
ctx.text_align = ctx.CENTER
ctx.text_baseline = ctx.MIDDLE
for idx, item in enumerate(self.items):
if idx == self.selection:
ctx.gray(0.0)
else:
ctx.gray(1.0)
ctx.move_to(0, offset)
ctx.text(item)
offset += 30
ctx.restore()
def think(self, ins: InputState, delta_ms: int) -> None:
self.background.think(ins, delta_ms)
self.input.think(ins, delta_ms)
if self.input.buttons.app.left.pressed:
if self.selection > 0:
self.selection -= 1
elif self.input.buttons.app.right.pressed:
if self.selection < len(self.items) - 1:
self.selection += 1
elif self.input.buttons.app.middle.pressed:
if self.selection == 0:
self.vm.push(AppList())
elif self.selection == 1:
self.vm.push(RecordView())
elif self.selection == 2:
self.vm.push(ManualInputView())
from st3m.goose import Optional, Enum
from st3m.input import InputController, InputState
from st3m.ui import colours
from st3m.ui.view import BaseView, ViewManager
from ctx import Context
import urequests
import time
from .background import Flow3rView
from .confirmation import ConfirmationView
class ViewState(Enum):
INITIAL = 1
LOADING = 2
ERROR = 3
LOADED = 4
class AppList(BaseView):
initial_ticks: int = 0
_state: ViewState = ViewState.INITIAL
apps: list[any] = []
selection: int = 0
input: InputController
background: Flow3rView
def __init__(self) -> None:
self.input = InputController()
self.vm = None
self.background = Flow3rView()
def on_enter(self, vm: Optional[ViewManager]) -> None:
self.vm = vm
self.initial_ticks = time.ticks_ms()
def draw(self, ctx: Context) -> None:
ctx.move_to(0, 0)
if self._state == ViewState.INITIAL or self._state == ViewState.LOADING:
ctx.rgb(*colours.BLACK)
ctx.rectangle(
-120.0,
-120.0,
240.0,
240.0,
).fill()
ctx.save()
ctx.rgb(*colours.WHITE)
ctx.font = "Camp Font 3"
ctx.font_size = 24
ctx.text_align = ctx.CENTER
ctx.text_baseline = ctx.MIDDLE
ctx.text("Collecting seeds...")
ctx.restore()
return
elif self._state == ViewState.ERROR:
ctx.rgb(*colours.BLACK)
ctx.rectangle(
-120.0,
-120.0,
240.0,
240.0,
).fill()
ctx.save()
ctx.rgb(*colours.WHITE)
ctx.gray(1.0)
ctx.font = "Camp Font 3"
ctx.font_size = 24
ctx.text_align = ctx.CENTER
ctx.text_baseline = ctx.MIDDLE
ctx.text("Something went wrong")
ctx.restore()
return
elif self._state == ViewState.LOADED:
self.background.draw(ctx)
ctx.save()
ctx.gray(1.0)
ctx.rectangle(
-120.0,
-15.0,
240.0,
30.0,
).fill()
ctx.translate(0, -30 * self.selection)
offset = 0
ctx.font = "Camp Font 3"
ctx.font_size = 24
ctx.text_align = ctx.CENTER
ctx.text_baseline = ctx.MIDDLE
ctx.move_to(0, 0)
for idx, app in enumerate(self.apps):
if idx == self.selection:
ctx.gray(0.0)
else:
ctx.gray(1.0)
ctx.move_to(0, offset)
ctx.text(app["name"])
offset += 30
ctx.restore()
else:
raise RuntimeError(f"Invalid view state {self._state}")
def think(self, ins: InputState, delta_ms: int) -> None:
if self.initial_ticks == 0 or time.ticks_ms() < self.initial_ticks + 300:
return
self.input.think(ins, delta_ms)
if self._state == ViewState.INITIAL:
try:
self._state = ViewState.LOADING
print("Loading app list...")
res = urequests.get("https://flow3r.garden/api/apps.json")
self.apps = res.json()["apps"]
if self.apps == None:
print(f"Invalid JSON or no apps: {res.json()}")
self._state = ViewState.ERROR
return
self._state = ViewState.LOADED
print("App list loaded")
except Exception as e:
print(f"Load failed: {e}")
self._state = ViewState.ERROR
return
elif self._state == ViewState.LOADING:
raise RuntimeError(f"Invalid view state {self._state}")
elif self._state == ViewState.ERROR:
return
self.background.think(ins, delta_ms)
if self.input.buttons.app.left.pressed:
if self.selection > 0:
self.selection -= 1
elif self.input.buttons.app.right.pressed:
if self.selection < len(self.apps) - 1:
self.selection += 1
elif self.input.buttons.app.middle.pressed:
print(f"state {self._state}")
print(f">> {self.apps[self.selection]}")
app = self.apps[self.selection]
url = app["tarDownloadUrl"]
name = app["name"]
author = app["author"]
# self.vm.push(DownloadView(url))
self.vm.push(
ConfirmationView(
url=url,
name=name,
author=author,
)
)
import random
from st3m.input import InputController, InputState
from st3m.ui.view import BaseView
from ctx import Context
class Flow3rView(BaseView):
input: InputController
def __init__(self) -> None:
self.vm = None
self.input = InputController()
self.flowers = []
for i in range(8):
self.flowers.append(
Flower(
((random.getrandbits(16) - 32767) / 32767.0) * 200,
((random.getrandbits(16)) / 65535.0) * 240 - 120,
((random.getrandbits(16)) / 65535.0) * 400 + 25,
)
)
def think(self, ins: InputState, delta_ms: int) -> None:
super().think(ins, delta_ms)
for c in self.flowers:
c.y += (10 * delta_ms / 1000.0) * 200 / c.z
if c.y > 300:
c.y = -300
c.rot += delta_ms * c.rot_speed
self.flowers = sorted(self.flowers, key=lambda c: -c.z)
def draw(self, ctx: Context) -> None:
ctx.save()
ctx.rectangle(-120, -120, 240, 240)
ctx.rgb(0.1, 0.4, 0.3)
ctx.fill()
for f in self.flowers:
f.draw(ctx)
ctx.restore()
class Flower:
def __init__(self, x: float, y: float, z: float) -> None:
self.x = x
self.y = y
self.z = z
self.rot = 0
self.rot_speed = (((random.getrandbits(16) - 32767) / 32767.0) - 0.5) / 800
def draw(self, ctx: Context):
ctx.save()
ctx.translate(-78 + self.x, -70 + self.y)
ctx.translate(50, 40)
ctx.rotate(self.rot)
ctx.translate(-50, -40)
ctx.scale(100 / self.z, 100.0 / self.z)
ctx.move_to(76.221727, 3.9788409).curve_to(
94.027758, 31.627675, 91.038918, 37.561293, 94.653428, 48.340473
).rel_curve_to(
25.783102, -3.90214, 30.783332, -1.52811, 47.230192, 4.252451
).rel_curve_to(
-11.30184, 19.609496, -21.35729, 20.701768, -35.31018, 32.087063
).rel_curve_to(
5.56219, 12.080061, 12.91196, 25.953973, 9.98735, 45.917643
).rel_curve_to(
-19.768963, -4.59388, -22.879866, -10.12216, -40.896842, -23.93099
).rel_curve_to(
-11.463256, 10.23025, -17.377386, 18.2378, -41.515124, 25.03533
).rel_curve_to(
0.05756, -29.49286, 4.71903, -31.931936, 10.342734, -46.700913
).curve_to(
33.174997, 77.048676, 19.482194, 71.413009, 8.8631648, 52.420793
).curve_to(
27.471602, 45.126773, 38.877997, 45.9184, 56.349456, 48.518302
).curve_to(
59.03275, 31.351935, 64.893201, 16.103886, 76.221727, 3.9788409
).close_path().rgba(
1.0, 0.6, 0.4, 0.4
).fill()
ctx.restore()
return
ctx.move_to(116.89842, 17.221179).rel_curve_to(
6.77406, 15.003357, 9.99904, 35.088466, 0.27033, 47.639569
).curve_to(
108.38621, 76.191194, 87.783414, 86.487988, 75.460015, 75.348373
).curve_to(
64.051094, 64.686361, 61.318767, 54.582827, 67.499384, 36.894251
).curve_to(
79.03955, 16.606134, 103.60918, 15.612261, 116.89842, 17.221179
).close_path().rgb(
0.5, 0.3, 0.4
).fill()
ctx.move_to(75.608612, 4.2453713).curve_to(
85.516707, 17.987709, 93.630911, 33.119248, 94.486497, 49.201225
).curve_to(
95.068862, 60.147617, 85.880014, 75.820834, 74.919761, 75.632395
).curve_to(
63.886159, 75.442695, 57.545631, 61.257211, 57.434286, 50.22254
).curve_to(
57.257291, 32.681814, 65.992688, 16.610811, 75.608612, 4.2453713
).close_path().rgb(
0.2, 0.5, 0.8
).fill()
ctx.restore()
from st3m.input import InputController, InputState
from st3m.ui import colours
from st3m.ui.view import BaseView, ViewManager
from ctx import Context
from .background import Flow3rView
class ConfirmationView(BaseView):
background: Flow3rView
input: InputController
url: str
name: str
author: str
def __init__(self, url: str, name: str, author: str) -> None:
self.input = InputController()
self.vm = None
self.background = Flow3rView()
self.url = url
self.name = name
self.author = author
def on_enter(self, vm: ViewManager | None) -> None:
super().on_enter(vm)
if self.vm is None:
raise RuntimeError("vm is None")
def draw(self, ctx: Context) -> None:
ctx.move_to(0, 0)
self.background.draw(ctx)
ctx.save()
ctx.rgb(*colours.WHITE)
ctx.rectangle(
-120.0,
-80.0,
240.0,
160.0,
).fill()
ctx.rgb(*colours.BLACK)
ctx.font = "Camp Font 3"
ctx.font_size = 24
ctx.text_align = ctx.CENTER
ctx.text_baseline = ctx.MIDDLE
ctx.move_to(0, -60)
ctx.text("Install")
ctx.move_to(0, -30)
ctx.text(self.name)
ctx.move_to(0, 0)
ctx.text("by")
ctx.move_to(0, 30)
ctx.text(self.author)
ctx.move_to(0, 60)
ctx.text("?")
ctx.restore()
def think(self, ins: InputState, delta_ms: int) -> None:
self.input.think(ins, delta_ms)
self.background.think(ins, delta_ms)
import network
from st3m.input import InputState
import urequests
import gzip
import utarfile
import io
import os
from st3m.ui.view import BaseView
from ctx import Context
class DownloadView(BaseView):
def __init__(self, url: str) -> None:
super().__init__()
self._state = 1
self._try = 1
self._url = url
def draw(self, ctx: Context) -> None:
ctx.rgb(0, 0, 0).rectangle(-120, -120, 240, 240).fill()
if self._state == 1 or self._state == 2:
# Fetching
ctx.rgb(255, 0, 0).rectangle(-20, -20, 40, 40).fill()
self._state = 2
elif self._state == 3 or self._state == 4:
# Extracting
ctx.rgb(0, 0, 255).rectangle(-20, -20, 40, 40).fill()
self._state = 4
elif self._state == 5:
# Done
ctx.rgb(0, 255, 0).rectangle(-20, -20, 40, 40).fill()
def think(self, ins: InputState, delta_ms: int) -> None:
super().think(ins, delta_ms) # Let BaseView do its thing
if self._state == 2:
try:
print("Getting it")
self.response = urequests.get(self._url)
if self.response.content is not None:
print("Got something")
self._state = 3
return
print("no content...")
except:
print("Exception")
print("Next try")
self._try += 1
elif self._state == 4:
tar = gzip.decompress(self.response.content)
self.response = None
t = utarfile.TarFile(fileobj=io.BytesIO(tar))
for i in t:
print(i.name)
if i.type == utarfile.DIRTYPE:
print("dirtype")
dirname = "/flash/sys/apps/" + i.name
if not os.path.exists(dirname):
print("making", dirname)
os.mkdir(dirname)
else:
print("dir", dirname, "exists")
else:
filename = "/flash/sys/apps/" + i.name
print("writing to", filename)
f = t.extractfile(i)
with open(filename, "wb") as of:
of.write(f.read())
self._state = 5
self.vm.pop()
[app]
name = "Get Apps"
menu = "Apps"
[entry]
class = "Gr33nhouseApp"
[metadata]
author = "Flow3r Badge Authors"
license = "LGPL-3.0-only"
url = "https://git.flow3r.garden/flow3r/flow3r-firmware"
from st3m.input import InputController, InputState
from st3m.ui import colours
from st3m.ui.view import BaseView, ViewManager
from ctx import Context
from .background import Flow3rView
class ManualInputView(BaseView):
input: InputController
def __init__(self) -> None:
self.input = InputController()
self.vm = None
self.background = Flow3rView()
def on_enter(self, vm: ViewManager | None) -> None:
super().on_enter(vm)
if self.vm is None:
raise RuntimeError("vm is None")
def draw(self, ctx: Context) -> None:
ctx.move_to(0, 0)
ctx.save()
ctx.rgb(*colours.BLACK)
ctx.rectangle(
-120.0,
-120.0,
240.0,
240.0,
).fill()
ctx.rgb(*colours.WHITE)
ctx.font = "Camp Font 3"
ctx.font_size = 24
ctx.text_align = ctx.CENTER
ctx.text_baseline = ctx.MIDDLE
ctx.text("Coming soon")
ctx.restore()
def think(self, ins: InputState, delta_ms: int) -> None:
self.input.think(ins, delta_ms)
from st3m.input import InputController, InputState
from st3m.ui import colours
from st3m.ui.view import BaseView, ViewManager
from ctx import Context
from .background import Flow3rView
class RecordView(BaseView):
input: InputController
def __init__(self) -> None:
self.input = InputController()
self.vm = None
self.background = Flow3rView()
def on_enter(self, vm: ViewManager | None) -> None:
super().on_enter(vm)
if self.vm is None:
raise RuntimeError("vm is None")
def draw(self, ctx: Context) -> None:
ctx.move_to(0, 0)
ctx.save()
ctx.rgb(*colours.BLACK)
ctx.rectangle(
-120.0,
-120.0,
240.0,
240.0,
).fill()
ctx.rgb(*colours.WHITE)
ctx.font = "Camp Font 3"
ctx.font_size = 24
ctx.text_align = ctx.CENTER
ctx.text_baseline = ctx.MIDDLE
ctx.text("Coming soon")
ctx.restore()
def think(self, ins: InputState, delta_ms: int) -> None:
self.input.think(ins, delta_ms)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment