bauiv1lib.chest
Provides chest related ui.
1# Released under the MIT License. See LICENSE for details. 2# 3"""Provides chest related ui.""" 4 5from __future__ import annotations 6 7from typing import override, TYPE_CHECKING 8 9import bacommon.cloud 10import bauiv1 as bui 11 12if TYPE_CHECKING: 13 pass 14 15 16class ChestWindow(bui.MainWindow): 17 """Allows operations on a chest.""" 18 19 # def __del__(self) -> None: 20 # print('~ChestWindow()') 21 22 def __init__( 23 self, 24 index: int, 25 transition: str | None = 'in_right', 26 origin_widget: bui.Widget | None = None, 27 ): 28 # print('ChestWindow()') 29 30 self._index = index 31 32 assert bui.app.classic is not None 33 uiscale = bui.app.ui_v1.uiscale 34 self._width = 1050 if uiscale is bui.UIScale.SMALL else 850 35 self._height = ( 36 500 37 if uiscale is bui.UIScale.SMALL 38 else 500 if uiscale is bui.UIScale.MEDIUM else 500 39 ) 40 self._xoffs = 70 if uiscale is bui.UIScale.SMALL else 0 41 self._yoffs = -42 if uiscale is bui.UIScale.SMALL else -25 42 self._action_in_flight = False 43 self._open_now_button: bui.Widget | None = None 44 self._watch_ad_button: bui.Widget | None = None 45 46 # The set of widgets we keep when doing a clear. 47 self._core_widgets: list[bui.Widget] = [] 48 49 super().__init__( 50 root_widget=bui.containerwidget( 51 size=(self._width, self._height), 52 toolbar_visibility='menu_full', 53 scale=( 54 1.55 55 if uiscale is bui.UIScale.SMALL 56 else 1.1 if uiscale is bui.UIScale.MEDIUM else 0.9 57 ), 58 stack_offset=( 59 (0, 0) 60 if uiscale is bui.UIScale.SMALL 61 else (0, 15) if uiscale is bui.UIScale.MEDIUM else (0, 0) 62 ), 63 ), 64 transition=transition, 65 origin_widget=origin_widget, 66 ) 67 68 self._title_text = bui.textwidget( 69 parent=self._root_widget, 70 position=(0, self._height - 45 + self._yoffs), 71 size=(self._width, 25), 72 text=f'Chest Slot {self._index + 1}', 73 color=bui.app.ui_v1.title_color, 74 maxwidth=150.0, 75 h_align='center', 76 v_align='center', 77 ) 78 self._core_widgets.append(self._title_text) 79 80 if uiscale is bui.UIScale.SMALL: 81 bui.containerwidget( 82 edit=self._root_widget, on_cancel_call=self.main_window_back 83 ) 84 else: 85 btn = bui.buttonwidget( 86 parent=self._root_widget, 87 position=(self._xoffs + 50, self._height - 55 + self._yoffs), 88 size=(60, 55), 89 scale=0.8, 90 label=bui.charstr(bui.SpecialChar.BACK), 91 button_type='backSmall', 92 extra_touch_border_scale=2.0, 93 autoselect=True, 94 on_activate_call=self.main_window_back, 95 ) 96 bui.containerwidget(edit=self._root_widget, cancel_button=btn) 97 self._core_widgets.append(btn) 98 99 self._infotext = bui.textwidget( 100 parent=self._root_widget, 101 position=(self._width * 0.5, self._height - 200 + self._yoffs), 102 size=(0, 0), 103 text=bui.Lstr(resource='loadingText'), 104 maxwidth=700, 105 scale=0.7, 106 color=(0.6, 0.5, 0.6), 107 h_align='center', 108 v_align='center', 109 ) 110 self._core_widgets.append(self._infotext) 111 112 plus = bui.app.plus 113 if plus is None: 114 self._error('Plus feature-set is not present.') 115 return 116 117 if plus.accounts.primary is None: 118 self._error(bui.Lstr(resource='notSignedInText')) 119 return 120 121 # Start by showing info/options for our target chest. Note that 122 # we always ask the server for these values even though we may 123 # have them through our appmode subscription which updates the 124 # chest UI. This is because the wait_for_connectivity() 125 # mechanism will often bring our window up a split second before 126 # the chest subscription receives its first values which would 127 # lead us to incorrectly think there is no chest there. If we 128 # want to optimize this in the future we could perhaps use local 129 # values only if there is a chest present in them. 130 assert not self._action_in_flight 131 self._action_in_flight = True 132 with plus.accounts.primary: 133 plus.cloud.send_message_cb( 134 bacommon.cloud.BSChestInfoMessage(chest_id=str(self._index)), 135 on_response=bui.WeakCall(self._on_chest_info_response), 136 ) 137 138 def _on_chest_info_response( 139 self, response: bacommon.cloud.BSChestInfoResponse | Exception 140 ) -> None: 141 assert self._action_in_flight # Should be us. 142 self._action_in_flight = False 143 144 if isinstance(response, Exception): 145 self._error( 146 bui.Lstr(resource='internal.unavailableNoConnectionText') 147 ) 148 return 149 150 if response.chest is None: 151 self._show_about_chest_slots() 152 return 153 154 self.show_chest_actions(response.chest) 155 156 def _on_chest_action_response( 157 self, response: bacommon.cloud.BSChestActionResponse | Exception 158 ) -> None: 159 assert self._action_in_flight # Should be us. 160 self._action_in_flight = False 161 162 # Communication/local error: 163 if isinstance(response, Exception): 164 self._error( 165 bui.Lstr(resource='internal.unavailableNoConnectionText') 166 ) 167 return 168 169 # Server-side error: 170 if response.error is not None: 171 self._error(bui.Lstr(translate=('serverResponses', response.error))) 172 return 173 174 # If there's contents listed in the response, show them. 175 if response.contents is not None: 176 print('WOULD SHOW CONTENTS:', response.contents) 177 else: 178 # Otherwise we're done here; just close out our UI. 179 self.main_window_back() 180 181 def show_chest_actions( 182 self, chest: bacommon.cloud.BSChestInfoResponse.Chest 183 ) -> None: 184 """Show state for our chest.""" 185 # pylint: disable=cyclic-import 186 from baclassic import ClassicAppMode 187 188 # We expect to be run under classic. 189 mode = bui.app.mode 190 if not isinstance(mode, ClassicAppMode): 191 self._error('Classic app mode not active.') 192 return 193 194 now = bui.utc_now_cloud() 195 secs_till_open = max(0.0, (chest.unlock_time - now).total_seconds()) 196 tstr = bui.timestring(secs_till_open, centi=False) 197 198 bui.textwidget( 199 parent=self._root_widget, 200 position=(self._width * 0.5, self._height - 120 + self._yoffs), 201 size=(0, 0), 202 text=tstr, 203 maxwidth=700, 204 scale=0.7, 205 color=(0.6, 0.5, 0.6), 206 h_align='center', 207 v_align='center', 208 ) 209 self._open_now_button = bui.buttonwidget( 210 parent=self._root_widget, 211 position=( 212 self._width * 0.5 - 200, 213 self._height - 250 + self._yoffs, 214 ), 215 size=(150, 100), 216 label=f'OPEN NOW FOR {chest.unlock_tokens} TOKENS', 217 button_type='square', 218 autoselect=True, 219 on_activate_call=bui.WeakCall( 220 self._open_now_press, chest.unlock_tokens 221 ), 222 ) 223 224 self._watch_ad_button = bui.buttonwidget( 225 parent=self._root_widget, 226 position=( 227 self._width * 0.5 + 50, 228 self._height - 250 + self._yoffs, 229 ), 230 size=(150, 100), 231 label='WATCH AN AD TO REDUCE WAIT', 232 button_type='square', 233 autoselect=True, 234 on_activate_call=bui.WeakCall(self._watch_ad_press), 235 ) 236 bui.textwidget(edit=self._infotext, text='') 237 238 def _open_now_press(self, token_payment: int) -> None: 239 240 # Allow only one in-flight action at once. 241 if self._action_in_flight: 242 bui.screenmessage( 243 bui.Lstr(resource='pleaseWaitText'), color=(1, 0, 0) 244 ) 245 bui.getsound('error').play() 246 return 247 248 plus = bui.app.plus 249 assert plus is not None 250 251 if plus.accounts.primary is None: 252 self._error(bui.Lstr(resource='notSignedInText')) 253 return 254 255 self._action_in_flight = True 256 with plus.accounts.primary: 257 plus.cloud.send_message_cb( 258 bacommon.cloud.BSChestActionMessage( 259 chest_id=str(self._index), 260 action=bacommon.cloud.BSChestActionMessage.Action.UNLOCK, 261 token_payment=token_payment, 262 ), 263 on_response=bui.WeakCall(self._on_chest_action_response), 264 ) 265 266 # Convey that something is in progress. 267 if self._open_now_button: 268 bui.buttonwidget(edit=self._open_now_button, label='...') 269 270 def _watch_ad_press(self) -> None: 271 272 # Allow only one in-flight action at once. 273 if self._action_in_flight: 274 bui.screenmessage( 275 bui.Lstr(resource='pleaseWaitText'), color=(1, 0, 0) 276 ) 277 bui.getsound('error').play() 278 return 279 280 plus = bui.app.plus 281 assert plus is not None 282 283 if plus.accounts.primary is None: 284 self._error(bui.Lstr(resource='notSignedInText')) 285 return 286 287 self._action_in_flight = True 288 with plus.accounts.primary: 289 plus.cloud.send_message_cb( 290 bacommon.cloud.BSChestActionMessage( 291 chest_id=str(self._index), 292 action=bacommon.cloud.BSChestActionMessage.Action.AD, 293 token_payment=0, 294 ), 295 on_response=bui.WeakCall(self._on_chest_action_response), 296 ) 297 298 # Convey that something is in progress. 299 if self._watch_ad_button: 300 bui.buttonwidget(edit=self._watch_ad_button, label='...') 301 302 def _reset(self) -> None: 303 """Clear all non-permanent widgets.""" 304 for widget in self._root_widget.get_children(): 305 if widget not in self._core_widgets: 306 widget.delete() 307 308 def _error(self, msg: str | bui.Lstr) -> None: 309 """Put ourself in an error state with a visible error message.""" 310 self._reset() 311 bui.textwidget(edit=self._infotext, text=msg, color=(1, 0, 0)) 312 313 def _show_about_chest_slots(self) -> None: 314 self._reset() 315 msg = ( 316 'This empty slot can hold a treasure chest.\n' 317 'Treasure chests are earned through gameplay.' 318 ) 319 bui.textwidget(edit=self._infotext, text=msg, color=(1, 1, 1)) 320 321 @override 322 def get_main_window_state(self) -> bui.MainWindowState: 323 # Support recreating our window for back/refresh purposes. 324 cls = type(self) 325 326 # Pull anything we need from self out here; if we do it in the 327 # lambda we keep self alive which is bad. 328 index = self._index 329 330 return bui.BasicMainWindowState( 331 create_call=lambda transition, origin_widget: cls( 332 index=index, transition=transition, origin_widget=origin_widget 333 ) 334 ) 335 336 337# Slight hack: we define different classes for our different chest slots 338# so that the default UI behavior is to replace each other when 339# different ones are pressed. If they are all the same class then the 340# default behavior for such presses is to toggle the existing one back 341# off. 342 343 344class ChestWindow0(ChestWindow): 345 """Child class of ChestWindow for slighty hackish reasons.""" 346 347 348class ChestWindow1(ChestWindow): 349 """Child class of ChestWindow for slighty hackish reasons.""" 350 351 352class ChestWindow2(ChestWindow): 353 """Child class of ChestWindow for slighty hackish reasons.""" 354 355 356class ChestWindow3(ChestWindow): 357 """Child class of ChestWindow for slighty hackish reasons."""
class
ChestWindow(bauiv1._uitypes.MainWindow):
17class ChestWindow(bui.MainWindow): 18 """Allows operations on a chest.""" 19 20 # def __del__(self) -> None: 21 # print('~ChestWindow()') 22 23 def __init__( 24 self, 25 index: int, 26 transition: str | None = 'in_right', 27 origin_widget: bui.Widget | None = None, 28 ): 29 # print('ChestWindow()') 30 31 self._index = index 32 33 assert bui.app.classic is not None 34 uiscale = bui.app.ui_v1.uiscale 35 self._width = 1050 if uiscale is bui.UIScale.SMALL else 850 36 self._height = ( 37 500 38 if uiscale is bui.UIScale.SMALL 39 else 500 if uiscale is bui.UIScale.MEDIUM else 500 40 ) 41 self._xoffs = 70 if uiscale is bui.UIScale.SMALL else 0 42 self._yoffs = -42 if uiscale is bui.UIScale.SMALL else -25 43 self._action_in_flight = False 44 self._open_now_button: bui.Widget | None = None 45 self._watch_ad_button: bui.Widget | None = None 46 47 # The set of widgets we keep when doing a clear. 48 self._core_widgets: list[bui.Widget] = [] 49 50 super().__init__( 51 root_widget=bui.containerwidget( 52 size=(self._width, self._height), 53 toolbar_visibility='menu_full', 54 scale=( 55 1.55 56 if uiscale is bui.UIScale.SMALL 57 else 1.1 if uiscale is bui.UIScale.MEDIUM else 0.9 58 ), 59 stack_offset=( 60 (0, 0) 61 if uiscale is bui.UIScale.SMALL 62 else (0, 15) if uiscale is bui.UIScale.MEDIUM else (0, 0) 63 ), 64 ), 65 transition=transition, 66 origin_widget=origin_widget, 67 ) 68 69 self._title_text = bui.textwidget( 70 parent=self._root_widget, 71 position=(0, self._height - 45 + self._yoffs), 72 size=(self._width, 25), 73 text=f'Chest Slot {self._index + 1}', 74 color=bui.app.ui_v1.title_color, 75 maxwidth=150.0, 76 h_align='center', 77 v_align='center', 78 ) 79 self._core_widgets.append(self._title_text) 80 81 if uiscale is bui.UIScale.SMALL: 82 bui.containerwidget( 83 edit=self._root_widget, on_cancel_call=self.main_window_back 84 ) 85 else: 86 btn = bui.buttonwidget( 87 parent=self._root_widget, 88 position=(self._xoffs + 50, self._height - 55 + self._yoffs), 89 size=(60, 55), 90 scale=0.8, 91 label=bui.charstr(bui.SpecialChar.BACK), 92 button_type='backSmall', 93 extra_touch_border_scale=2.0, 94 autoselect=True, 95 on_activate_call=self.main_window_back, 96 ) 97 bui.containerwidget(edit=self._root_widget, cancel_button=btn) 98 self._core_widgets.append(btn) 99 100 self._infotext = bui.textwidget( 101 parent=self._root_widget, 102 position=(self._width * 0.5, self._height - 200 + self._yoffs), 103 size=(0, 0), 104 text=bui.Lstr(resource='loadingText'), 105 maxwidth=700, 106 scale=0.7, 107 color=(0.6, 0.5, 0.6), 108 h_align='center', 109 v_align='center', 110 ) 111 self._core_widgets.append(self._infotext) 112 113 plus = bui.app.plus 114 if plus is None: 115 self._error('Plus feature-set is not present.') 116 return 117 118 if plus.accounts.primary is None: 119 self._error(bui.Lstr(resource='notSignedInText')) 120 return 121 122 # Start by showing info/options for our target chest. Note that 123 # we always ask the server for these values even though we may 124 # have them through our appmode subscription which updates the 125 # chest UI. This is because the wait_for_connectivity() 126 # mechanism will often bring our window up a split second before 127 # the chest subscription receives its first values which would 128 # lead us to incorrectly think there is no chest there. If we 129 # want to optimize this in the future we could perhaps use local 130 # values only if there is a chest present in them. 131 assert not self._action_in_flight 132 self._action_in_flight = True 133 with plus.accounts.primary: 134 plus.cloud.send_message_cb( 135 bacommon.cloud.BSChestInfoMessage(chest_id=str(self._index)), 136 on_response=bui.WeakCall(self._on_chest_info_response), 137 ) 138 139 def _on_chest_info_response( 140 self, response: bacommon.cloud.BSChestInfoResponse | Exception 141 ) -> None: 142 assert self._action_in_flight # Should be us. 143 self._action_in_flight = False 144 145 if isinstance(response, Exception): 146 self._error( 147 bui.Lstr(resource='internal.unavailableNoConnectionText') 148 ) 149 return 150 151 if response.chest is None: 152 self._show_about_chest_slots() 153 return 154 155 self.show_chest_actions(response.chest) 156 157 def _on_chest_action_response( 158 self, response: bacommon.cloud.BSChestActionResponse | Exception 159 ) -> None: 160 assert self._action_in_flight # Should be us. 161 self._action_in_flight = False 162 163 # Communication/local error: 164 if isinstance(response, Exception): 165 self._error( 166 bui.Lstr(resource='internal.unavailableNoConnectionText') 167 ) 168 return 169 170 # Server-side error: 171 if response.error is not None: 172 self._error(bui.Lstr(translate=('serverResponses', response.error))) 173 return 174 175 # If there's contents listed in the response, show them. 176 if response.contents is not None: 177 print('WOULD SHOW CONTENTS:', response.contents) 178 else: 179 # Otherwise we're done here; just close out our UI. 180 self.main_window_back() 181 182 def show_chest_actions( 183 self, chest: bacommon.cloud.BSChestInfoResponse.Chest 184 ) -> None: 185 """Show state for our chest.""" 186 # pylint: disable=cyclic-import 187 from baclassic import ClassicAppMode 188 189 # We expect to be run under classic. 190 mode = bui.app.mode 191 if not isinstance(mode, ClassicAppMode): 192 self._error('Classic app mode not active.') 193 return 194 195 now = bui.utc_now_cloud() 196 secs_till_open = max(0.0, (chest.unlock_time - now).total_seconds()) 197 tstr = bui.timestring(secs_till_open, centi=False) 198 199 bui.textwidget( 200 parent=self._root_widget, 201 position=(self._width * 0.5, self._height - 120 + self._yoffs), 202 size=(0, 0), 203 text=tstr, 204 maxwidth=700, 205 scale=0.7, 206 color=(0.6, 0.5, 0.6), 207 h_align='center', 208 v_align='center', 209 ) 210 self._open_now_button = bui.buttonwidget( 211 parent=self._root_widget, 212 position=( 213 self._width * 0.5 - 200, 214 self._height - 250 + self._yoffs, 215 ), 216 size=(150, 100), 217 label=f'OPEN NOW FOR {chest.unlock_tokens} TOKENS', 218 button_type='square', 219 autoselect=True, 220 on_activate_call=bui.WeakCall( 221 self._open_now_press, chest.unlock_tokens 222 ), 223 ) 224 225 self._watch_ad_button = bui.buttonwidget( 226 parent=self._root_widget, 227 position=( 228 self._width * 0.5 + 50, 229 self._height - 250 + self._yoffs, 230 ), 231 size=(150, 100), 232 label='WATCH AN AD TO REDUCE WAIT', 233 button_type='square', 234 autoselect=True, 235 on_activate_call=bui.WeakCall(self._watch_ad_press), 236 ) 237 bui.textwidget(edit=self._infotext, text='') 238 239 def _open_now_press(self, token_payment: int) -> None: 240 241 # Allow only one in-flight action at once. 242 if self._action_in_flight: 243 bui.screenmessage( 244 bui.Lstr(resource='pleaseWaitText'), color=(1, 0, 0) 245 ) 246 bui.getsound('error').play() 247 return 248 249 plus = bui.app.plus 250 assert plus is not None 251 252 if plus.accounts.primary is None: 253 self._error(bui.Lstr(resource='notSignedInText')) 254 return 255 256 self._action_in_flight = True 257 with plus.accounts.primary: 258 plus.cloud.send_message_cb( 259 bacommon.cloud.BSChestActionMessage( 260 chest_id=str(self._index), 261 action=bacommon.cloud.BSChestActionMessage.Action.UNLOCK, 262 token_payment=token_payment, 263 ), 264 on_response=bui.WeakCall(self._on_chest_action_response), 265 ) 266 267 # Convey that something is in progress. 268 if self._open_now_button: 269 bui.buttonwidget(edit=self._open_now_button, label='...') 270 271 def _watch_ad_press(self) -> None: 272 273 # Allow only one in-flight action at once. 274 if self._action_in_flight: 275 bui.screenmessage( 276 bui.Lstr(resource='pleaseWaitText'), color=(1, 0, 0) 277 ) 278 bui.getsound('error').play() 279 return 280 281 plus = bui.app.plus 282 assert plus is not None 283 284 if plus.accounts.primary is None: 285 self._error(bui.Lstr(resource='notSignedInText')) 286 return 287 288 self._action_in_flight = True 289 with plus.accounts.primary: 290 plus.cloud.send_message_cb( 291 bacommon.cloud.BSChestActionMessage( 292 chest_id=str(self._index), 293 action=bacommon.cloud.BSChestActionMessage.Action.AD, 294 token_payment=0, 295 ), 296 on_response=bui.WeakCall(self._on_chest_action_response), 297 ) 298 299 # Convey that something is in progress. 300 if self._watch_ad_button: 301 bui.buttonwidget(edit=self._watch_ad_button, label='...') 302 303 def _reset(self) -> None: 304 """Clear all non-permanent widgets.""" 305 for widget in self._root_widget.get_children(): 306 if widget not in self._core_widgets: 307 widget.delete() 308 309 def _error(self, msg: str | bui.Lstr) -> None: 310 """Put ourself in an error state with a visible error message.""" 311 self._reset() 312 bui.textwidget(edit=self._infotext, text=msg, color=(1, 0, 0)) 313 314 def _show_about_chest_slots(self) -> None: 315 self._reset() 316 msg = ( 317 'This empty slot can hold a treasure chest.\n' 318 'Treasure chests are earned through gameplay.' 319 ) 320 bui.textwidget(edit=self._infotext, text=msg, color=(1, 1, 1)) 321 322 @override 323 def get_main_window_state(self) -> bui.MainWindowState: 324 # Support recreating our window for back/refresh purposes. 325 cls = type(self) 326 327 # Pull anything we need from self out here; if we do it in the 328 # lambda we keep self alive which is bad. 329 index = self._index 330 331 return bui.BasicMainWindowState( 332 create_call=lambda transition, origin_widget: cls( 333 index=index, transition=transition, origin_widget=origin_widget 334 ) 335 )
Allows operations on a chest.
ChestWindow( index: int, transition: str | None = 'in_right', origin_widget: _bauiv1.Widget | None = None)
23 def __init__( 24 self, 25 index: int, 26 transition: str | None = 'in_right', 27 origin_widget: bui.Widget | None = None, 28 ): 29 # print('ChestWindow()') 30 31 self._index = index 32 33 assert bui.app.classic is not None 34 uiscale = bui.app.ui_v1.uiscale 35 self._width = 1050 if uiscale is bui.UIScale.SMALL else 850 36 self._height = ( 37 500 38 if uiscale is bui.UIScale.SMALL 39 else 500 if uiscale is bui.UIScale.MEDIUM else 500 40 ) 41 self._xoffs = 70 if uiscale is bui.UIScale.SMALL else 0 42 self._yoffs = -42 if uiscale is bui.UIScale.SMALL else -25 43 self._action_in_flight = False 44 self._open_now_button: bui.Widget | None = None 45 self._watch_ad_button: bui.Widget | None = None 46 47 # The set of widgets we keep when doing a clear. 48 self._core_widgets: list[bui.Widget] = [] 49 50 super().__init__( 51 root_widget=bui.containerwidget( 52 size=(self._width, self._height), 53 toolbar_visibility='menu_full', 54 scale=( 55 1.55 56 if uiscale is bui.UIScale.SMALL 57 else 1.1 if uiscale is bui.UIScale.MEDIUM else 0.9 58 ), 59 stack_offset=( 60 (0, 0) 61 if uiscale is bui.UIScale.SMALL 62 else (0, 15) if uiscale is bui.UIScale.MEDIUM else (0, 0) 63 ), 64 ), 65 transition=transition, 66 origin_widget=origin_widget, 67 ) 68 69 self._title_text = bui.textwidget( 70 parent=self._root_widget, 71 position=(0, self._height - 45 + self._yoffs), 72 size=(self._width, 25), 73 text=f'Chest Slot {self._index + 1}', 74 color=bui.app.ui_v1.title_color, 75 maxwidth=150.0, 76 h_align='center', 77 v_align='center', 78 ) 79 self._core_widgets.append(self._title_text) 80 81 if uiscale is bui.UIScale.SMALL: 82 bui.containerwidget( 83 edit=self._root_widget, on_cancel_call=self.main_window_back 84 ) 85 else: 86 btn = bui.buttonwidget( 87 parent=self._root_widget, 88 position=(self._xoffs + 50, self._height - 55 + self._yoffs), 89 size=(60, 55), 90 scale=0.8, 91 label=bui.charstr(bui.SpecialChar.BACK), 92 button_type='backSmall', 93 extra_touch_border_scale=2.0, 94 autoselect=True, 95 on_activate_call=self.main_window_back, 96 ) 97 bui.containerwidget(edit=self._root_widget, cancel_button=btn) 98 self._core_widgets.append(btn) 99 100 self._infotext = bui.textwidget( 101 parent=self._root_widget, 102 position=(self._width * 0.5, self._height - 200 + self._yoffs), 103 size=(0, 0), 104 text=bui.Lstr(resource='loadingText'), 105 maxwidth=700, 106 scale=0.7, 107 color=(0.6, 0.5, 0.6), 108 h_align='center', 109 v_align='center', 110 ) 111 self._core_widgets.append(self._infotext) 112 113 plus = bui.app.plus 114 if plus is None: 115 self._error('Plus feature-set is not present.') 116 return 117 118 if plus.accounts.primary is None: 119 self._error(bui.Lstr(resource='notSignedInText')) 120 return 121 122 # Start by showing info/options for our target chest. Note that 123 # we always ask the server for these values even though we may 124 # have them through our appmode subscription which updates the 125 # chest UI. This is because the wait_for_connectivity() 126 # mechanism will often bring our window up a split second before 127 # the chest subscription receives its first values which would 128 # lead us to incorrectly think there is no chest there. If we 129 # want to optimize this in the future we could perhaps use local 130 # values only if there is a chest present in them. 131 assert not self._action_in_flight 132 self._action_in_flight = True 133 with plus.accounts.primary: 134 plus.cloud.send_message_cb( 135 bacommon.cloud.BSChestInfoMessage(chest_id=str(self._index)), 136 on_response=bui.WeakCall(self._on_chest_info_response), 137 )
Create a MainWindow given a root widget and transition info.
Automatically handles in and out transitions on the provided widget, so there is no need to set transitions when creating it.
182 def show_chest_actions( 183 self, chest: bacommon.cloud.BSChestInfoResponse.Chest 184 ) -> None: 185 """Show state for our chest.""" 186 # pylint: disable=cyclic-import 187 from baclassic import ClassicAppMode 188 189 # We expect to be run under classic. 190 mode = bui.app.mode 191 if not isinstance(mode, ClassicAppMode): 192 self._error('Classic app mode not active.') 193 return 194 195 now = bui.utc_now_cloud() 196 secs_till_open = max(0.0, (chest.unlock_time - now).total_seconds()) 197 tstr = bui.timestring(secs_till_open, centi=False) 198 199 bui.textwidget( 200 parent=self._root_widget, 201 position=(self._width * 0.5, self._height - 120 + self._yoffs), 202 size=(0, 0), 203 text=tstr, 204 maxwidth=700, 205 scale=0.7, 206 color=(0.6, 0.5, 0.6), 207 h_align='center', 208 v_align='center', 209 ) 210 self._open_now_button = bui.buttonwidget( 211 parent=self._root_widget, 212 position=( 213 self._width * 0.5 - 200, 214 self._height - 250 + self._yoffs, 215 ), 216 size=(150, 100), 217 label=f'OPEN NOW FOR {chest.unlock_tokens} TOKENS', 218 button_type='square', 219 autoselect=True, 220 on_activate_call=bui.WeakCall( 221 self._open_now_press, chest.unlock_tokens 222 ), 223 ) 224 225 self._watch_ad_button = bui.buttonwidget( 226 parent=self._root_widget, 227 position=( 228 self._width * 0.5 + 50, 229 self._height - 250 + self._yoffs, 230 ), 231 size=(150, 100), 232 label='WATCH AN AD TO REDUCE WAIT', 233 button_type='square', 234 autoselect=True, 235 on_activate_call=bui.WeakCall(self._watch_ad_press), 236 ) 237 bui.textwidget(edit=self._infotext, text='')
Show state for our chest.
322 @override 323 def get_main_window_state(self) -> bui.MainWindowState: 324 # Support recreating our window for back/refresh purposes. 325 cls = type(self) 326 327 # Pull anything we need from self out here; if we do it in the 328 # lambda we keep self alive which is bad. 329 index = self._index 330 331 return bui.BasicMainWindowState( 332 create_call=lambda transition, origin_widget: cls( 333 index=index, transition=transition, origin_widget=origin_widget 334 ) 335 )
Return a WindowState to recreate this window, if supported.
345class ChestWindow0(ChestWindow): 346 """Child class of ChestWindow for slighty hackish reasons."""
Child class of ChestWindow for slighty hackish reasons.
Inherited Members
349class ChestWindow1(ChestWindow): 350 """Child class of ChestWindow for slighty hackish reasons."""
Child class of ChestWindow for slighty hackish reasons.
Inherited Members
353class ChestWindow2(ChestWindow): 354 """Child class of ChestWindow for slighty hackish reasons."""
Child class of ChestWindow for slighty hackish reasons.
Inherited Members
357class ChestWindow3(ChestWindow): 358 """Child class of ChestWindow for slighty hackish reasons."""
Child class of ChestWindow for slighty hackish reasons.