You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
bingo-cli/bingo.py

122 lines
4.0 KiB
Python

#!/usr/bin/env python3
from textual.app import App, ComposeResult
from textual.widgets import Header, Input, Static, Button
from textual.containers import Horizontal, Container
from textual.validation import Number
from textual.command import DiscoveryHit, Provider, Hits, Hit
from textual.reactive import reactive
from datetime import datetime
from BingoBoard import BingoBoard
MESSAGE = '''
Be excellent to each other!
Made with :red_heart: by Panki
[@click="app.open_link('https://tty0.social/@panki')"]Mastodon:[/] tty0.social/@panki
[@click="app.open_link('https://git.theresno.cloud/panki/bingo-cli')"]Source:[/] git.theresno.cloud/panki/bingo-cli
Built using [@click="app.open_link('https://textual.textualize.io/')"]Textual[/]
'''
class AboutCommand(Provider):
async def discover(self) -> Hits:
yield DiscoveryHit(display='About', command=self.app.action_toggle_sidebar, help='Link to repo etc.')
def show_about(self):
pass
async def search(self, query: str) -> Hits:
matcher = self.matcher(query)
command = "About"
score = matcher.match(command)
if score > 0:
yield Hit(score, matcher.highlight(command), self.app.action_toggle_sidebar, 'Link to repo etc.')
class Sidebar(Container):
def compose(self) -> ComposeResult:
yield Static('CCC Bingo', classes='title')
yield Static(MESSAGE, classes='message')
self.button = Button('< Back', variant='primary', classes='btn_sidebar')
self.button.disabled = True
yield self.button
def on_button_pressed(self, event: Button.Pressed) -> None:
print('sidebar button press')
self.app.action_toggle_sidebar()
class BingoApp(App):
'''A Textual app to run a Bingo board.'''
CSS_PATH = "bingo.tcss"
COMMANDS = App.COMMANDS | {AboutCommand}
AUTO_FOCUS = 'Input'
show_sidebar = reactive(False)
def action_toggle_sidebar(self) -> None:
print('sidebar toggle')
sidebar = self.query_one(Sidebar)
self.set_focus(None)
if sidebar.has_class("-hidden"):
sidebar.remove_class("-hidden")
sidebar.button.disabled = False
else:
if sidebar.query("*:focus"):
self.screen.set_focus(None)
sidebar.add_class("-hidden")
sidebar.button.disabled = True
def compose(self) -> ComposeResult:
'''Create child widgets for the app.'''
yield Sidebar(classes="-hidden")
yield Header(show_clock=True)
yield BingoDisplay()
def on_mount(self) -> None:
self.title = 'CCC Bingo'
self.sub_title = 'GPN22 Edition'
def action_toggle_dark(self) -> None:
'''An action to toggle dark mode.'''
self.dark = not self.dark
class BingoDisplay(Static):
def compose(self) -> ComposeResult:
'''Create child widgets for the app.'''
self.board = BingoBoard()
yield self.board
5 months ago
self.input_field = Input(
str(self.board.seed),
type='integer',
placeholder='UNIX timestamp',
max_length=10,
classes='seed_input',
validators=[
5 months ago
Number(minimum=1000000000, maximum = 2000000000)
]
)
5 months ago
self.input_field.border_title = 'Seed'
yield Horizontal(
5 months ago
self.input_field,
Button.error(':game_die: re-roll', classes='roll_btn'),
classes='bottom_line'
)
5 months ago
def on_button_pressed(self, event: Button.Pressed) -> None:
'''Re-roll the board state with current time as seed'''
5 months ago
self.board.roll_board(int(datetime.now().timestamp()))
self.input_field.value = str(self.board.seed)
def on_input_submitted(self, event: Input.Submitted) -> None:
'''Re-roll the board state with the seed from the input'''
if event.validation_result.is_valid:
self.board.roll_board(int(event.value))
if __name__ == "__main__":
app = BingoApp()
app.run()