bauiv1lib.promocode
UI functionality for entering promo codes.
1# Released under the MIT License. See LICENSE for details. 2# 3"""UI functionality for entering promo codes.""" 4 5from __future__ import annotations 6 7import time 8import logging 9from typing import TYPE_CHECKING 10 11import bauiv1 as bui 12 13if TYPE_CHECKING: 14 from typing import Any 15 16 17class PromoCodeWindow(bui.Window): 18 """Window for entering promo codes.""" 19 20 def __init__( 21 self, modal: bool = False, origin_widget: bui.Widget | None = None 22 ): 23 scale_origin: tuple[float, float] | None 24 if origin_widget is not None: 25 self._transition_out = 'out_scale' 26 scale_origin = origin_widget.get_screen_space_center() 27 transition = 'in_scale' 28 else: 29 self._transition_out = 'out_right' 30 scale_origin = None 31 transition = 'in_right' 32 33 width = 450 34 height = 330 35 36 self._modal = modal 37 self._r = 'promoCodeWindow' 38 39 assert bui.app.classic is not None 40 uiscale = bui.app.ui_v1.uiscale 41 super().__init__( 42 root_widget=bui.containerwidget( 43 size=(width, height), 44 transition=transition, 45 toolbar_visibility='menu_minimal_no_back', 46 scale_origin_stack_offset=scale_origin, 47 scale=( 48 2.0 49 if uiscale is bui.UIScale.SMALL 50 else 1.5 if uiscale is bui.UIScale.MEDIUM else 1.0 51 ), 52 ) 53 ) 54 55 btn = bui.buttonwidget( 56 parent=self._root_widget, 57 scale=0.5, 58 position=(40, height - 40), 59 size=(60, 60), 60 label='', 61 on_activate_call=self._do_back, 62 autoselect=True, 63 color=(0.55, 0.5, 0.6), 64 icon=bui.gettexture('crossOut'), 65 iconscale=1.2, 66 ) 67 68 v = height - 74 69 bui.textwidget( 70 parent=self._root_widget, 71 text=bui.Lstr(resource='codesExplainText'), 72 maxwidth=width * 0.9, 73 position=(width * 0.5, v), 74 color=(0.7, 0.7, 0.7, 1.0), 75 size=(0, 0), 76 scale=0.8, 77 h_align='center', 78 v_align='center', 79 ) 80 v -= 60 81 82 bui.textwidget( 83 parent=self._root_widget, 84 text=bui.Lstr( 85 resource='supportEmailText', 86 subs=[('${EMAIL}', 'support@froemling.net')], 87 ), 88 maxwidth=width * 0.9, 89 position=(width * 0.5, v), 90 color=(0.7, 0.7, 0.7, 1.0), 91 size=(0, 0), 92 scale=0.65, 93 h_align='center', 94 v_align='center', 95 ) 96 97 v -= 80 98 99 bui.textwidget( 100 parent=self._root_widget, 101 text=bui.Lstr(resource=self._r + '.codeText'), 102 position=(22, v), 103 color=(0.8, 0.8, 0.8, 1.0), 104 size=(90, 30), 105 h_align='right', 106 ) 107 v -= 8 108 109 self._text_field = bui.textwidget( 110 parent=self._root_widget, 111 position=(125, v), 112 size=(280, 46), 113 text='', 114 h_align='left', 115 v_align='center', 116 max_chars=64, 117 color=(0.9, 0.9, 0.9, 1.0), 118 description=bui.Lstr(resource=self._r + '.codeText'), 119 editable=True, 120 padding=4, 121 on_return_press_call=self._activate_enter_button, 122 ) 123 bui.widget(edit=btn, down_widget=self._text_field) 124 125 v -= 79 126 b_width = 200 127 self._enter_button = btn2 = bui.buttonwidget( 128 parent=self._root_widget, 129 position=(width * 0.5 - b_width * 0.5, v), 130 size=(b_width, 60), 131 scale=1.0, 132 label=bui.Lstr( 133 resource='submitText', fallback_resource=self._r + '.enterText' 134 ), 135 on_activate_call=self._do_enter, 136 ) 137 bui.containerwidget( 138 edit=self._root_widget, 139 cancel_button=btn, 140 start_button=btn2, 141 selected_child=self._text_field, 142 ) 143 144 def _do_back(self) -> None: 145 # pylint: disable=cyclic-import 146 from bauiv1lib.settings.advanced import AdvancedSettingsWindow 147 148 # no-op if our underlying widget is dead or on its way out. 149 if not self._root_widget or self._root_widget.transitioning_out: 150 return 151 152 bui.containerwidget( 153 edit=self._root_widget, transition=self._transition_out 154 ) 155 if not self._modal: 156 assert bui.app.classic is not None 157 bui.app.ui_v1.set_main_menu_window( 158 AdvancedSettingsWindow(transition='in_left').get_root_widget(), 159 from_window=self._root_widget, 160 ) 161 162 def _activate_enter_button(self) -> None: 163 self._enter_button.activate() 164 165 def _do_enter(self) -> None: 166 # pylint: disable=cyclic-import 167 from bauiv1lib.settings.advanced import AdvancedSettingsWindow 168 169 # no-op if our underlying widget is dead or on its way out. 170 if not self._root_widget or self._root_widget.transitioning_out: 171 return 172 173 bui.containerwidget( 174 edit=self._root_widget, transition=self._transition_out 175 ) 176 if not self._modal: 177 assert bui.app.classic is not None 178 bui.app.ui_v1.set_main_menu_window( 179 AdvancedSettingsWindow(transition='in_left').get_root_widget(), 180 from_window=self._root_widget, 181 ) 182 183 code: Any = bui.textwidget(query=self._text_field) 184 assert isinstance(code, str) 185 186 bui.app.create_async_task(_run_code(code)) 187 188 189async def _run_code(code: str) -> None: 190 from bacommon.cloud import PromoCodeMessage 191 192 plus = bui.app.plus 193 assert plus is not None 194 195 try: 196 # If we're signed in with a V2 account, ship this to V2 server. 197 if plus.accounts.primary is not None: 198 with plus.accounts.primary: 199 response = await plus.cloud.send_message_async( 200 PromoCodeMessage(code) 201 ) 202 # If V2 handled it, we're done. 203 if response.valid: 204 # Support simple message printing from v2 server. 205 if response.message is not None: 206 bui.screenmessage(response.message, color=(0, 1, 0)) 207 return 208 209 # If V2 didn't accept it (or isn't signed in) kick it over to V1. 210 plus.add_v1_account_transaction( 211 { 212 'type': 'PROMO_CODE', 213 'expire_time': time.time() + 5, 214 'code': code, 215 } 216 ) 217 plus.run_v1_account_transactions() 218 except Exception: 219 logging.exception('Error sending promo code.') 220 bui.screenmessage('Error sending code (see log).', color=(1, 0, 0)) 221 bui.getsound('error').play()
class
PromoCodeWindow(bauiv1._uitypes.Window):
18class PromoCodeWindow(bui.Window): 19 """Window for entering promo codes.""" 20 21 def __init__( 22 self, modal: bool = False, origin_widget: bui.Widget | None = None 23 ): 24 scale_origin: tuple[float, float] | None 25 if origin_widget is not None: 26 self._transition_out = 'out_scale' 27 scale_origin = origin_widget.get_screen_space_center() 28 transition = 'in_scale' 29 else: 30 self._transition_out = 'out_right' 31 scale_origin = None 32 transition = 'in_right' 33 34 width = 450 35 height = 330 36 37 self._modal = modal 38 self._r = 'promoCodeWindow' 39 40 assert bui.app.classic is not None 41 uiscale = bui.app.ui_v1.uiscale 42 super().__init__( 43 root_widget=bui.containerwidget( 44 size=(width, height), 45 transition=transition, 46 toolbar_visibility='menu_minimal_no_back', 47 scale_origin_stack_offset=scale_origin, 48 scale=( 49 2.0 50 if uiscale is bui.UIScale.SMALL 51 else 1.5 if uiscale is bui.UIScale.MEDIUM else 1.0 52 ), 53 ) 54 ) 55 56 btn = bui.buttonwidget( 57 parent=self._root_widget, 58 scale=0.5, 59 position=(40, height - 40), 60 size=(60, 60), 61 label='', 62 on_activate_call=self._do_back, 63 autoselect=True, 64 color=(0.55, 0.5, 0.6), 65 icon=bui.gettexture('crossOut'), 66 iconscale=1.2, 67 ) 68 69 v = height - 74 70 bui.textwidget( 71 parent=self._root_widget, 72 text=bui.Lstr(resource='codesExplainText'), 73 maxwidth=width * 0.9, 74 position=(width * 0.5, v), 75 color=(0.7, 0.7, 0.7, 1.0), 76 size=(0, 0), 77 scale=0.8, 78 h_align='center', 79 v_align='center', 80 ) 81 v -= 60 82 83 bui.textwidget( 84 parent=self._root_widget, 85 text=bui.Lstr( 86 resource='supportEmailText', 87 subs=[('${EMAIL}', 'support@froemling.net')], 88 ), 89 maxwidth=width * 0.9, 90 position=(width * 0.5, v), 91 color=(0.7, 0.7, 0.7, 1.0), 92 size=(0, 0), 93 scale=0.65, 94 h_align='center', 95 v_align='center', 96 ) 97 98 v -= 80 99 100 bui.textwidget( 101 parent=self._root_widget, 102 text=bui.Lstr(resource=self._r + '.codeText'), 103 position=(22, v), 104 color=(0.8, 0.8, 0.8, 1.0), 105 size=(90, 30), 106 h_align='right', 107 ) 108 v -= 8 109 110 self._text_field = bui.textwidget( 111 parent=self._root_widget, 112 position=(125, v), 113 size=(280, 46), 114 text='', 115 h_align='left', 116 v_align='center', 117 max_chars=64, 118 color=(0.9, 0.9, 0.9, 1.0), 119 description=bui.Lstr(resource=self._r + '.codeText'), 120 editable=True, 121 padding=4, 122 on_return_press_call=self._activate_enter_button, 123 ) 124 bui.widget(edit=btn, down_widget=self._text_field) 125 126 v -= 79 127 b_width = 200 128 self._enter_button = btn2 = bui.buttonwidget( 129 parent=self._root_widget, 130 position=(width * 0.5 - b_width * 0.5, v), 131 size=(b_width, 60), 132 scale=1.0, 133 label=bui.Lstr( 134 resource='submitText', fallback_resource=self._r + '.enterText' 135 ), 136 on_activate_call=self._do_enter, 137 ) 138 bui.containerwidget( 139 edit=self._root_widget, 140 cancel_button=btn, 141 start_button=btn2, 142 selected_child=self._text_field, 143 ) 144 145 def _do_back(self) -> None: 146 # pylint: disable=cyclic-import 147 from bauiv1lib.settings.advanced import AdvancedSettingsWindow 148 149 # no-op if our underlying widget is dead or on its way out. 150 if not self._root_widget or self._root_widget.transitioning_out: 151 return 152 153 bui.containerwidget( 154 edit=self._root_widget, transition=self._transition_out 155 ) 156 if not self._modal: 157 assert bui.app.classic is not None 158 bui.app.ui_v1.set_main_menu_window( 159 AdvancedSettingsWindow(transition='in_left').get_root_widget(), 160 from_window=self._root_widget, 161 ) 162 163 def _activate_enter_button(self) -> None: 164 self._enter_button.activate() 165 166 def _do_enter(self) -> None: 167 # pylint: disable=cyclic-import 168 from bauiv1lib.settings.advanced import AdvancedSettingsWindow 169 170 # no-op if our underlying widget is dead or on its way out. 171 if not self._root_widget or self._root_widget.transitioning_out: 172 return 173 174 bui.containerwidget( 175 edit=self._root_widget, transition=self._transition_out 176 ) 177 if not self._modal: 178 assert bui.app.classic is not None 179 bui.app.ui_v1.set_main_menu_window( 180 AdvancedSettingsWindow(transition='in_left').get_root_widget(), 181 from_window=self._root_widget, 182 ) 183 184 code: Any = bui.textwidget(query=self._text_field) 185 assert isinstance(code, str) 186 187 bui.app.create_async_task(_run_code(code))
Window for entering promo codes.
PromoCodeWindow(modal: bool = False, origin_widget: _bauiv1.Widget | None = None)
21 def __init__( 22 self, modal: bool = False, origin_widget: bui.Widget | None = None 23 ): 24 scale_origin: tuple[float, float] | None 25 if origin_widget is not None: 26 self._transition_out = 'out_scale' 27 scale_origin = origin_widget.get_screen_space_center() 28 transition = 'in_scale' 29 else: 30 self._transition_out = 'out_right' 31 scale_origin = None 32 transition = 'in_right' 33 34 width = 450 35 height = 330 36 37 self._modal = modal 38 self._r = 'promoCodeWindow' 39 40 assert bui.app.classic is not None 41 uiscale = bui.app.ui_v1.uiscale 42 super().__init__( 43 root_widget=bui.containerwidget( 44 size=(width, height), 45 transition=transition, 46 toolbar_visibility='menu_minimal_no_back', 47 scale_origin_stack_offset=scale_origin, 48 scale=( 49 2.0 50 if uiscale is bui.UIScale.SMALL 51 else 1.5 if uiscale is bui.UIScale.MEDIUM else 1.0 52 ), 53 ) 54 ) 55 56 btn = bui.buttonwidget( 57 parent=self._root_widget, 58 scale=0.5, 59 position=(40, height - 40), 60 size=(60, 60), 61 label='', 62 on_activate_call=self._do_back, 63 autoselect=True, 64 color=(0.55, 0.5, 0.6), 65 icon=bui.gettexture('crossOut'), 66 iconscale=1.2, 67 ) 68 69 v = height - 74 70 bui.textwidget( 71 parent=self._root_widget, 72 text=bui.Lstr(resource='codesExplainText'), 73 maxwidth=width * 0.9, 74 position=(width * 0.5, v), 75 color=(0.7, 0.7, 0.7, 1.0), 76 size=(0, 0), 77 scale=0.8, 78 h_align='center', 79 v_align='center', 80 ) 81 v -= 60 82 83 bui.textwidget( 84 parent=self._root_widget, 85 text=bui.Lstr( 86 resource='supportEmailText', 87 subs=[('${EMAIL}', 'support@froemling.net')], 88 ), 89 maxwidth=width * 0.9, 90 position=(width * 0.5, v), 91 color=(0.7, 0.7, 0.7, 1.0), 92 size=(0, 0), 93 scale=0.65, 94 h_align='center', 95 v_align='center', 96 ) 97 98 v -= 80 99 100 bui.textwidget( 101 parent=self._root_widget, 102 text=bui.Lstr(resource=self._r + '.codeText'), 103 position=(22, v), 104 color=(0.8, 0.8, 0.8, 1.0), 105 size=(90, 30), 106 h_align='right', 107 ) 108 v -= 8 109 110 self._text_field = bui.textwidget( 111 parent=self._root_widget, 112 position=(125, v), 113 size=(280, 46), 114 text='', 115 h_align='left', 116 v_align='center', 117 max_chars=64, 118 color=(0.9, 0.9, 0.9, 1.0), 119 description=bui.Lstr(resource=self._r + '.codeText'), 120 editable=True, 121 padding=4, 122 on_return_press_call=self._activate_enter_button, 123 ) 124 bui.widget(edit=btn, down_widget=self._text_field) 125 126 v -= 79 127 b_width = 200 128 self._enter_button = btn2 = bui.buttonwidget( 129 parent=self._root_widget, 130 position=(width * 0.5 - b_width * 0.5, v), 131 size=(b_width, 60), 132 scale=1.0, 133 label=bui.Lstr( 134 resource='submitText', fallback_resource=self._r + '.enterText' 135 ), 136 on_activate_call=self._do_enter, 137 ) 138 bui.containerwidget( 139 edit=self._root_widget, 140 cancel_button=btn, 141 start_button=btn2, 142 selected_child=self._text_field, 143 )
Inherited Members
- bauiv1._uitypes.Window
- get_root_widget