#!/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()