bauiv1lib.profile.upgrade
UI for player profile upgrades.
1# Released under the MIT License. See LICENSE for details. 2# 3"""UI for player profile upgrades.""" 4 5from __future__ import annotations 6 7import time 8import weakref 9from typing import TYPE_CHECKING 10 11import bauiv1 as bui 12 13if TYPE_CHECKING: 14 from typing import Any 15 16 from bauiv1lib.profile.edit import EditProfileWindow 17 18 19class ProfileUpgradeWindow(bui.Window): 20 """Window for player profile upgrades to global.""" 21 22 def __init__( 23 self, 24 edit_profile_window: EditProfileWindow, 25 transition: str = 'in_right', 26 ): 27 if bui.app.classic is None: 28 raise RuntimeError('This requires classic.') 29 30 plus = bui.app.plus 31 assert plus is not None 32 33 self._r = 'editProfileWindow' 34 35 uiscale = bui.app.ui_v1.uiscale 36 self._width = 750 if uiscale is bui.UIScale.SMALL else 680 37 self._height = 450 if uiscale is bui.UIScale.SMALL else 350 38 assert bui.app.classic is not None 39 self._base_scale = ( 40 1.9 41 if uiscale is bui.UIScale.SMALL 42 else 1.5 if uiscale is bui.UIScale.MEDIUM else 1.2 43 ) 44 yoffs = -60.0 if uiscale is bui.UIScale.SMALL else 0 45 self._upgrade_start_time: float | None = None 46 self._name = edit_profile_window.getname() 47 self._edit_profile_window = weakref.ref(edit_profile_window) 48 49 top_extra = 15 if uiscale is bui.UIScale.SMALL else 15 50 super().__init__( 51 root_widget=bui.containerwidget( 52 size=(self._width, self._height + top_extra), 53 toolbar_visibility='menu_store_no_back', 54 transition=transition, 55 scale=self._base_scale, 56 stack_offset=( 57 (0, 0) if uiscale is bui.UIScale.SMALL else (0, 0) 58 ), 59 ) 60 ) 61 cancel_button = bui.buttonwidget( 62 parent=self._root_widget, 63 position=(52, self._height - 290 + yoffs), 64 size=(155, 60), 65 scale=0.8, 66 autoselect=True, 67 label=bui.Lstr(resource='cancelText'), 68 on_activate_call=self._cancel, 69 ) 70 self._upgrade_button = bui.buttonwidget( 71 parent=self._root_widget, 72 position=(self._width - 190, self._height - 290 + yoffs), 73 size=(155, 60), 74 scale=0.8, 75 autoselect=True, 76 label=bui.Lstr(resource='upgradeText'), 77 on_activate_call=self._on_upgrade_press, 78 ) 79 bui.containerwidget( 80 edit=self._root_widget, 81 cancel_button=cancel_button, 82 start_button=self._upgrade_button, 83 selected_child=self._upgrade_button, 84 ) 85 86 assert bui.app.classic is not None 87 bui.textwidget( 88 parent=self._root_widget, 89 position=(self._width * 0.5, self._height - 38 + yoffs), 90 size=(0, 0), 91 text=bui.Lstr(resource=f'{self._r}.upgradeToGlobalProfileText'), 92 color=bui.app.ui_v1.title_color, 93 maxwidth=self._width * 0.45, 94 scale=1.0, 95 h_align='center', 96 v_align='center', 97 ) 98 99 assert bui.app.classic is not None 100 bui.textwidget( 101 parent=self._root_widget, 102 position=(self._width * 0.5, self._height - 100 + yoffs), 103 size=(0, 0), 104 text=bui.Lstr(resource=f'{self._r}.upgradeProfileInfoText'), 105 color=bui.app.ui_v1.infotextcolor, 106 maxwidth=self._width * 0.8, 107 scale=0.7, 108 h_align='center', 109 v_align='center', 110 ) 111 112 self._status_text = bui.textwidget( 113 parent=self._root_widget, 114 position=(self._width * 0.5, self._height - 160 + yoffs), 115 size=(0, 0), 116 text=bui.Lstr( 117 resource=f'{self._r}.checkingAvailabilityText', 118 subs=[('${NAME}', self._name)], 119 ), 120 color=(0.8, 0.4, 0.0), 121 maxwidth=self._width * 0.8, 122 scale=0.65, 123 h_align='center', 124 v_align='center', 125 ) 126 127 self._price_text = bui.textwidget( 128 parent=self._root_widget, 129 position=(self._width * 0.5, self._height - 230 + yoffs), 130 size=(0, 0), 131 text='', 132 color=(0.2, 1, 0.2), 133 maxwidth=self._width * 0.8, 134 scale=1.5, 135 h_align='center', 136 v_align='center', 137 ) 138 139 bui.app.classic.master_server_v1_get( 140 'bsGlobalProfileCheck', 141 {'name': self._name, 'b': bui.app.env.engine_build_number}, 142 callback=bui.WeakCall(self._profile_check_result), 143 ) 144 self._cost = plus.get_v1_account_misc_read_val( 145 'price.global_profile', 500 146 ) 147 self._status: str | None = 'waiting' 148 self._update_timer = bui.AppTimer( 149 1.023, bui.WeakCall(self._update), repeat=True 150 ) 151 self._update() 152 153 def _profile_check_result(self, result: dict[str, Any] | None) -> None: 154 if result is None: 155 bui.textwidget( 156 edit=self._status_text, 157 text=bui.Lstr(resource='internal.unavailableNoConnectionText'), 158 color=(1, 0, 0), 159 ) 160 self._status = 'error' 161 bui.buttonwidget( 162 edit=self._upgrade_button, 163 color=(0.4, 0.4, 0.4), 164 textcolor=(0.5, 0.5, 0.5), 165 ) 166 else: 167 if result['available']: 168 bui.textwidget( 169 edit=self._status_text, 170 text=bui.Lstr( 171 resource=f'{self._r}.availableText', 172 subs=[('${NAME}', self._name)], 173 ), 174 color=(0, 1, 0), 175 ) 176 bui.textwidget( 177 edit=self._price_text, 178 text=bui.charstr(bui.SpecialChar.TICKET) + str(self._cost), 179 ) 180 self._status = None 181 else: 182 bui.textwidget( 183 edit=self._status_text, 184 text=bui.Lstr( 185 resource=f'{self._r}.unavailableText', 186 subs=[('${NAME}', self._name)], 187 ), 188 color=(1, 0, 0), 189 ) 190 self._status = 'unavailable' 191 bui.buttonwidget( 192 edit=self._upgrade_button, 193 color=(0.4, 0.4, 0.4), 194 textcolor=(0.5, 0.5, 0.5), 195 ) 196 197 def _on_upgrade_press(self) -> None: 198 # from bauiv1lib import gettickets 199 200 if self._status is None: 201 plus = bui.app.plus 202 assert plus is not None 203 204 # If it appears we don't have enough tickets, offer to buy more. 205 tickets = plus.get_v1_account_ticket_count() 206 if tickets < self._cost: 207 bui.getsound('error').play() 208 print('FIXME - show not-enough-tickets msg.') 209 # gettickets.show_get_tickets_prompt() 210 return 211 bui.screenmessage( 212 bui.Lstr(resource='purchasingText'), color=(0, 1, 0) 213 ) 214 self._status = 'pre_upgrading' 215 216 # Now we tell the original editor to save the profile, add an 217 # upgrade transaction, and then sit and wait for everything to 218 # go through. 219 edit_profile_window = self._edit_profile_window() 220 if edit_profile_window is None: 221 print('profile upgrade: original edit window gone') 222 return 223 success = edit_profile_window.save(transition_out=False) 224 if not success: 225 print('profile upgrade: error occurred saving profile') 226 bui.screenmessage( 227 bui.Lstr(resource='errorText'), color=(1, 0, 0) 228 ) 229 bui.getsound('error').play() 230 return 231 plus.add_v1_account_transaction( 232 {'type': 'UPGRADE_PROFILE', 'name': self._name} 233 ) 234 plus.run_v1_account_transactions() 235 self._status = 'upgrading' 236 self._upgrade_start_time = time.time() 237 else: 238 bui.getsound('error').play() 239 240 def _update(self) -> None: 241 plus = bui.app.plus 242 assert plus is not None 243 244 # If our originating window dies at any point, cancel. 245 edit_profile_window = self._edit_profile_window() 246 if edit_profile_window is None: 247 self._cancel() 248 return 249 250 # Once we've kicked off an upgrade attempt and all transactions go 251 # through, we're done. 252 if ( 253 self._status == 'upgrading' 254 and not plus.have_outstanding_v1_account_transactions() 255 ): 256 self._status = 'exiting' 257 bui.containerwidget(edit=self._root_widget, transition='out_right') 258 edit_profile_window = self._edit_profile_window() 259 if edit_profile_window is None: 260 print( 261 'profile upgrade transition out:' 262 ' original edit window gone' 263 ) 264 return 265 bui.getsound('gunCocking').play() 266 edit_profile_window.reload_window() 267 268 def _cancel(self) -> None: 269 # If we recently sent out an upgrade request, disallow canceling 270 # for a bit. 271 if ( 272 self._upgrade_start_time is not None 273 and time.time() - self._upgrade_start_time < 10.0 274 ): 275 bui.getsound('error').play() 276 return 277 bui.containerwidget(edit=self._root_widget, transition='out_right')
class
ProfileUpgradeWindow(bauiv1._uitypes.Window):
20class ProfileUpgradeWindow(bui.Window): 21 """Window for player profile upgrades to global.""" 22 23 def __init__( 24 self, 25 edit_profile_window: EditProfileWindow, 26 transition: str = 'in_right', 27 ): 28 if bui.app.classic is None: 29 raise RuntimeError('This requires classic.') 30 31 plus = bui.app.plus 32 assert plus is not None 33 34 self._r = 'editProfileWindow' 35 36 uiscale = bui.app.ui_v1.uiscale 37 self._width = 750 if uiscale is bui.UIScale.SMALL else 680 38 self._height = 450 if uiscale is bui.UIScale.SMALL else 350 39 assert bui.app.classic is not None 40 self._base_scale = ( 41 1.9 42 if uiscale is bui.UIScale.SMALL 43 else 1.5 if uiscale is bui.UIScale.MEDIUM else 1.2 44 ) 45 yoffs = -60.0 if uiscale is bui.UIScale.SMALL else 0 46 self._upgrade_start_time: float | None = None 47 self._name = edit_profile_window.getname() 48 self._edit_profile_window = weakref.ref(edit_profile_window) 49 50 top_extra = 15 if uiscale is bui.UIScale.SMALL else 15 51 super().__init__( 52 root_widget=bui.containerwidget( 53 size=(self._width, self._height + top_extra), 54 toolbar_visibility='menu_store_no_back', 55 transition=transition, 56 scale=self._base_scale, 57 stack_offset=( 58 (0, 0) if uiscale is bui.UIScale.SMALL else (0, 0) 59 ), 60 ) 61 ) 62 cancel_button = bui.buttonwidget( 63 parent=self._root_widget, 64 position=(52, self._height - 290 + yoffs), 65 size=(155, 60), 66 scale=0.8, 67 autoselect=True, 68 label=bui.Lstr(resource='cancelText'), 69 on_activate_call=self._cancel, 70 ) 71 self._upgrade_button = bui.buttonwidget( 72 parent=self._root_widget, 73 position=(self._width - 190, self._height - 290 + yoffs), 74 size=(155, 60), 75 scale=0.8, 76 autoselect=True, 77 label=bui.Lstr(resource='upgradeText'), 78 on_activate_call=self._on_upgrade_press, 79 ) 80 bui.containerwidget( 81 edit=self._root_widget, 82 cancel_button=cancel_button, 83 start_button=self._upgrade_button, 84 selected_child=self._upgrade_button, 85 ) 86 87 assert bui.app.classic is not None 88 bui.textwidget( 89 parent=self._root_widget, 90 position=(self._width * 0.5, self._height - 38 + yoffs), 91 size=(0, 0), 92 text=bui.Lstr(resource=f'{self._r}.upgradeToGlobalProfileText'), 93 color=bui.app.ui_v1.title_color, 94 maxwidth=self._width * 0.45, 95 scale=1.0, 96 h_align='center', 97 v_align='center', 98 ) 99 100 assert bui.app.classic is not None 101 bui.textwidget( 102 parent=self._root_widget, 103 position=(self._width * 0.5, self._height - 100 + yoffs), 104 size=(0, 0), 105 text=bui.Lstr(resource=f'{self._r}.upgradeProfileInfoText'), 106 color=bui.app.ui_v1.infotextcolor, 107 maxwidth=self._width * 0.8, 108 scale=0.7, 109 h_align='center', 110 v_align='center', 111 ) 112 113 self._status_text = bui.textwidget( 114 parent=self._root_widget, 115 position=(self._width * 0.5, self._height - 160 + yoffs), 116 size=(0, 0), 117 text=bui.Lstr( 118 resource=f'{self._r}.checkingAvailabilityText', 119 subs=[('${NAME}', self._name)], 120 ), 121 color=(0.8, 0.4, 0.0), 122 maxwidth=self._width * 0.8, 123 scale=0.65, 124 h_align='center', 125 v_align='center', 126 ) 127 128 self._price_text = bui.textwidget( 129 parent=self._root_widget, 130 position=(self._width * 0.5, self._height - 230 + yoffs), 131 size=(0, 0), 132 text='', 133 color=(0.2, 1, 0.2), 134 maxwidth=self._width * 0.8, 135 scale=1.5, 136 h_align='center', 137 v_align='center', 138 ) 139 140 bui.app.classic.master_server_v1_get( 141 'bsGlobalProfileCheck', 142 {'name': self._name, 'b': bui.app.env.engine_build_number}, 143 callback=bui.WeakCall(self._profile_check_result), 144 ) 145 self._cost = plus.get_v1_account_misc_read_val( 146 'price.global_profile', 500 147 ) 148 self._status: str | None = 'waiting' 149 self._update_timer = bui.AppTimer( 150 1.023, bui.WeakCall(self._update), repeat=True 151 ) 152 self._update() 153 154 def _profile_check_result(self, result: dict[str, Any] | None) -> None: 155 if result is None: 156 bui.textwidget( 157 edit=self._status_text, 158 text=bui.Lstr(resource='internal.unavailableNoConnectionText'), 159 color=(1, 0, 0), 160 ) 161 self._status = 'error' 162 bui.buttonwidget( 163 edit=self._upgrade_button, 164 color=(0.4, 0.4, 0.4), 165 textcolor=(0.5, 0.5, 0.5), 166 ) 167 else: 168 if result['available']: 169 bui.textwidget( 170 edit=self._status_text, 171 text=bui.Lstr( 172 resource=f'{self._r}.availableText', 173 subs=[('${NAME}', self._name)], 174 ), 175 color=(0, 1, 0), 176 ) 177 bui.textwidget( 178 edit=self._price_text, 179 text=bui.charstr(bui.SpecialChar.TICKET) + str(self._cost), 180 ) 181 self._status = None 182 else: 183 bui.textwidget( 184 edit=self._status_text, 185 text=bui.Lstr( 186 resource=f'{self._r}.unavailableText', 187 subs=[('${NAME}', self._name)], 188 ), 189 color=(1, 0, 0), 190 ) 191 self._status = 'unavailable' 192 bui.buttonwidget( 193 edit=self._upgrade_button, 194 color=(0.4, 0.4, 0.4), 195 textcolor=(0.5, 0.5, 0.5), 196 ) 197 198 def _on_upgrade_press(self) -> None: 199 # from bauiv1lib import gettickets 200 201 if self._status is None: 202 plus = bui.app.plus 203 assert plus is not None 204 205 # If it appears we don't have enough tickets, offer to buy more. 206 tickets = plus.get_v1_account_ticket_count() 207 if tickets < self._cost: 208 bui.getsound('error').play() 209 print('FIXME - show not-enough-tickets msg.') 210 # gettickets.show_get_tickets_prompt() 211 return 212 bui.screenmessage( 213 bui.Lstr(resource='purchasingText'), color=(0, 1, 0) 214 ) 215 self._status = 'pre_upgrading' 216 217 # Now we tell the original editor to save the profile, add an 218 # upgrade transaction, and then sit and wait for everything to 219 # go through. 220 edit_profile_window = self._edit_profile_window() 221 if edit_profile_window is None: 222 print('profile upgrade: original edit window gone') 223 return 224 success = edit_profile_window.save(transition_out=False) 225 if not success: 226 print('profile upgrade: error occurred saving profile') 227 bui.screenmessage( 228 bui.Lstr(resource='errorText'), color=(1, 0, 0) 229 ) 230 bui.getsound('error').play() 231 return 232 plus.add_v1_account_transaction( 233 {'type': 'UPGRADE_PROFILE', 'name': self._name} 234 ) 235 plus.run_v1_account_transactions() 236 self._status = 'upgrading' 237 self._upgrade_start_time = time.time() 238 else: 239 bui.getsound('error').play() 240 241 def _update(self) -> None: 242 plus = bui.app.plus 243 assert plus is not None 244 245 # If our originating window dies at any point, cancel. 246 edit_profile_window = self._edit_profile_window() 247 if edit_profile_window is None: 248 self._cancel() 249 return 250 251 # Once we've kicked off an upgrade attempt and all transactions go 252 # through, we're done. 253 if ( 254 self._status == 'upgrading' 255 and not plus.have_outstanding_v1_account_transactions() 256 ): 257 self._status = 'exiting' 258 bui.containerwidget(edit=self._root_widget, transition='out_right') 259 edit_profile_window = self._edit_profile_window() 260 if edit_profile_window is None: 261 print( 262 'profile upgrade transition out:' 263 ' original edit window gone' 264 ) 265 return 266 bui.getsound('gunCocking').play() 267 edit_profile_window.reload_window() 268 269 def _cancel(self) -> None: 270 # If we recently sent out an upgrade request, disallow canceling 271 # for a bit. 272 if ( 273 self._upgrade_start_time is not None 274 and time.time() - self._upgrade_start_time < 10.0 275 ): 276 bui.getsound('error').play() 277 return 278 bui.containerwidget(edit=self._root_widget, transition='out_right')
Window for player profile upgrades to global.
ProfileUpgradeWindow( edit_profile_window: bauiv1lib.profile.edit.EditProfileWindow, transition: str = 'in_right')
23 def __init__( 24 self, 25 edit_profile_window: EditProfileWindow, 26 transition: str = 'in_right', 27 ): 28 if bui.app.classic is None: 29 raise RuntimeError('This requires classic.') 30 31 plus = bui.app.plus 32 assert plus is not None 33 34 self._r = 'editProfileWindow' 35 36 uiscale = bui.app.ui_v1.uiscale 37 self._width = 750 if uiscale is bui.UIScale.SMALL else 680 38 self._height = 450 if uiscale is bui.UIScale.SMALL else 350 39 assert bui.app.classic is not None 40 self._base_scale = ( 41 1.9 42 if uiscale is bui.UIScale.SMALL 43 else 1.5 if uiscale is bui.UIScale.MEDIUM else 1.2 44 ) 45 yoffs = -60.0 if uiscale is bui.UIScale.SMALL else 0 46 self._upgrade_start_time: float | None = None 47 self._name = edit_profile_window.getname() 48 self._edit_profile_window = weakref.ref(edit_profile_window) 49 50 top_extra = 15 if uiscale is bui.UIScale.SMALL else 15 51 super().__init__( 52 root_widget=bui.containerwidget( 53 size=(self._width, self._height + top_extra), 54 toolbar_visibility='menu_store_no_back', 55 transition=transition, 56 scale=self._base_scale, 57 stack_offset=( 58 (0, 0) if uiscale is bui.UIScale.SMALL else (0, 0) 59 ), 60 ) 61 ) 62 cancel_button = bui.buttonwidget( 63 parent=self._root_widget, 64 position=(52, self._height - 290 + yoffs), 65 size=(155, 60), 66 scale=0.8, 67 autoselect=True, 68 label=bui.Lstr(resource='cancelText'), 69 on_activate_call=self._cancel, 70 ) 71 self._upgrade_button = bui.buttonwidget( 72 parent=self._root_widget, 73 position=(self._width - 190, self._height - 290 + yoffs), 74 size=(155, 60), 75 scale=0.8, 76 autoselect=True, 77 label=bui.Lstr(resource='upgradeText'), 78 on_activate_call=self._on_upgrade_press, 79 ) 80 bui.containerwidget( 81 edit=self._root_widget, 82 cancel_button=cancel_button, 83 start_button=self._upgrade_button, 84 selected_child=self._upgrade_button, 85 ) 86 87 assert bui.app.classic is not None 88 bui.textwidget( 89 parent=self._root_widget, 90 position=(self._width * 0.5, self._height - 38 + yoffs), 91 size=(0, 0), 92 text=bui.Lstr(resource=f'{self._r}.upgradeToGlobalProfileText'), 93 color=bui.app.ui_v1.title_color, 94 maxwidth=self._width * 0.45, 95 scale=1.0, 96 h_align='center', 97 v_align='center', 98 ) 99 100 assert bui.app.classic is not None 101 bui.textwidget( 102 parent=self._root_widget, 103 position=(self._width * 0.5, self._height - 100 + yoffs), 104 size=(0, 0), 105 text=bui.Lstr(resource=f'{self._r}.upgradeProfileInfoText'), 106 color=bui.app.ui_v1.infotextcolor, 107 maxwidth=self._width * 0.8, 108 scale=0.7, 109 h_align='center', 110 v_align='center', 111 ) 112 113 self._status_text = bui.textwidget( 114 parent=self._root_widget, 115 position=(self._width * 0.5, self._height - 160 + yoffs), 116 size=(0, 0), 117 text=bui.Lstr( 118 resource=f'{self._r}.checkingAvailabilityText', 119 subs=[('${NAME}', self._name)], 120 ), 121 color=(0.8, 0.4, 0.0), 122 maxwidth=self._width * 0.8, 123 scale=0.65, 124 h_align='center', 125 v_align='center', 126 ) 127 128 self._price_text = bui.textwidget( 129 parent=self._root_widget, 130 position=(self._width * 0.5, self._height - 230 + yoffs), 131 size=(0, 0), 132 text='', 133 color=(0.2, 1, 0.2), 134 maxwidth=self._width * 0.8, 135 scale=1.5, 136 h_align='center', 137 v_align='center', 138 ) 139 140 bui.app.classic.master_server_v1_get( 141 'bsGlobalProfileCheck', 142 {'name': self._name, 'b': bui.app.env.engine_build_number}, 143 callback=bui.WeakCall(self._profile_check_result), 144 ) 145 self._cost = plus.get_v1_account_misc_read_val( 146 'price.global_profile', 500 147 ) 148 self._status: str | None = 'waiting' 149 self._update_timer = bui.AppTimer( 150 1.023, bui.WeakCall(self._update), repeat=True 151 ) 152 self._update()