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