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

124 lines
4.1 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.command import 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.')
#yield Hit(1, 'About', 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
self.input_field = Input(
str(self.board.seed),
type='integer',
placeholder='UNIX timestamp',
max_length=10,
classes='seed_input',
validators=[
Number(minimum=1000000000, maximum = 2000000000)
]
)
self.input_field.border_title = 'Seed'
yield Horizontal(
self.input_field,
Button.error(':game_die: re-roll', classes='roll_btn'),
classes='bottom_line'
)
def on_button_pressed(self, event: Button.Pressed) -> None:
'''Re-roll the board state with current time as seed'''
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()