bauiv1lib.purchase

UI related to purchasing items.

  1# Released under the MIT License. See LICENSE for details.
  2#
  3"""UI related to purchasing items."""
  4
  5from __future__ import annotations
  6
  7from typing import TYPE_CHECKING
  8
  9import bauiv1 as bui
 10
 11if TYPE_CHECKING:
 12    from typing import Any
 13
 14
 15class PurchaseWindow(bui.Window):
 16    """Window for purchasing one or more items."""
 17
 18    def __init__(
 19        self,
 20        items: list[str],
 21        origin_widget: bui.Widget | None = None,
 22        header_text: bui.Lstr | None = None,
 23    ):
 24        from bauiv1lib.store.item import instantiate_store_item_display
 25
 26        plus = bui.app.plus
 27        assert plus is not None
 28
 29        assert bui.app.classic is not None
 30        store = bui.app.classic.store
 31
 32        if header_text is None:
 33            header_text = bui.Lstr(
 34                resource='unlockThisText',
 35                fallback_resource='unlockThisInTheStoreText',
 36            )
 37        if len(items) != 1:
 38            raise ValueError('expected exactly 1 item')
 39        self._items = list(items)
 40        self._width = 580
 41        self._height = 520
 42        uiscale = bui.app.ui_v1.uiscale
 43
 44        if origin_widget is not None:
 45            scale_origin = origin_widget.get_screen_space_center()
 46        else:
 47            scale_origin = None
 48
 49        super().__init__(
 50            root_widget=bui.containerwidget(
 51                parent=bui.get_special_widget('overlay_stack'),
 52                size=(self._width, self._height),
 53                transition='in_scale',
 54                toolbar_visibility='menu_store',
 55                scale=(
 56                    1.2
 57                    if uiscale is bui.UIScale.SMALL
 58                    else 1.1 if uiscale is bui.UIScale.MEDIUM else 1.0
 59                ),
 60                scale_origin_stack_offset=scale_origin,
 61                stack_offset=(
 62                    (0, -15) if uiscale is bui.UIScale.SMALL else (0, 0)
 63                ),
 64            )
 65        )
 66        self._is_double = False
 67        self._title_text = bui.textwidget(
 68            parent=self._root_widget,
 69            position=(self._width * 0.5, self._height - 30),
 70            size=(0, 0),
 71            text=header_text,
 72            h_align='center',
 73            v_align='center',
 74            maxwidth=self._width * 0.9 - 120,
 75            scale=1.2,
 76            color=(1, 0.8, 0.3, 1),
 77        )
 78        size = store.get_store_item_display_size(items[0])
 79        display: dict[str, Any] = {}
 80        instantiate_store_item_display(
 81            items[0],
 82            display,
 83            parent_widget=self._root_widget,
 84            b_pos=(
 85                self._width * 0.5
 86                - size[0] * 0.5
 87                + 10
 88                - ((size[0] * 0.5 + 30) if self._is_double else 0),
 89                self._height * 0.5
 90                - size[1] * 0.5
 91                + 30
 92                + (20 if self._is_double else 0),
 93            ),
 94            b_width=size[0],
 95            b_height=size[1],
 96            button=False,
 97        )
 98
 99        # Wire up the parts we need.
100        if self._is_double:
101            pass  # not working
102        else:
103            if self._items == ['pro']:
104                price_str = plus.get_price(self._items[0])
105                pyoffs = -15
106            else:
107                pyoffs = 0
108                price = self._price = plus.get_v1_account_misc_read_val(
109                    'price.' + str(items[0]), -1
110                )
111                price_str = bui.charstr(bui.SpecialChar.TICKET) + str(price)
112            self._price_text = bui.textwidget(
113                parent=self._root_widget,
114                position=(self._width * 0.5, 150 + pyoffs),
115                size=(0, 0),
116                text=price_str,
117                h_align='center',
118                v_align='center',
119                maxwidth=self._width * 0.9,
120                scale=1.4,
121                color=(0.2, 1, 0.2),
122            )
123
124        self._update_timer = bui.AppTimer(
125            1.0, bui.WeakCall(self._update), repeat=True
126        )
127
128        self._cancel_button = bui.buttonwidget(
129            parent=self._root_widget,
130            position=(50, 40),
131            size=(150, 60),
132            scale=1.0,
133            on_activate_call=self._cancel,
134            autoselect=True,
135            label=bui.Lstr(resource='cancelText'),
136        )
137        self._purchase_button = bui.buttonwidget(
138            parent=self._root_widget,
139            position=(self._width - 200, 40),
140            size=(150, 60),
141            scale=1.0,
142            on_activate_call=self._purchase,
143            autoselect=True,
144            label=bui.Lstr(resource='store.purchaseText'),
145        )
146
147        bui.containerwidget(
148            edit=self._root_widget,
149            cancel_button=self._cancel_button,
150            start_button=self._purchase_button,
151            selected_child=self._purchase_button,
152        )
153
154    def _update(self) -> None:
155        can_die = False
156
157        plus = bui.app.plus
158        assert plus is not None
159
160        # We go away if we see that our target item is owned.
161        if self._items == ['pro']:
162            assert bui.app.classic is not None
163            if bui.app.classic.accounts.have_pro():
164                can_die = True
165        else:
166            if plus.get_v1_account_product_purchased(self._items[0]):
167                can_die = True
168
169        if can_die:
170            bui.containerwidget(edit=self._root_widget, transition='out_scale')
171
172    def _purchase(self) -> None:
173
174        plus = bui.app.plus
175        assert plus is not None
176
177        if self._items == ['pro']:
178            plus.purchase('pro')
179        else:
180            ticket_count: int | None
181            try:
182                ticket_count = plus.get_v1_account_ticket_count()
183            except Exception:
184                ticket_count = None
185            if ticket_count is not None and ticket_count < self._price:
186                bui.getsound('error').play()
187                bui.screenmessage(
188                    bui.Lstr(resource='notEnoughTicketsText'),
189                    color=(1, 0, 0),
190                )
191                # gettickets.show_get_tickets_prompt()
192                return
193
194            def do_it() -> None:
195                assert plus is not None
196
197                plus.in_game_purchase(self._items[0], self._price)
198
199            bui.getsound('swish').play()
200            do_it()
201
202    def _cancel(self) -> None:
203        bui.containerwidget(edit=self._root_widget, transition='out_scale')
class PurchaseWindow(bauiv1._uitypes.Window):
 16class PurchaseWindow(bui.Window):
 17    """Window for purchasing one or more items."""
 18
 19    def __init__(
 20        self,
 21        items: list[str],
 22        origin_widget: bui.Widget | None = None,
 23        header_text: bui.Lstr | None = None,
 24    ):
 25        from bauiv1lib.store.item import instantiate_store_item_display
 26
 27        plus = bui.app.plus
 28        assert plus is not None
 29
 30        assert bui.app.classic is not None
 31        store = bui.app.classic.store
 32
 33        if header_text is None:
 34            header_text = bui.Lstr(
 35                resource='unlockThisText',
 36                fallback_resource='unlockThisInTheStoreText',
 37            )
 38        if len(items) != 1:
 39            raise ValueError('expected exactly 1 item')
 40        self._items = list(items)
 41        self._width = 580
 42        self._height = 520
 43        uiscale = bui.app.ui_v1.uiscale
 44
 45        if origin_widget is not None:
 46            scale_origin = origin_widget.get_screen_space_center()
 47        else:
 48            scale_origin = None
 49
 50        super().__init__(
 51            root_widget=bui.containerwidget(
 52                parent=bui.get_special_widget('overlay_stack'),
 53                size=(self._width, self._height),
 54                transition='in_scale',
 55                toolbar_visibility='menu_store',
 56                scale=(
 57                    1.2
 58                    if uiscale is bui.UIScale.SMALL
 59                    else 1.1 if uiscale is bui.UIScale.MEDIUM else 1.0
 60                ),
 61                scale_origin_stack_offset=scale_origin,
 62                stack_offset=(
 63                    (0, -15) if uiscale is bui.UIScale.SMALL else (0, 0)
 64                ),
 65            )
 66        )
 67        self._is_double = False
 68        self._title_text = bui.textwidget(
 69            parent=self._root_widget,
 70            position=(self._width * 0.5, self._height - 30),
 71            size=(0, 0),
 72            text=header_text,
 73            h_align='center',
 74            v_align='center',
 75            maxwidth=self._width * 0.9 - 120,
 76            scale=1.2,
 77            color=(1, 0.8, 0.3, 1),
 78        )
 79        size = store.get_store_item_display_size(items[0])
 80        display: dict[str, Any] = {}
 81        instantiate_store_item_display(
 82            items[0],
 83            display,
 84            parent_widget=self._root_widget,
 85            b_pos=(
 86                self._width * 0.5
 87                - size[0] * 0.5
 88                + 10
 89                - ((size[0] * 0.5 + 30) if self._is_double else 0),
 90                self._height * 0.5
 91                - size[1] * 0.5
 92                + 30
 93                + (20 if self._is_double else 0),
 94            ),
 95            b_width=size[0],
 96            b_height=size[1],
 97            button=False,
 98        )
 99
100        # Wire up the parts we need.
101        if self._is_double:
102            pass  # not working
103        else:
104            if self._items == ['pro']:
105                price_str = plus.get_price(self._items[0])
106                pyoffs = -15
107            else:
108                pyoffs = 0
109                price = self._price = plus.get_v1_account_misc_read_val(
110                    'price.' + str(items[0]), -1
111                )
112                price_str = bui.charstr(bui.SpecialChar.TICKET) + str(price)
113            self._price_text = bui.textwidget(
114                parent=self._root_widget,
115                position=(self._width * 0.5, 150 + pyoffs),
116                size=(0, 0),
117                text=price_str,
118                h_align='center',
119                v_align='center',
120                maxwidth=self._width * 0.9,
121                scale=1.4,
122                color=(0.2, 1, 0.2),
123            )
124
125        self._update_timer = bui.AppTimer(
126            1.0, bui.WeakCall(self._update), repeat=True
127        )
128
129        self._cancel_button = bui.buttonwidget(
130            parent=self._root_widget,
131            position=(50, 40),
132            size=(150, 60),
133            scale=1.0,
134            on_activate_call=self._cancel,
135            autoselect=True,
136            label=bui.Lstr(resource='cancelText'),
137        )
138        self._purchase_button = bui.buttonwidget(
139            parent=self._root_widget,
140            position=(self._width - 200, 40),
141            size=(150, 60),
142            scale=1.0,
143            on_activate_call=self._purchase,
144            autoselect=True,
145            label=bui.Lstr(resource='store.purchaseText'),
146        )
147
148        bui.containerwidget(
149            edit=self._root_widget,
150            cancel_button=self._cancel_button,
151            start_button=self._purchase_button,
152            selected_child=self._purchase_button,
153        )
154
155    def _update(self) -> None:
156        can_die = False
157
158        plus = bui.app.plus
159        assert plus is not None
160
161        # We go away if we see that our target item is owned.
162        if self._items == ['pro']:
163            assert bui.app.classic is not None
164            if bui.app.classic.accounts.have_pro():
165                can_die = True
166        else:
167            if plus.get_v1_account_product_purchased(self._items[0]):
168                can_die = True
169
170        if can_die:
171            bui.containerwidget(edit=self._root_widget, transition='out_scale')
172
173    def _purchase(self) -> None:
174
175        plus = bui.app.plus
176        assert plus is not None
177
178        if self._items == ['pro']:
179            plus.purchase('pro')
180        else:
181            ticket_count: int | None
182            try:
183                ticket_count = plus.get_v1_account_ticket_count()
184            except Exception:
185                ticket_count = None
186            if ticket_count is not None and ticket_count < self._price:
187                bui.getsound('error').play()
188                bui.screenmessage(
189                    bui.Lstr(resource='notEnoughTicketsText'),
190                    color=(1, 0, 0),
191                )
192                # gettickets.show_get_tickets_prompt()
193                return
194
195            def do_it() -> None:
196                assert plus is not None
197
198                plus.in_game_purchase(self._items[0], self._price)
199
200            bui.getsound('swish').play()
201            do_it()
202
203    def _cancel(self) -> None:
204        bui.containerwidget(edit=self._root_widget, transition='out_scale')

Window for purchasing one or more items.

PurchaseWindow( items: list[str], origin_widget: _bauiv1.Widget | None = None, header_text: babase.Lstr | None = None)
 19    def __init__(
 20        self,
 21        items: list[str],
 22        origin_widget: bui.Widget | None = None,
 23        header_text: bui.Lstr | None = None,
 24    ):
 25        from bauiv1lib.store.item import instantiate_store_item_display
 26
 27        plus = bui.app.plus
 28        assert plus is not None
 29
 30        assert bui.app.classic is not None
 31        store = bui.app.classic.store
 32
 33        if header_text is None:
 34            header_text = bui.Lstr(
 35                resource='unlockThisText',
 36                fallback_resource='unlockThisInTheStoreText',
 37            )
 38        if len(items) != 1:
 39            raise ValueError('expected exactly 1 item')
 40        self._items = list(items)
 41        self._width = 580
 42        self._height = 520
 43        uiscale = bui.app.ui_v1.uiscale
 44
 45        if origin_widget is not None:
 46            scale_origin = origin_widget.get_screen_space_center()
 47        else:
 48            scale_origin = None
 49
 50        super().__init__(
 51            root_widget=bui.containerwidget(
 52                parent=bui.get_special_widget('overlay_stack'),
 53                size=(self._width, self._height),
 54                transition='in_scale',
 55                toolbar_visibility='menu_store',
 56                scale=(
 57                    1.2
 58                    if uiscale is bui.UIScale.SMALL
 59                    else 1.1 if uiscale is bui.UIScale.MEDIUM else 1.0
 60                ),
 61                scale_origin_stack_offset=scale_origin,
 62                stack_offset=(
 63                    (0, -15) if uiscale is bui.UIScale.SMALL else (0, 0)
 64                ),
 65            )
 66        )
 67        self._is_double = False
 68        self._title_text = bui.textwidget(
 69            parent=self._root_widget,
 70            position=(self._width * 0.5, self._height - 30),
 71            size=(0, 0),
 72            text=header_text,
 73            h_align='center',
 74            v_align='center',
 75            maxwidth=self._width * 0.9 - 120,
 76            scale=1.2,
 77            color=(1, 0.8, 0.3, 1),
 78        )
 79        size = store.get_store_item_display_size(items[0])
 80        display: dict[str, Any] = {}
 81        instantiate_store_item_display(
 82            items[0],
 83            display,
 84            parent_widget=self._root_widget,
 85            b_pos=(
 86                self._width * 0.5
 87                - size[0] * 0.5
 88                + 10
 89                - ((size[0] * 0.5 + 30) if self._is_double else 0),
 90                self._height * 0.5
 91                - size[1] * 0.5
 92                + 30
 93                + (20 if self._is_double else 0),
 94            ),
 95            b_width=size[0],
 96            b_height=size[1],
 97            button=False,
 98        )
 99
100        # Wire up the parts we need.
101        if self._is_double:
102            pass  # not working
103        else:
104            if self._items == ['pro']:
105                price_str = plus.get_price(self._items[0])
106                pyoffs = -15
107            else:
108                pyoffs = 0
109                price = self._price = plus.get_v1_account_misc_read_val(
110                    'price.' + str(items[0]), -1
111                )
112                price_str = bui.charstr(bui.SpecialChar.TICKET) + str(price)
113            self._price_text = bui.textwidget(
114                parent=self._root_widget,
115                position=(self._width * 0.5, 150 + pyoffs),
116                size=(0, 0),
117                text=price_str,
118                h_align='center',
119                v_align='center',
120                maxwidth=self._width * 0.9,
121                scale=1.4,
122                color=(0.2, 1, 0.2),
123            )
124
125        self._update_timer = bui.AppTimer(
126            1.0, bui.WeakCall(self._update), repeat=True
127        )
128
129        self._cancel_button = bui.buttonwidget(
130            parent=self._root_widget,
131            position=(50, 40),
132            size=(150, 60),
133            scale=1.0,
134            on_activate_call=self._cancel,
135            autoselect=True,
136            label=bui.Lstr(resource='cancelText'),
137        )
138        self._purchase_button = bui.buttonwidget(
139            parent=self._root_widget,
140            position=(self._width - 200, 40),
141            size=(150, 60),
142            scale=1.0,
143            on_activate_call=self._purchase,
144            autoselect=True,
145            label=bui.Lstr(resource='store.purchaseText'),
146        )
147
148        bui.containerwidget(
149            edit=self._root_widget,
150            cancel_button=self._cancel_button,
151            start_button=self._purchase_button,
152            selected_child=self._purchase_button,
153        )