# Released under the MIT License. See LICENSE for details.
#
"""Dialog window controlled by the master server."""
from __future__ import annotations
import logging
from dataclasses import dataclass, field
from typing import Annotated
from efro.dataclassio import ioprepped, IOAttrs
import bauiv1 as bui
[docs]
@ioprepped
@dataclass
class ServerDialogData:
"""Data for ServerDialog."""
dialog_id: str
text: str
subs: list[tuple[str, str]] = field(
default_factory=list
)
show_cancel: bool = True
copy_text: str | None = None
[docs]
class ServerDialogWindow(bui.Window):
"""A dialog window driven by the master-server."""
def __init__(self, data: ServerDialogData):
self._data = data
txt = bui.Lstr(
translate=('serverResponses', data.text), subs=data.subs
).evaluate()
txt = txt.strip()
txt_scale = 1.5
txt_height = (
bui.get_string_height(txt, suppress_warning=True) * txt_scale
)
self._width = 500
self._height = 160 + min(200, txt_height)
assert bui.app.classic is not None
uiscale = bui.app.ui_v1.uiscale
super().__init__(
root_widget=bui.containerwidget(
size=(self._width, self._height),
transition='in_scale',
scale=(
1.8
if uiscale is bui.UIScale.SMALL
else 1.35 if uiscale is bui.UIScale.MEDIUM else 1.0
),
)
)
self._starttime = bui.apptime()
bui.getsound('swish').play()
bui.textwidget(
parent=self._root_widget,
position=(self._width * 0.5, 70 + (self._height - 70) * 0.5),
size=(0, 0),
color=(1.0, 3.0, 1.0),
scale=txt_scale,
h_align='center',
v_align='center',
text=txt,
maxwidth=self._width * 0.85,
max_height=(self._height - 110),
)
show_copy = data.copy_text is not None and bui.clipboard_is_supported()
# Currently can't do both copy and cancel since they go in the same
# spot. Cancel wins in this case since it is important functionality
# and copy is just for convenience (and not even always available).
if show_copy and data.show_cancel:
logging.warning(
'serverdialog requesting both copy and cancel;'
' copy will not be shown.'
)
show_copy = False
self._cancel_button = (
None
if not data.show_cancel
else bui.buttonwidget(
parent=self._root_widget,
position=(30, 30),
size=(160, 60),
autoselect=True,
label=bui.Lstr(resource='cancelText'),
on_activate_call=self._cancel_press,
)
)
self._copy_button = (
None
if not show_copy
else bui.buttonwidget(
parent=self._root_widget,
position=(30, 30),
size=(160, 60),
autoselect=True,
label=bui.Lstr(resource='copyText'),
on_activate_call=self._copy_press,
)
)
self._ok_button = bui.buttonwidget(
parent=self._root_widget,
position=(
(
(self._width - 182)
if (data.show_cancel or show_copy)
else (self._width * 0.5 - 80)
),
30,
),
size=(160, 60),
autoselect=True,
label=bui.Lstr(resource='okText'),
on_activate_call=self._ok_press,
)
bui.containerwidget(
edit=self._root_widget,
cancel_button=self._cancel_button,
start_button=self._ok_button,
selected_child=self._ok_button,
)
def _copy_press(self) -> None:
assert self._data.copy_text is not None
bui.clipboard_set_text(self._data.copy_text)
bui.screenmessage(bui.Lstr(resource='copyConfirmText'), color=(0, 1, 0))
def _ok_press(self) -> None:
plus = bui.app.plus
assert plus is not None
if bui.apptime() - self._starttime < 1.0:
bui.getsound('error').play()
return
plus.add_v1_account_transaction(
{
'type': 'DIALOG_RESPONSE',
'dialogID': self._data.dialog_id,
'response': 1,
}
)
bui.containerwidget(edit=self._root_widget, transition='out_scale')
def _cancel_press(self) -> None:
plus = bui.app.plus
assert plus is not None
if bui.apptime() - self._starttime < 1.0:
bui.getsound('error').play()
return
plus.add_v1_account_transaction(
{
'type': 'DIALOG_RESPONSE',
'dialogID': self._data.dialog_id,
'response': 0,
}
)
bui.containerwidget(edit=self._root_widget, transition='out_scale')
# Docs-generation hack; import some stuff that we likely only forward-declared
# in our actual source code so that docs tools can find it.
from typing import (Coroutine, Any, Literal, Callable,
Generator, Awaitable, Sequence, Self)
import asyncio
from concurrent.futures import Future
from pathlib import Path
from enum import Enum