Source code for bauiv1lib.profile.upgrade

# Released under the MIT License. See LICENSE for details.
#
"""UI for player profile upgrades."""

from __future__ import annotations

import time
import weakref
from typing import TYPE_CHECKING

import bauiv1 as bui

if TYPE_CHECKING:
    from typing import Any

    from bauiv1lib.profile.edit import EditProfileWindow


[docs] class ProfileUpgradeWindow(bui.Window): """Window for player profile upgrades to global.""" def __init__( self, edit_profile_window: EditProfileWindow, transition: str = 'in_right', ): if bui.app.classic is None: raise RuntimeError('This requires classic.') plus = bui.app.plus assert plus is not None self._r = 'editProfileWindow' uiscale = bui.app.ui_v1.uiscale self._width = 750 if uiscale is bui.UIScale.SMALL else 680 self._height = 450 if uiscale is bui.UIScale.SMALL else 350 assert bui.app.classic is not None self._base_scale = ( 1.92 if uiscale is bui.UIScale.SMALL else 1.5 if uiscale is bui.UIScale.MEDIUM else 1.2 ) yoffs = -60.0 if uiscale is bui.UIScale.SMALL else 0 self._upgrade_start_time: float | None = None self._name = edit_profile_window.getname() self._edit_profile_window = weakref.ref(edit_profile_window) top_extra = 15 if uiscale is bui.UIScale.SMALL else 15 super().__init__( root_widget=bui.containerwidget( size=(self._width, self._height + top_extra), toolbar_visibility='menu_store_no_back', transition=transition, scale=self._base_scale, stack_offset=( (0, 0) if uiscale is bui.UIScale.SMALL else (0, 0) ), ) ) cancel_button = bui.buttonwidget( parent=self._root_widget, position=(52, self._height - 290 + yoffs), size=(155, 60), scale=0.8, autoselect=True, label=bui.Lstr(resource='cancelText'), on_activate_call=self._cancel, ) self._upgrade_button = bui.buttonwidget( parent=self._root_widget, position=(self._width - 190, self._height - 290 + yoffs), size=(155, 60), scale=0.8, autoselect=True, label=bui.Lstr(resource='upgradeText'), on_activate_call=self._on_upgrade_press, ) bui.containerwidget( edit=self._root_widget, cancel_button=cancel_button, start_button=self._upgrade_button, selected_child=self._upgrade_button, ) assert bui.app.classic is not None bui.textwidget( parent=self._root_widget, position=(self._width * 0.5, self._height - 38 + yoffs), size=(0, 0), text=bui.Lstr(resource=f'{self._r}.upgradeToGlobalProfileText'), color=bui.app.ui_v1.title_color, maxwidth=self._width * 0.45, scale=1.0, h_align='center', v_align='center', ) assert bui.app.classic is not None bui.textwidget( parent=self._root_widget, position=(self._width * 0.5, self._height - 100 + yoffs), size=(0, 0), text=bui.Lstr(resource=f'{self._r}.upgradeProfileInfoText'), color=bui.app.ui_v1.infotextcolor, maxwidth=self._width * 0.8, scale=0.7, h_align='center', v_align='center', ) self._status_text = bui.textwidget( parent=self._root_widget, position=(self._width * 0.5, self._height - 160 + yoffs), size=(0, 0), text=bui.Lstr( resource=f'{self._r}.checkingAvailabilityText', subs=[('${NAME}', self._name)], ), color=(0.8, 0.4, 0.0), maxwidth=self._width * 0.8, scale=0.65, h_align='center', v_align='center', ) self._price_text = bui.textwidget( parent=self._root_widget, position=(self._width * 0.5, self._height - 230 + yoffs), size=(0, 0), text='', color=(0.2, 1, 0.2), maxwidth=self._width * 0.8, scale=1.5, h_align='center', v_align='center', ) bui.app.classic.master_server_v1_get( 'bsGlobalProfileCheck', {'name': self._name, 'b': bui.app.env.engine_build_number}, callback=bui.WeakCall(self._profile_check_result), ) self._cost = plus.get_v1_account_misc_read_val( 'price.global_profile', 500 ) self._status: str | None = 'waiting' self._update_timer = bui.AppTimer( 1.023, bui.WeakCall(self._update), repeat=True ) self._update() def _profile_check_result(self, result: dict[str, Any] | None) -> None: if result is None: bui.textwidget( edit=self._status_text, text=bui.Lstr(resource='internal.unavailableNoConnectionText'), color=(1, 0, 0), ) self._status = 'error' bui.buttonwidget( edit=self._upgrade_button, color=(0.4, 0.4, 0.4), textcolor=(0.5, 0.5, 0.5), ) else: if result['available']: bui.textwidget( edit=self._status_text, text=bui.Lstr( resource=f'{self._r}.availableText', subs=[('${NAME}', self._name)], ), color=(0, 1, 0), ) bui.textwidget( edit=self._price_text, text=bui.charstr(bui.SpecialChar.TICKET) + str(self._cost), ) self._status = None else: bui.textwidget( edit=self._status_text, text=bui.Lstr( resource=f'{self._r}.unavailableText', subs=[('${NAME}', self._name)], ), color=(1, 0, 0), ) self._status = 'unavailable' bui.buttonwidget( edit=self._upgrade_button, color=(0.4, 0.4, 0.4), textcolor=(0.5, 0.5, 0.5), ) def _on_upgrade_press(self) -> None: # from bauiv1lib import gettickets if self._status is None: plus = bui.app.plus assert plus is not None # If it appears we don't have enough tickets, offer to buy more. tickets = plus.get_v1_account_ticket_count() if tickets < self._cost: bui.getsound('error').play() bui.screenmessage( bui.Lstr(resource='notEnoughTicketsText'), color=(1, 0, 0), ) # gettickets.show_get_tickets_prompt() return bui.screenmessage( bui.Lstr(resource='purchasingText'), color=(0, 1, 0) ) self._status = 'pre_upgrading' # Now we tell the original editor to save the profile, add an # upgrade transaction, and then sit and wait for everything to # go through. edit_profile_window = self._edit_profile_window() if edit_profile_window is None: print('profile upgrade: original edit window gone') return success = edit_profile_window.save(transition_out=False) if not success: print('profile upgrade: error occurred saving profile') bui.screenmessage( bui.Lstr(resource='errorText'), color=(1, 0, 0) ) bui.getsound('error').play() return plus.add_v1_account_transaction( {'type': 'UPGRADE_PROFILE', 'name': self._name} ) plus.run_v1_account_transactions() self._status = 'upgrading' self._upgrade_start_time = time.time() else: bui.getsound('error').play() def _update(self) -> None: plus = bui.app.plus assert plus is not None # If our originating window dies at any point, cancel. edit_profile_window = self._edit_profile_window() if edit_profile_window is None: self._cancel() return # Once we've kicked off an upgrade attempt and all transactions go # through, we're done. if ( self._status == 'upgrading' and not plus.have_outstanding_v1_account_transactions() ): self._status = 'exiting' bui.containerwidget(edit=self._root_widget, transition='out_right') edit_profile_window = self._edit_profile_window() if edit_profile_window is None: print( 'profile upgrade transition out:' ' original edit window gone' ) return bui.getsound('gunCocking').play() edit_profile_window.reload_window() def _cancel(self) -> None: # If we recently sent out an upgrade request, disallow canceling # for a bit. if ( self._upgrade_start_time is not None and time.time() - self._upgrade_start_time < 10.0 ): bui.getsound('error').play() return bui.containerwidget(edit=self._root_widget, transition='out_right')
# Docs-generation hack; import some stuff that we likely only forward-declared # in our actual source code so that docs tools can find it. from typing import (Coroutine, Any, Literal, Callable, Generator, Awaitable, Sequence, Self) import asyncio from concurrent.futures import Future from pathlib import Path from enum import Enum