Converted gather window to new TabRow class and killed old tabs functionality

This commit is contained in:
Eric Froemling 2020-10-20 15:13:58 -07:00
parent cc1ec205c0
commit 6bcd827ced
4 changed files with 80 additions and 120 deletions

View File

@ -6,6 +6,7 @@
- Ditto with AccountSubsystem and ba.app.accounts
- Ditto with MetadataSubsystem and ba.app.meta
- Ditto with AdsSubsystem and ba.app.ads
- Revamped tab-button functionality into a cleaner type-safe class (bastd.ui.tabs.TabRow)
### 1.5.26 (20217)
- Simplified licensing header on python scripts.

View File

@ -7,6 +7,7 @@ from __future__ import annotations
import threading
import time
from enum import Enum
from typing import TYPE_CHECKING, cast
import _ba
@ -19,6 +20,16 @@ if TYPE_CHECKING:
class GatherWindow(ba.Window):
"""Window for joining/inviting friends."""
class TabID(Enum):
"""Our available tab types."""
ABOUT = 'about'
INTERNET = 'internet'
GOOGLE_PLAY = 'google_play'
LOCAL_NETWORK = 'local_network'
BLUETOOTH = 'bluetooth'
WIFI_DIRECT = 'wifi_direct'
MANUAL = 'manual'
def __del__(self) -> None:
_ba.set_party_icon_always_visible(False)
@ -27,7 +38,7 @@ class GatherWindow(ba.Window):
origin_widget: ba.Widget = None):
# pylint: disable=too-many-statements
# pylint: disable=too-many-locals
from bastd.ui import tabs
from bastd.ui.tabs import TabRow
ba.set_analytics_screen('Gather Window')
scale_origin: Optional[Tuple[float, float]]
if origin_widget is not None:
@ -45,7 +56,7 @@ class GatherWindow(ba.Window):
x_offs = 100 if uiscale is ba.UIScale.SMALL else 0
self._height = (582 if uiscale is ba.UIScale.SMALL else
680 if uiscale is ba.UIScale.MEDIUM else 800)
self._current_tab: Optional[str] = None
self._current_tab: Optional[GatherWindow.TabID] = None
extra_top = 20 if uiscale is ba.UIScale.SMALL else 0
self._r = 'gatherWindow'
self._tab_data: Any = None
@ -130,35 +141,35 @@ class GatherWindow(ba.Window):
platform = ba.app.platform
subplatform = ba.app.subplatform
tabs_def: List[Tuple[str, ba.Lstr]] = [
('about', ba.Lstr(resource=self._r + '.aboutText'))
tabs_def: List[Tuple[GatherWindow.TabID, ba.Lstr]] = [
(self.TabID.ABOUT, ba.Lstr(resource=self._r + '.aboutText'))
]
if _ba.get_account_misc_read_val('enablePublicParties', True):
tabs_def.append(
('internet', ba.Lstr(resource=self._r + '.internetText')))
tabs_def.append((self.TabID.INTERNET,
ba.Lstr(resource=self._r + '.internetText')))
if platform == 'android' and subplatform == 'google':
tabs_def.append(
('google_play', ba.Lstr(resource=self._r + '.googlePlayText')))
tabs_def.append(
('local_network', ba.Lstr(resource=self._r + '.localNetworkText')))
tabs_def.append((self.TabID.GOOGLE_PLAY,
ba.Lstr(resource=self._r + '.googlePlayText')))
tabs_def.append((self.TabID.LOCAL_NETWORK,
ba.Lstr(resource=self._r + '.localNetworkText')))
tabs_def.append(('manual', ba.Lstr(resource=self._r + '.manualText')))
tabs_def.append(
(self.TabID.MANUAL, ba.Lstr(resource=self._r + '.manualText')))
scroll_buffer_h = 130 + 2 * x_offs
tab_buffer_h = 250 + 2 * x_offs
self._tab_buttons = tabs.create_tab_buttons(
self._root_widget,
tabs_def,
pos=(tab_buffer_h * 0.5, self._height - 130),
size=(self._width - tab_buffer_h, 50),
on_select_call=self._set_tab)
self._tab_row = TabRow(self._root_widget,
tabs_def,
pos=(tab_buffer_h * 0.5, self._height - 130),
size=(self._width - tab_buffer_h, 50),
on_select_call=self._set_tab)
if ba.app.ui.use_toolbars:
ba.widget(edit=self._tab_buttons[tabs_def[-1][0]],
ba.widget(edit=self._tab_row.tabs[tabs_def[-1][0]].button,
right_widget=_ba.get_special_widget('party_button'))
if uiscale is ba.UIScale.SMALL:
ba.widget(edit=self._tab_buttons[tabs_def[0][0]],
ba.widget(edit=self._tab_row.tabs[tabs_def[0][0]].button,
left_widget=_ba.get_special_widget('back_button'))
self._scroll_width = self._width - scroll_buffer_h
@ -222,21 +233,20 @@ class GatherWindow(ba.Window):
return
appinvite.handle_app_invites_press()
def _set_tab(self, tab: str) -> None:
def _set_tab(self, tab_id: TabID) -> None:
# pylint: disable=too-many-statements
# pylint: disable=too-many-locals
from bastd.ui import tabs
if self._current_tab == tab:
if self._current_tab is tab_id:
return
self._current_tab = tab
self._current_tab = tab_id
# We wanna preserve our current tab between runs.
cfg = ba.app.config
cfg['Gather Tab'] = tab
cfg['Gather Tab'] = tab_id.value
cfg.commit()
# Update tab colors based on which is selected.
tabs.update_tab_button_colors(self._tab_buttons, tab)
self._tab_row.update_appearance(tab_id)
# (Re)create scroll widget.
if self._tab_container:
@ -249,7 +259,7 @@ class GatherWindow(ba.Window):
self._tab_data = {}
# So we can still select root level widgets with direction buttons.
def _simple_message(tab2: str,
def _simple_message(tab2: GatherWindow.TabID,
message: ba.Lstr,
string_height: float,
include_invite: bool = False) -> None:
@ -268,7 +278,7 @@ class GatherWindow(ba.Window):
size=(c_width_2, c_height_2),
background=False,
selectable=include_invite)
ba.widget(edit=cnt2, up_widget=self._tab_buttons[tab2])
ba.widget(edit=cnt2, up_widget=self._tab_row.tabs[tab2].button)
ba.textwidget(
parent=cnt2,
@ -306,9 +316,9 @@ class GatherWindow(ba.Window):
'gatherWindow.getFriendInviteCodeText')),
autoselect=True,
on_activate_call=ba.WeakCall(self._invite_to_try_press),
up_widget=self._tab_buttons[tab2])
up_widget=self._tab_row.tabs[tab2].button)
if tab == 'about':
if tab_id is self.TabID.ABOUT:
msg = ba.Lstr(resource=self._r + '.aboutDescriptionText',
subs=[('${PARTY}',
ba.charstr(ba.SpecialChar.PARTY_ICON)),
@ -327,9 +337,9 @@ class GatherWindow(ba.Window):
'.aboutDescriptionLocalMultiplayerExtraText'))
])
_simple_message(tab, msg, 400, include_invite=True)
_simple_message(tab_id, msg, 400, include_invite=True)
elif tab == 'google_play':
elif tab_id is self.TabID.GOOGLE_PLAY:
c_width = self._scroll_width
c_height = 380.0
self._tab_container = cnt = ba.containerwidget(
@ -351,7 +361,7 @@ class GatherWindow(ba.Window):
v_align='center',
text=ba.Lstr(resource='googleMultiplayerDiscontinuedText'))
elif tab == 'internet':
elif tab_id is self.TabID.INTERNET:
c_width = self._scroll_width
c_height = self._scroll_height - 20
self._tab_container = cnt = ba.containerwidget(
@ -378,7 +388,7 @@ class GatherWindow(ba.Window):
'join', playsound=True),
text=ba.Lstr(resource=self._r +
'.joinPublicPartyDescriptionText'))
ba.widget(edit=txt, up_widget=self._tab_buttons[tab])
ba.widget(edit=txt, up_widget=self._tab_row.tabs[tab_id].button)
self._internet_host_text = txt = ba.textwidget(
parent=cnt,
position=(c_width * 0.5 + 45, v - 13),
@ -397,7 +407,7 @@ class GatherWindow(ba.Window):
'.hostPublicPartyDescriptionText'))
ba.widget(edit=txt,
left_widget=self._internet_join_text,
up_widget=self._tab_buttons[tab])
up_widget=self._tab_row.tabs[tab_id].button)
ba.widget(edit=self._internet_join_text, right_widget=txt)
# Attempt to fetch our local address so we have it for
@ -447,7 +457,7 @@ class GatherWindow(ba.Window):
# initial query.
self._update_internet_tab()
elif tab == 'local_network':
elif tab_id is self.TabID.LOCAL_NETWORK:
c_width = self._scroll_width
c_height = self._scroll_height - 20
sub_scroll_height = c_height - 85
@ -545,14 +555,14 @@ class GatherWindow(ba.Window):
size=(sub_scroll_width, sub_scroll_height))
self._tab_data = NetScanner(scrollw,
self._tab_buttons[tab],
self._tab_row.tabs[tab_id].button,
width=sub_scroll_width)
ba.widget(edit=scrollw,
autoselect=True,
up_widget=self._tab_buttons[tab])
up_widget=self._tab_row.tabs[tab_id].button)
elif tab == 'bluetooth':
elif tab_id is self.TabID.BLUETOOTH:
c_width = self._scroll_width
c_height = 380
sub_scroll_width = 650
@ -594,7 +604,7 @@ class GatherWindow(ba.Window):
size=(300, 70),
autoselect=True,
label=ba.Lstr(resource=self._r + '.bluetoothHostText'))
ba.widget(edit=btn, up_widget=self._tab_buttons[tab])
ba.widget(edit=btn, up_widget=self._tab_row.tabs[tab_id].button)
btn = ba.buttonwidget(
parent=cnt,
position=(c_width * 0.5 - sub_scroll_width * 0.5 + 330,
@ -604,10 +614,10 @@ class GatherWindow(ba.Window):
on_activate_call=ba.Call(ba.screenmessage,
'FIXME: Not wired up yet.'),
label=ba.Lstr(resource=self._r + '.bluetoothJoinText'))
ba.widget(edit=btn, up_widget=self._tab_buttons[tab])
ba.widget(edit=self._tab_buttons[tab], down_widget=btn)
ba.widget(edit=btn, up_widget=self._tab_row.tabs[tab_id].button)
ba.widget(edit=self._tab_row.tabs[tab_id].button, down_widget=btn)
elif tab == 'wifi_direct':
elif tab_id is self.TabID.WIFI_DIRECT:
c_width = self._scroll_width
c_height = self._scroll_height - 20
self._tab_container = cnt = ba.containerwidget(
@ -641,7 +651,7 @@ class GatherWindow(ba.Window):
on_activate_call=_ba.android_show_wifi_settings)
v -= 82
ba.widget(edit=btn, up_widget=self._tab_buttons[tab])
ba.widget(edit=btn, up_widget=self._tab_row.tabs[tab_id].button)
ba.textwidget(parent=cnt,
position=(c_width * 0.5, v),
@ -657,7 +667,7 @@ class GatherWindow(ba.Window):
subs=[('${APP_NAME}',
ba.Lstr(resource='titleText'))]))
elif tab == 'manual':
elif tab_id is self.TabID.MANUAL:
c_width = self._scroll_width
c_height = 380
last_addr = ba.app.config.get('Last Manual Party Connect Address',
@ -787,7 +797,7 @@ class GatherWindow(ba.Window):
position=(c_width * 0.5 - 150, v),
autoselect=True,
on_activate_call=ba.Call(_connect, txt, txt2))
ba.widget(edit=txt, up_widget=self._tab_buttons[tab])
ba.widget(edit=txt, up_widget=self._tab_row.tabs[tab_id].button)
ba.textwidget(edit=txt, on_return_press_call=btn.activate)
ba.textwidget(edit=txt2, on_return_press_call=btn.activate)
v -= 45
@ -1897,18 +1907,21 @@ class GatherWindow(ba.Window):
def _save_state(self) -> None:
try:
sel = self._root_widget.get_selected_child()
selected_tab_ids = [
tab_id for tab_id, tab in self._tab_row.tabs.items()
if sel == tab.button
]
if sel == self._back_button:
sel_name = 'Back'
elif sel in list(self._tab_buttons.values()):
sel_name = 'Tab:' + list(self._tab_buttons.keys())[list(
self._tab_buttons.values()).index(sel)]
elif selected_tab_ids:
assert len(selected_tab_ids) == 1
sel_name = f'Tab:{selected_tab_ids[0].value}'
elif sel == self._tab_container:
sel_name = 'TabContainer'
else:
raise ValueError(f'unrecognized selection: \'{sel}\'')
ba.app.ui.window_states[self.__class__.__name__] = {
'sel_name': sel_name,
'tab': self._current_tab,
'internet_tab': self._internet_tab
}
except Exception:
@ -1916,21 +1929,32 @@ class GatherWindow(ba.Window):
def _restore_state(self) -> None:
try:
sel: Optional[ba.Widget]
winstate = ba.app.ui.window_states.get(self.__class__.__name__, {})
sel_name = winstate.get('sel_name', None)
assert isinstance(sel_name, (str, type(None)))
self._internet_tab = winstate.get('internet_tab', 'join')
current_tab = ba.app.config.get('Gather Tab', None)
if current_tab is None or current_tab not in self._tab_buttons:
current_tab = 'about'
# current_tab = ba.app.config.get('Gather Tab', None)
current_tab = self.TabID.ABOUT
try:
stored_tab = self.TabID(ba.app.config.get('Gather Tab'))
if stored_tab in self._tab_row.tabs:
current_tab = stored_tab
except ValueError:
pass
self._set_tab(current_tab)
if sel_name == 'Back':
sel = self._back_button
elif sel_name == 'TabContainer':
sel = self._tab_container
elif isinstance(sel_name, str) and sel_name.startswith('Tab:'):
sel = self._tab_buttons[sel_name.split(':')[-1]]
try:
sel_tab_id = self.TabID(sel_name.split(':')[-1])
except ValueError:
sel_tab_id = self.TabID.ABOUT
sel = self._tab_row.tabs[sel_tab_id].button
else:
sel = self._tab_buttons[current_tab]
sel = self._tab_row.tabs[current_tab].button
ba.containerwidget(edit=self._root_widget, selected_child=sel)
except Exception:
ba.print_exception(f'Error restoring state for {self}.')

View File

@ -75,69 +75,3 @@ class TabRow(Generic[T]):
ba.playsound(ba.getsound('click01'))
if call is not None:
call(arg)
def create_tab_buttons(parent_widget: ba.Widget,
tabs: List[Tuple[str, ba.Lstr]],
pos: Sequence[float],
size: Sequence[float],
on_select_call: Callable[[Any], Any] = None,
return_extra_info: bool = False) -> Dict[str, Any]:
"""(internal)"""
# pylint: disable=too-many-locals
tab_pos_v = pos[1]
tab_buttons = {}
tab_buttons_indexed = []
tab_button_width = float(size[0]) / len(tabs)
# Add a bit more visual spacing as our buttons get narrower.
tab_spacing = (250.0 - tab_button_width) * 0.06
positions = []
sizes = []
h = pos[0]
for _i, tab in enumerate(tabs):
def _tick_and_call(call: Optional[Callable[[Any], Any]],
arg: Any) -> None:
ba.playsound(ba.getsound('click01'))
if call is not None:
call(arg)
pos = (h + tab_spacing * 0.5, tab_pos_v)
size = (tab_button_width - tab_spacing, 50.0)
positions.append(pos)
sizes.append(size)
btn = ba.buttonwidget(parent=parent_widget,
position=pos,
autoselect=True,
button_type='tab',
size=size,
label=tab[1],
enable_sound=False,
on_activate_call=ba.Call(_tick_and_call,
on_select_call, tab[0]))
h += tab_button_width
tab_buttons[tab[0]] = btn
tab_buttons_indexed.append(btn)
if return_extra_info:
return {
'buttons': tab_buttons,
'buttons_indexed': tab_buttons_indexed,
'positions': positions,
'sizes': sizes
}
return tab_buttons
def update_tab_button_colors(tabs: Dict[str, ba.Widget],
selected_tab: str) -> None:
"""(internal)"""
for t_id, tbutton in list(tabs.items()):
if t_id == selected_tab:
ba.buttonwidget(edit=tbutton,
color=(0.5, 0.4, 0.93),
textcolor=(0.85, 0.75, 0.95)) # lit
else:
ba.buttonwidget(edit=tbutton,
color=(0.52, 0.48, 0.63),
textcolor=(0.65, 0.6, 0.7)) # unlit

View File

@ -504,6 +504,7 @@ class WatchWindow(ba.Window):
def _restore_state(self) -> None:
try:
sel: Optional[ba.Widget]
sel_name = ba.app.ui.window_states.get(self.__class__.__name__,
{}).get('sel_name')
assert isinstance(sel_name, (str, type(None)))