wip
This commit is contained in:
parent
a6f36ca6f9
commit
c9f7d54e07
13 changed files with 1803 additions and 42 deletions
|
|
@ -1,18 +1,341 @@
|
|||
Screen {
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#create {
|
||||
align: center middle;
|
||||
layers: main footer;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#create #create-label {
|
||||
align: center middle;
|
||||
text-align: center;
|
||||
border-title-align: center;
|
||||
padding: 1 2;
|
||||
color: $text;
|
||||
border: round gray 90%;
|
||||
}
|
||||
|
||||
DebugInfo {
|
||||
min-height: 10;
|
||||
}
|
||||
|
||||
Sidebar {
|
||||
height: 100vh;
|
||||
width: auto;
|
||||
min-width: 20;
|
||||
background: $secondary-background-darken-2;
|
||||
dock: left;
|
||||
margin-right: 1;
|
||||
layer: main;
|
||||
background: $panel;
|
||||
width: 35;
|
||||
height: 100%;
|
||||
border-right: vkey $background;
|
||||
}
|
||||
|
||||
Footer {
|
||||
layer: footer;
|
||||
Sidebar Button {
|
||||
width: 1fr;
|
||||
}
|
||||
|
||||
Sidebar Button#settings {
|
||||
dock: bottom;
|
||||
}
|
||||
|
||||
Sidebar #meta-buttons-container {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
Sidebar #quit {
|
||||
background: $error 25%;
|
||||
}
|
||||
|
||||
Sidebar #quit:hover {
|
||||
background: $error 50%;
|
||||
}
|
||||
|
||||
Sidebar TabbedContent {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
Sidebar TabPane {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
Sidebar TabbedContent ContentSwitcher {
|
||||
height: 1fr;
|
||||
}
|
||||
|
||||
Sidebar OptionList {
|
||||
height: 1fr;
|
||||
}
|
||||
|
||||
Hud #hud {
|
||||
height: 3;
|
||||
width: 100%;
|
||||
background: $surface;
|
||||
background: blue;
|
||||
layout: horizontal;
|
||||
}
|
||||
|
||||
Hud #character {
|
||||
background: red;
|
||||
}
|
||||
|
||||
Hud #ship {
|
||||
background: gold;
|
||||
}
|
||||
|
||||
Conversation {
|
||||
height: 90%;
|
||||
width: 100%;
|
||||
background: $panel;
|
||||
}
|
||||
|
||||
Conversation Input {
|
||||
dock: bottom;
|
||||
}
|
||||
|
||||
Response {
|
||||
height: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
Response.response-hover {
|
||||
background: $boost;
|
||||
}
|
||||
|
||||
Response.show-edit-buttons {
|
||||
border: round $warning 50%;
|
||||
border-title-align: center;
|
||||
background: $boost;
|
||||
padding: 2 4;
|
||||
margin: 1 3;
|
||||
}
|
||||
|
||||
ResponseBody {
|
||||
height: auto;
|
||||
border: round gray 90%;
|
||||
padding: 1 2 0 2;
|
||||
margin: 1 3;
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
Response Horizontal {
|
||||
height: auto;
|
||||
width: 100%;
|
||||
align: center middle;
|
||||
}
|
||||
|
||||
Response Button {
|
||||
margin: 0 2;
|
||||
}
|
||||
|
||||
ResponseBody.show-edit-buttons {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
UserResponse {
|
||||
align-horizontal: right;
|
||||
}
|
||||
|
||||
UserResponse ResponseBody {
|
||||
background: lightslategray 10%;
|
||||
}
|
||||
|
||||
BotResponse ResponseBody {
|
||||
border: skyblue 50%;
|
||||
background: $primary 30%;
|
||||
}
|
||||
|
||||
ModalScreen {
|
||||
align: center middle;
|
||||
}
|
||||
|
||||
SettingsDialogue,
|
||||
BotsDialogue,
|
||||
DatabaseUpgradeDialogue,
|
||||
ConfirmMessageDeleteDialogue {
|
||||
background: $panel;
|
||||
margin: 1 2;
|
||||
padding: 2 4;
|
||||
width: 70%;
|
||||
min-width: 60;
|
||||
height: auto;
|
||||
border: thick $primary 80%;
|
||||
}
|
||||
|
||||
SettingsDialogue TabbedContent {
|
||||
margin: 4;
|
||||
padding: 2;
|
||||
}
|
||||
|
||||
SettingsDialogue TabPane {
|
||||
height: 10;
|
||||
}
|
||||
|
||||
DatabaseUpgradeDialogue {
|
||||
border: thick red 50%;
|
||||
padding: 2 4;
|
||||
}
|
||||
|
||||
DatabaseUpgradeDialogue Label {
|
||||
/* color: darkorange; */
|
||||
width: 100%;
|
||||
margin: 2 0;
|
||||
}
|
||||
ConfirmMessageDeleteDialogue {
|
||||
width: auto;
|
||||
}
|
||||
ConfirmMessageDeleteDialogue Horizontal {
|
||||
height: auto;
|
||||
width: 100%;
|
||||
align: center middle;
|
||||
margin: 2 0 0 0;
|
||||
}
|
||||
ConfirmMessageDeleteDialogue .confirm-delete-message {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
ConfirmMessageDeleteDialogue Button {
|
||||
margin: 0 2;
|
||||
}
|
||||
|
||||
#message-top {
|
||||
align: center middle;
|
||||
}
|
||||
|
||||
#empty-thread-container {
|
||||
align: center middle;
|
||||
min-width: 50%;
|
||||
width: auto;
|
||||
padding: 4 10;
|
||||
border: round $secondary;
|
||||
height: auto;
|
||||
/* background: $boost; */
|
||||
color: $text;
|
||||
border-title-align: center;
|
||||
}
|
||||
#empty-thread-bot-name {
|
||||
width: auto;
|
||||
}
|
||||
#empty-thread-bot-description {
|
||||
border-left: solid $secondary 60%;
|
||||
padding-left: 1;
|
||||
margin-top: 1;
|
||||
height: auto;
|
||||
text-style: italic;
|
||||
max-width: 100%;
|
||||
/* width: 100%; */
|
||||
}
|
||||
|
||||
#bot-name-container {
|
||||
align: center middle;
|
||||
height: 4;
|
||||
border-bottom: solid $secondary;
|
||||
}
|
||||
|
||||
#bot-name {
|
||||
color: $success;
|
||||
|
||||
text-style: bold;
|
||||
}
|
||||
|
||||
.sidebar-title {
|
||||
height: 3;
|
||||
text-align: center;
|
||||
/* text-style: bold; */
|
||||
width: 100%;
|
||||
padding-top: 1;
|
||||
}
|
||||
|
||||
.settings-container {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
border: round white 40%;
|
||||
margin: 2 1;
|
||||
padding: 1 2;
|
||||
}
|
||||
|
||||
SettingsDialogue .api-key-info {
|
||||
width: 100%;
|
||||
margin: 2 1 0 1;
|
||||
}
|
||||
|
||||
SettingsDialogue .error {
|
||||
color: red;
|
||||
}
|
||||
|
||||
BotsDialogue {
|
||||
width: 80%;
|
||||
height: 70%;
|
||||
}
|
||||
|
||||
BotsDialogue Horizontal {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
BotsDialogue Button {
|
||||
margin-right: 2;
|
||||
}
|
||||
|
||||
BotsDialogue #install-default-bots {
|
||||
padding: 0 2;
|
||||
}
|
||||
|
||||
BotsOptionList {
|
||||
border: solid white 50%;
|
||||
background: $boost;
|
||||
margin: 1 2;
|
||||
}
|
||||
|
||||
BotInfo {
|
||||
border: solid white 50%;
|
||||
column-span: 2;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
BotInfo TextTable {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: auto auto;
|
||||
padding: 1 2 1 2;
|
||||
}
|
||||
|
||||
BotInfo TextTable .label {
|
||||
padding-right: 1;
|
||||
color: gray;
|
||||
}
|
||||
|
||||
#bots-info-container {
|
||||
layout: grid;
|
||||
grid-size: 3;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
BotsList {
|
||||
margin: 1 2;
|
||||
}
|
||||
BotInfo {
|
||||
margin: 1 2;
|
||||
background: $boost;
|
||||
border: solid $secondary;
|
||||
}
|
||||
|
||||
#bot-info-outer-container {
|
||||
margin: 2 3 2 3;
|
||||
}
|
||||
BotInfo .bot-info-container {
|
||||
margin-bottom: 2;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
BotInfo .label {
|
||||
text-style: bold;
|
||||
}
|
||||
|
||||
BotInfo .text {
|
||||
border-left: solid $secondary 60%;
|
||||
padding-left: 1;
|
||||
margin-top: 1;
|
||||
/* height: auto; */
|
||||
text-style: italic;
|
||||
max-width: 100%;
|
||||
width: auto;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,44 +1,389 @@
|
|||
from pathlib import Path
|
||||
import logging
|
||||
import time
|
||||
from typing import Optional
|
||||
|
||||
import marvin
|
||||
import pendulum
|
||||
import pyperclip
|
||||
from textual.app import App, ComposeResult
|
||||
from textual.containers import Container
|
||||
from textual.css.query import NoMatches
|
||||
from textual.widgets import Footer, Static
|
||||
from textual.containers import Container, Horizontal, VerticalScroll
|
||||
from textual.events import Enter, Leave
|
||||
from textual.logging import TextualHandler
|
||||
from textual.message import Message
|
||||
from textual.reactive import reactive
|
||||
from textual.screen import ModalScreen, Screen
|
||||
from textual.widgets import Button, Input, Label, Markdown
|
||||
|
||||
from marvin_sw_text_adventure.config import config
|
||||
from marvin_sw_text_adventure.console import console
|
||||
from marvin_sw_text_adventure.game import (
|
||||
Game,
|
||||
StarWarsCharacter,
|
||||
create_game,
|
||||
did_complete_mission,
|
||||
get_next_mission,
|
||||
)
|
||||
|
||||
config["tui"] = {}
|
||||
config["tui"]["bindings"] = {}
|
||||
logging.basicConfig(
|
||||
level="NOTSET",
|
||||
handlers=[TextualHandler()],
|
||||
)
|
||||
|
||||
|
||||
class Sidebar(Static):
|
||||
class ResponseHover(Message):
|
||||
pass
|
||||
|
||||
|
||||
class ResponseBody(Markdown):
|
||||
text: str = ""
|
||||
|
||||
def update(self, markdown: str):
|
||||
self.text = markdown
|
||||
super().update(markdown)
|
||||
|
||||
def on_enter(self):
|
||||
self.post_message(ResponseHover())
|
||||
|
||||
|
||||
class Response(Container):
|
||||
body = None
|
||||
stream_finished: bool = False
|
||||
|
||||
def __init__(self, message: marvin.models.threads.Message, **kwargs) -> None:
|
||||
classes = kwargs.setdefault("classes", "")
|
||||
kwargs["classes"] = f"{classes} response".strip()
|
||||
self.message = message
|
||||
super().__init__(**kwargs)
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Container(
|
||||
Static("sidebar"),
|
||||
id="sidebar",
|
||||
self.body = ResponseBody(self.message.content, classes="response-body markdown")
|
||||
self.body.border_title = (
|
||||
"You" if self.message.role == "user" else self.message.name
|
||||
)
|
||||
self.body.border_subtitle = (
|
||||
pendulum.instance(self.message.timestamp).in_tz("local").format("h:mm:ss A")
|
||||
)
|
||||
self.border_title = "Edit message"
|
||||
|
||||
yield self.body
|
||||
with Horizontal(classes="edit-buttons-container hidden"):
|
||||
yield Button("Copy", variant="default", id="copy-message")
|
||||
yield Button("Delete", variant="error", id="delete-message")
|
||||
|
||||
def on_click(self):
|
||||
self.action_toggle_buttons()
|
||||
|
||||
def on_response_hover(self, event: ResponseHover):
|
||||
"""
|
||||
This is an "enter" event bubbled up from the ResponseBody, since the
|
||||
default "Leave" is triggered when hovering on child widgets. This keeps
|
||||
the hover class even when hovering on the child widget.
|
||||
"""
|
||||
self.add_class("response-hover")
|
||||
|
||||
def on_enter(self, event: Enter):
|
||||
self.add_class("response-hover")
|
||||
|
||||
def on_leave(self, event: Leave):
|
||||
self.remove_class("response-hover")
|
||||
|
||||
def action_toggle_buttons(self):
|
||||
self.toggle_class("show-edit-buttons")
|
||||
self.body.toggle_class("show-edit-buttons")
|
||||
self.query_one(".edit-buttons-container").toggle_class("hidden")
|
||||
|
||||
def on_button_pressed(self, event: Button.Pressed):
|
||||
if event.button.id == "copy-message":
|
||||
pyperclip.copy(self.message.content)
|
||||
self.action_toggle_buttons()
|
||||
|
||||
elif event.button.id == "delete-message":
|
||||
self.app.push_screen(ConfirmMessageDeleteScreen(self.message.id))
|
||||
|
||||
|
||||
class UserResponse(Response):
|
||||
def __init__(self, message: marvin.models.threads.Message, **kwargs) -> None:
|
||||
classes = kwargs.setdefault("classes", "")
|
||||
kwargs["classes"] = f"{classes} user-response".strip()
|
||||
super().__init__(message=message, **kwargs)
|
||||
|
||||
|
||||
class BotResponse(Response):
|
||||
def __init__(self, message: marvin.models.threads.Message, **kwargs) -> None:
|
||||
classes = kwargs.setdefault("classes", "")
|
||||
kwargs["classes"] = f"{classes} bot-response".strip()
|
||||
super().__init__(message=message, **kwargs)
|
||||
|
||||
|
||||
class Hud(Container):
|
||||
...
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
with VerticalScroll(id="hud"):
|
||||
with Container(id="character"):
|
||||
yield Label("character name", id="character-name")
|
||||
yield Label("character health", id="character-health")
|
||||
yield Label("imperial credits", id="imperial-credits")
|
||||
with Container(id="ship"):
|
||||
yield Label("ship name", id="ship-name")
|
||||
yield Label("ship health", id="ship-health")
|
||||
yield Label("ship fuel", id="ship-fuel")
|
||||
|
||||
|
||||
class Conversation(Container):
|
||||
# bot_name = reactive(None, layout=True)
|
||||
|
||||
# def watch_bot_name(self, bot_name: str):
|
||||
# with self.app.batch_update():
|
||||
# bot_name_label = self.query_one("#empty-thread-bot-name", Label)
|
||||
# bot_description_label = self.query_one(
|
||||
# "#empty-thread-bot-description", Label
|
||||
# )
|
||||
|
||||
# if bot_name:
|
||||
# bot_name_label.update(
|
||||
# f"Send a message to [bold green]{self.bot_name}[/]!"
|
||||
# )
|
||||
# if self.app.bot.description:
|
||||
# bot_description_label.update(f"{self.app.bot.description}")
|
||||
# bot_description_label.remove_class("hidden")
|
||||
# else:
|
||||
# bot_description_label.add_class("hidden")
|
||||
|
||||
# else:
|
||||
# bot_description_label.add_class("hidden")
|
||||
# bot_name_label.update("Send a message to start a thread...")
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
input = Input(placeholder="What do you do ❯", id="message-input")
|
||||
input.focus()
|
||||
yield input
|
||||
with VerticalScroll(id="messages"):
|
||||
with Container(id="message-top"):
|
||||
with Container(id="empty-thread-container"):
|
||||
yield Label("", id="empty-thread-bot-name")
|
||||
yield Label("", id="empty-thread-bot-description")
|
||||
|
||||
async def add_response(self, response: Response, scroll: bool = True) -> None:
|
||||
messages = self.app.query_one("Conversation #messages", VerticalScroll)
|
||||
# wait for the responses to be fully mounted before scrolling
|
||||
# to avoid issues with rendering Markdown
|
||||
await messages.mount(response)
|
||||
if scroll:
|
||||
messages.scroll_end(duration=0.2)
|
||||
|
||||
# show / hide the empty thread message
|
||||
empty = self.app.query_one("Conversation #empty-thread-container")
|
||||
empty.add_class("hidden")
|
||||
|
||||
def clear_responses(self) -> None:
|
||||
responses = self.app.query("Response")
|
||||
for response in responses:
|
||||
response.remove()
|
||||
# self.bot_name = getattr(self.app.bot, "name")
|
||||
empty = self.query_one("Conversation #empty-thread-container")
|
||||
empty.remove_class("hidden")
|
||||
|
||||
|
||||
class CreateScreen(ModalScreen):
|
||||
def __init__(self, message: str, **kwargs) -> None:
|
||||
self.message = message
|
||||
super().__init__(**kwargs)
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
with Container(id="create"):
|
||||
yield Label(self.message, id="create-label")
|
||||
|
||||
|
||||
class MainScreen(Screen):
|
||||
BINDINGS = [
|
||||
("escape", "focus_threads", "Focus on Threads"),
|
||||
("n", "new_thread", "New Thread"),
|
||||
("k", "scroll_up_messages", "Scroll Up"),
|
||||
("j", "scroll_down_messages", "Scroll Down"),
|
||||
("u", "page_up_messages", "Page Up"),
|
||||
("d", "page_down_messages", "Page Down"),
|
||||
]
|
||||
action: Optional[str] = reactive(None, always_update=True, layout=True)
|
||||
|
||||
def action_focus_threads(self) -> None:
|
||||
self.app.query_one("#threads", Threads).focus()
|
||||
|
||||
def action_focus_message(self) -> None:
|
||||
self.app.query_one("#message-input", Input).focus()
|
||||
|
||||
def action_scroll_up_messages(self) -> None:
|
||||
messages = self.query_one("Conversation #messages", VerticalScroll)
|
||||
messages.scroll_up(duration=0.1)
|
||||
|
||||
def action_scroll_down_messages(self) -> None:
|
||||
messages = self.query_one("Conversation #messages", VerticalScroll)
|
||||
messages.scroll_down(duration=0.1)
|
||||
|
||||
def action_page_up_messages(self) -> None:
|
||||
messages = self.query_one("Conversation #messages", VerticalScroll)
|
||||
messages.scroll_page_up(duration=0.1)
|
||||
|
||||
def action_page_down_messages(self) -> None:
|
||||
messages = self.query_one("Conversation #messages", VerticalScroll)
|
||||
messages.scroll_page_down(duration=0.1)
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
# yield Sidebar(id="sidebar")
|
||||
yield Hud(id="hud")
|
||||
yield Conversation(id="conversation")
|
||||
|
||||
async def on_mount(self):
|
||||
if not marvin.settings.openai_api_key.get_secret_value():
|
||||
self.set_timer(0.5, self.action_show_settings_screen)
|
||||
conversation = self.query_one("Conversation", Conversation)
|
||||
|
||||
await conversation.add_response(
|
||||
BotResponse(
|
||||
marvin.models.threads.Message(
|
||||
role="bot",
|
||||
name="sw-text-adventure",
|
||||
bot_id=123,
|
||||
content=f"{self.app.character.name} from {self.app.character.home_planet} - {self.app.character.backstory}",
|
||||
)
|
||||
)
|
||||
)
|
||||
await conversation.add_response(
|
||||
BotResponse(
|
||||
marvin.models.threads.Message(
|
||||
role="bot",
|
||||
name="sw-text-adventure",
|
||||
bot_id=123,
|
||||
content=f"Mission: {self.app.character.mission.description}",
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
async def on_input_submitted(self, event: Input.Submitted) -> None:
|
||||
if event.input.disabled:
|
||||
return
|
||||
elif not event.input.value:
|
||||
return
|
||||
action = event.input.value
|
||||
event.input.value = ""
|
||||
conversation = self.query_one("Conversation", Conversation)
|
||||
await conversation.add_response(
|
||||
UserResponse(
|
||||
marvin.models.threads.Message(name="User", role="user", content=action)
|
||||
)
|
||||
)
|
||||
self.action = action
|
||||
|
||||
class Tui(App):
|
||||
"""A Textual app to manage requests."""
|
||||
async def watch_action(self, action: str) -> None:
|
||||
if action is None:
|
||||
return
|
||||
conversation = self.query_one("Conversation", Conversation)
|
||||
|
||||
CSS_PATH = Path("__file__").parent / "app.css"
|
||||
BINDINGS = [tuple(b.values()) for b in config["tui"]["bindings"]]
|
||||
result = did_complete_mission(self.app.character, action)
|
||||
self.app.character.previous_missions.append(
|
||||
(self.app.character.mission, result)
|
||||
)
|
||||
self.app.character.previous_missions = self.app.character.previous_missions[-5:]
|
||||
self.app.character.imperial_credits -= result.imperial_credits_spent
|
||||
self.app.character.imperial_credits += result.imperial_credits_earned
|
||||
self.app.character.health -= result.health_lost
|
||||
self.app.character.health += result.health_gained
|
||||
self.app.character.ship.fuel_level -= result.fuel_used
|
||||
message = ""
|
||||
message += f"Your mission has been completed"
|
||||
message += result.story
|
||||
message += f"You earned {result.imperial_credits_earned} imperial credits"
|
||||
message += f"You spent {result.imperial_credits_spent} imperial credits"
|
||||
message += f"You gained {result.health_gained} health"
|
||||
message += f"You lost {result.health_lost} health"
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
"""Create child widgets for the app."""
|
||||
yield Container(Static("hello world"))
|
||||
yield Footer()
|
||||
await conversation.add_response(
|
||||
BotResponse(
|
||||
marvin.models.threads.Message(
|
||||
role="bot",
|
||||
name="sw-text-adventure",
|
||||
bot_id=123,
|
||||
content=result.story,
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
def action_toggle_dark(self) -> None:
|
||||
"""An action to toggle dark mode."""
|
||||
self.dark = not self.dark
|
||||
await conversation.add_response(
|
||||
BotResponse(
|
||||
marvin.models.threads.Message(
|
||||
role="bot",
|
||||
name="sw-text-adventure",
|
||||
bot_id=123,
|
||||
content=f"You earned {result.imperial_credits_earned} imperial credits, spent {result.imperial_credits_spent} imperial credits, gained {result.health_gained} hp, and lost {result.health_lost} hp.",
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
def action_toggle_sidebar(self):
|
||||
try:
|
||||
self.query_one("PromptSidebar").remove()
|
||||
except NoMatches:
|
||||
self.mount(Sidebar())
|
||||
self.app.character.mission = get_next_mission(
|
||||
self.app.character, action, result.success
|
||||
)
|
||||
|
||||
await conversation.add_response(
|
||||
BotResponse(
|
||||
marvin.models.threads.Message(
|
||||
role="bot",
|
||||
name="sw-text-adventure",
|
||||
bot_id=123,
|
||||
content=f"Next Mission: {self.app.character.mission.description} imperial credits, spent {result.imperial_credits_spent} imperial credits, gained {result.health_gained} hp, and lost {result.health_lost}",
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
async def on_button_pressed(self, event: Button.Pressed) -> None:
|
||||
if event.button.id == "show-settings":
|
||||
self.action_show_settings_screen()
|
||||
elif event.button.id == "show-bots":
|
||||
self.action_show_bots_screen()
|
||||
elif event.button.id == "create-new-thread":
|
||||
self.action_new_thread()
|
||||
elif event.button.id == "delete-thread":
|
||||
await self.action_delete_thread()
|
||||
elif event.button.id == "quit":
|
||||
self.app.exit()
|
||||
|
||||
|
||||
class SWTextAdventure(App):
|
||||
CSS_PATH = ["app.css"]
|
||||
character: Optional[StarWarsCharacter] = reactive(
|
||||
None, always_update=True, layout=True
|
||||
)
|
||||
game_type: Optional[str] = reactive(None, always_update=True, layout=True)
|
||||
game: Optional[Game] = reactive(None, always_update=True, layout=True)
|
||||
game_ready: bool = reactive(False)
|
||||
is_ready: bool = False
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.game_type = "star-wars"
|
||||
|
||||
async def on_ready(self) -> None:
|
||||
self.push_screen(MainScreen())
|
||||
|
||||
async def watch_game_type(self) -> None:
|
||||
self.push_screen(CreateScreen(message="starting"))
|
||||
time.sleep(1)
|
||||
if self.character is None:
|
||||
self.push_screen(CreateScreen(message="creating character"))
|
||||
self.character = StarWarsCharacter.parse_file("character.json")
|
||||
# self.character=create_character()
|
||||
if self.game is None:
|
||||
self.push_screen(
|
||||
CreateScreen(message=f"creating game for {self.character.name}")
|
||||
)
|
||||
self.game = create_game # (self.character)
|
||||
# self.pop_screen()
|
||||
self.game_ready = True
|
||||
self.is_ready = True
|
||||
|
||||
async def watch_action(self) -> None:
|
||||
...
|
||||
|
||||
async def watch_game_ready(self, game_ready: bool) -> None:
|
||||
console.log(f"Game ready: {game_ready}")
|
||||
|
||||
|
||||
def run_app():
|
||||
|
|
@ -54,7 +399,7 @@ def run_app():
|
|||
features.add("devtools")
|
||||
|
||||
os.environ["TEXTUAL"] = ",".join(sorted(features))
|
||||
app = Tui()
|
||||
app = SWTextAdventure()
|
||||
app.run()
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue