bastd.ui.league.rankwindow
UI related to league rank.
1# Released under the MIT License. See LICENSE for details. 2# 3"""UI related to league rank.""" 4# pylint: disable=too-many-lines 5 6from __future__ import annotations 7 8import copy 9from typing import TYPE_CHECKING 10 11import ba 12import ba.internal 13from bastd.ui import popup as popup_ui 14 15if TYPE_CHECKING: 16 from typing import Any 17 18 19class LeagueRankWindow(ba.Window): 20 """Window for showing league rank.""" 21 22 def __init__( 23 self, 24 transition: str = 'in_right', 25 modal: bool = False, 26 origin_widget: ba.Widget | None = None, 27 ): 28 ba.set_analytics_screen('League Rank Window') 29 30 self._league_rank_data: dict[str, Any] | None = None 31 self._modal = modal 32 33 # If they provided an origin-widget, scale up from that. 34 scale_origin: tuple[float, float] | None 35 if origin_widget is not None: 36 self._transition_out = 'out_scale' 37 scale_origin = origin_widget.get_screen_space_center() 38 transition = 'in_scale' 39 else: 40 self._transition_out = 'out_right' 41 scale_origin = None 42 43 uiscale = ba.app.ui.uiscale 44 self._width = 1320 if uiscale is ba.UIScale.SMALL else 1120 45 x_inset = 100 if uiscale is ba.UIScale.SMALL else 0 46 self._height = ( 47 657 48 if uiscale is ba.UIScale.SMALL 49 else 710 50 if uiscale is ba.UIScale.MEDIUM 51 else 800 52 ) 53 self._r = 'coopSelectWindow' 54 self._rdict = ba.app.lang.get_resource(self._r) 55 top_extra = 20 if uiscale is ba.UIScale.SMALL else 0 56 57 self._league_url_arg = '' 58 59 self._is_current_season = False 60 self._can_do_more_button = True 61 62 super().__init__( 63 root_widget=ba.containerwidget( 64 size=(self._width, self._height + top_extra), 65 stack_offset=(0, -15) 66 if uiscale is ba.UIScale.SMALL 67 else (0, 10) 68 if uiscale is ba.UIScale.MEDIUM 69 else (0, 0), 70 transition=transition, 71 scale_origin_stack_offset=scale_origin, 72 scale=( 73 1.2 74 if uiscale is ba.UIScale.SMALL 75 else 0.93 76 if uiscale is ba.UIScale.MEDIUM 77 else 0.8 78 ), 79 ) 80 ) 81 82 self._back_button = btn = ba.buttonwidget( 83 parent=self._root_widget, 84 position=( 85 75 + x_inset, 86 self._height - 87 - (4 if uiscale is ba.UIScale.SMALL else 0), 87 ), 88 size=(120, 60), 89 scale=1.2, 90 autoselect=True, 91 label=ba.Lstr(resource='doneText' if self._modal else 'backText'), 92 button_type=None if self._modal else 'back', 93 on_activate_call=self._back, 94 ) 95 96 self._title_text = ba.textwidget( 97 parent=self._root_widget, 98 position=(self._width * 0.5, self._height - 56), 99 size=(0, 0), 100 text=ba.Lstr( 101 resource='league.leagueRankText', 102 fallback_resource='coopSelectWindow.powerRankingText', 103 ), 104 h_align='center', 105 color=ba.app.ui.title_color, 106 scale=1.4, 107 maxwidth=600, 108 v_align='center', 109 ) 110 111 ba.buttonwidget( 112 edit=btn, 113 button_type='backSmall', 114 position=( 115 75 + x_inset, 116 self._height - 87 - (2 if uiscale is ba.UIScale.SMALL else 0), 117 ), 118 size=(60, 55), 119 label=ba.charstr(ba.SpecialChar.BACK), 120 ) 121 122 self._scroll_width = self._width - (130 + 2 * x_inset) 123 self._scroll_height = self._height - 160 124 self._scrollwidget = ba.scrollwidget( 125 parent=self._root_widget, 126 highlight=False, 127 position=(65 + x_inset, 70), 128 size=(self._scroll_width, self._scroll_height), 129 center_small_content=True, 130 ) 131 ba.widget(edit=self._scrollwidget, autoselect=True) 132 ba.containerwidget(edit=self._scrollwidget, claims_left_right=True) 133 ba.containerwidget( 134 edit=self._root_widget, 135 cancel_button=self._back_button, 136 selected_child=self._back_button, 137 ) 138 139 self._last_power_ranking_query_time: float | None = None 140 self._doing_power_ranking_query = False 141 142 self._subcontainer: ba.Widget | None = None 143 self._subcontainerwidth = 800 144 self._subcontainerheight = 483 145 self._power_ranking_score_widgets: list[ba.Widget] = [] 146 147 self._season_popup_menu: popup_ui.PopupMenu | None = None 148 self._requested_season: str | None = None 149 self._season: str | None = None 150 151 # take note of our account state; we'll refresh later if this changes 152 self._account_state = ba.internal.get_v1_account_state() 153 154 self._refresh() 155 self._restore_state() 156 157 # if we've got cached power-ranking data already, display it 158 info = ba.app.accounts_v1.get_cached_league_rank_data() 159 if info is not None: 160 self._update_for_league_rank_data(info) 161 162 self._update_timer = ba.Timer( 163 1.0, 164 ba.WeakCall(self._update), 165 timetype=ba.TimeType.REAL, 166 repeat=True, 167 ) 168 self._update(show=(info is None)) 169 170 def _on_achievements_press(self) -> None: 171 from bastd.ui import achievements 172 173 # only allow this for all-time or the current season 174 # (we currently don't keep specific achievement data for old seasons) 175 if self._season == 'a' or self._is_current_season: 176 prab = self._power_ranking_achievements_button 177 achievements.AchievementsWindow( 178 position=prab.get_screen_space_center() 179 ) 180 else: 181 ba.screenmessage( 182 ba.Lstr( 183 resource='achievementsUnavailableForOldSeasonsText', 184 fallback_resource='unavailableText', 185 ), 186 color=(1, 0, 0), 187 ) 188 ba.playsound(ba.getsound('error')) 189 190 def _on_activity_mult_press(self) -> None: 191 from bastd.ui import confirm 192 193 txt = ba.Lstr( 194 resource='coopSelectWindow.activenessAllTimeInfoText' 195 if self._season == 'a' 196 else 'coopSelectWindow.activenessInfoText', 197 subs=[ 198 ( 199 '${MAX}', 200 str( 201 ba.internal.get_v1_account_misc_read_val( 202 'activenessMax', 1.0 203 ) 204 ), 205 ) 206 ], 207 ) 208 confirm.ConfirmWindow( 209 txt, 210 cancel_button=False, 211 width=460, 212 height=150, 213 origin_widget=self._activity_mult_button, 214 ) 215 216 def _on_pro_mult_press(self) -> None: 217 from bastd.ui import confirm 218 219 txt = ba.Lstr( 220 resource='coopSelectWindow.proMultInfoText', 221 subs=[ 222 ( 223 '${PERCENT}', 224 str( 225 ba.internal.get_v1_account_misc_read_val( 226 'proPowerRankingBoost', 10 227 ) 228 ), 229 ), 230 ( 231 '${PRO}', 232 ba.Lstr( 233 resource='store.bombSquadProNameText', 234 subs=[('${APP_NAME}', ba.Lstr(resource='titleText'))], 235 ), 236 ), 237 ], 238 ) 239 confirm.ConfirmWindow( 240 txt, 241 cancel_button=False, 242 width=460, 243 height=130, 244 origin_widget=self._pro_mult_button, 245 ) 246 247 def _on_trophies_press(self) -> None: 248 from bastd.ui.trophies import TrophiesWindow 249 250 info = self._league_rank_data 251 if info is not None: 252 prtb = self._power_ranking_trophies_button 253 TrophiesWindow( 254 position=prtb.get_screen_space_center(), 255 data=info, 256 ) 257 else: 258 ba.playsound(ba.getsound('error')) 259 260 def _on_power_ranking_query_response( 261 self, data: dict[str, Any] | None 262 ) -> None: 263 self._doing_power_ranking_query = False 264 # important: *only* cache this if we requested the current season.. 265 if data is not None and data.get('s', None) is None: 266 ba.app.accounts_v1.cache_league_rank_data(data) 267 # always store a copy locally though (even for other seasons) 268 self._league_rank_data = copy.deepcopy(data) 269 self._update_for_league_rank_data(data) 270 271 def _restore_state(self) -> None: 272 pass 273 274 def _update(self, show: bool = False) -> None: 275 276 cur_time = ba.time(ba.TimeType.REAL) 277 278 # if our account state has changed, refresh our UI 279 account_state = ba.internal.get_v1_account_state() 280 if account_state != self._account_state: 281 self._account_state = account_state 282 self._save_state() 283 self._refresh() 284 285 # and power ranking too... 286 if not self._doing_power_ranking_query: 287 self._last_power_ranking_query_time = None 288 289 # send off a new power-ranking query if its been long enough or our 290 # requested season has changed or whatnot.. 291 if not self._doing_power_ranking_query and ( 292 self._last_power_ranking_query_time is None 293 or cur_time - self._last_power_ranking_query_time > 30.0 294 ): 295 try: 296 if show: 297 ba.textwidget(edit=self._league_title_text, text='') 298 ba.textwidget(edit=self._league_text, text='') 299 ba.textwidget(edit=self._league_number_text, text='') 300 ba.textwidget( 301 edit=self._your_power_ranking_text, 302 text=ba.Lstr( 303 value='${A}...', 304 subs=[('${A}', ba.Lstr(resource='loadingText'))], 305 ), 306 ) 307 ba.textwidget(edit=self._to_ranked_text, text='') 308 ba.textwidget(edit=self._power_ranking_rank_text, text='') 309 ba.textwidget(edit=self._season_ends_text, text='') 310 ba.textwidget(edit=self._trophy_counts_reset_text, text='') 311 except Exception: 312 ba.print_exception('Error showing updated rank info.') 313 314 self._last_power_ranking_query_time = cur_time 315 self._doing_power_ranking_query = True 316 ba.internal.power_ranking_query( 317 season=self._requested_season, 318 callback=ba.WeakCall(self._on_power_ranking_query_response), 319 ) 320 321 def _refresh(self) -> None: 322 # pylint: disable=too-many-statements 323 324 # (re)create the sub-container if need be.. 325 if self._subcontainer is not None: 326 self._subcontainer.delete() 327 self._subcontainer = ba.containerwidget( 328 parent=self._scrollwidget, 329 size=(self._subcontainerwidth, self._subcontainerheight), 330 background=False, 331 ) 332 333 w_parent = self._subcontainer 334 v = self._subcontainerheight - 20 335 336 v -= 0 337 338 h2 = 80 339 v2 = v - 60 340 worth_color = (0.6, 0.6, 0.65) 341 tally_color = (0.5, 0.6, 0.8) 342 spc = 43 343 344 h_offs_tally = 150 345 tally_maxwidth = 120 346 v2 -= 70 347 348 ba.textwidget( 349 parent=w_parent, 350 position=(h2 - 60, v2 + 106), 351 size=(0, 0), 352 flatness=1.0, 353 shadow=0.0, 354 text=ba.Lstr(resource='coopSelectWindow.pointsText'), 355 h_align='left', 356 v_align='center', 357 scale=0.8, 358 color=(1, 1, 1, 0.3), 359 maxwidth=200, 360 ) 361 362 self._power_ranking_achievements_button = ba.buttonwidget( 363 parent=w_parent, 364 position=(h2 - 60, v2 + 10), 365 size=(200, 80), 366 icon=ba.gettexture('achievementsIcon'), 367 autoselect=True, 368 on_activate_call=ba.WeakCall(self._on_achievements_press), 369 up_widget=self._back_button, 370 left_widget=self._back_button, 371 color=(0.5, 0.5, 0.6), 372 textcolor=(0.7, 0.7, 0.8), 373 label='', 374 ) 375 376 self._power_ranking_achievement_total_text = ba.textwidget( 377 parent=w_parent, 378 position=(h2 + h_offs_tally, v2 + 45), 379 size=(0, 0), 380 flatness=1.0, 381 shadow=0.0, 382 text='-', 383 h_align='left', 384 v_align='center', 385 scale=0.8, 386 color=tally_color, 387 maxwidth=tally_maxwidth, 388 ) 389 390 v2 -= 80 391 392 self._power_ranking_trophies_button = ba.buttonwidget( 393 parent=w_parent, 394 position=(h2 - 60, v2 + 10), 395 size=(200, 80), 396 icon=ba.gettexture('medalSilver'), 397 autoselect=True, 398 on_activate_call=ba.WeakCall(self._on_trophies_press), 399 left_widget=self._back_button, 400 color=(0.5, 0.5, 0.6), 401 textcolor=(0.7, 0.7, 0.8), 402 label='', 403 ) 404 self._power_ranking_trophies_total_text = ba.textwidget( 405 parent=w_parent, 406 position=(h2 + h_offs_tally, v2 + 45), 407 size=(0, 0), 408 flatness=1.0, 409 shadow=0.0, 410 text='-', 411 h_align='left', 412 v_align='center', 413 scale=0.8, 414 color=tally_color, 415 maxwidth=tally_maxwidth, 416 ) 417 418 v2 -= 100 419 420 ba.textwidget( 421 parent=w_parent, 422 position=(h2 - 60, v2 + 86), 423 size=(0, 0), 424 flatness=1.0, 425 shadow=0.0, 426 text=ba.Lstr(resource='coopSelectWindow.multipliersText'), 427 h_align='left', 428 v_align='center', 429 scale=0.8, 430 color=(1, 1, 1, 0.3), 431 maxwidth=200, 432 ) 433 434 self._activity_mult_button: ba.Widget | None 435 if ba.internal.get_v1_account_misc_read_val('act', False): 436 self._activity_mult_button = ba.buttonwidget( 437 parent=w_parent, 438 position=(h2 - 60, v2 + 10), 439 size=(200, 60), 440 icon=ba.gettexture('heart'), 441 icon_color=(0.5, 0, 0.5), 442 label=ba.Lstr(resource='coopSelectWindow.activityText'), 443 autoselect=True, 444 on_activate_call=ba.WeakCall(self._on_activity_mult_press), 445 left_widget=self._back_button, 446 color=(0.5, 0.5, 0.6), 447 textcolor=(0.7, 0.7, 0.8), 448 ) 449 450 self._activity_mult_text = ba.textwidget( 451 parent=w_parent, 452 position=(h2 + h_offs_tally, v2 + 40), 453 size=(0, 0), 454 flatness=1.0, 455 shadow=0.0, 456 text='-', 457 h_align='left', 458 v_align='center', 459 scale=0.8, 460 color=tally_color, 461 maxwidth=tally_maxwidth, 462 ) 463 v2 -= 65 464 else: 465 self._activity_mult_button = None 466 467 self._pro_mult_button = ba.buttonwidget( 468 parent=w_parent, 469 position=(h2 - 60, v2 + 10), 470 size=(200, 60), 471 icon=ba.gettexture('logo'), 472 icon_color=(0.3, 0, 0.3), 473 label=ba.Lstr( 474 resource='store.bombSquadProNameText', 475 subs=[('${APP_NAME}', ba.Lstr(resource='titleText'))], 476 ), 477 autoselect=True, 478 on_activate_call=ba.WeakCall(self._on_pro_mult_press), 479 left_widget=self._back_button, 480 color=(0.5, 0.5, 0.6), 481 textcolor=(0.7, 0.7, 0.8), 482 ) 483 484 self._pro_mult_text = ba.textwidget( 485 parent=w_parent, 486 position=(h2 + h_offs_tally, v2 + 40), 487 size=(0, 0), 488 flatness=1.0, 489 shadow=0.0, 490 text='-', 491 h_align='left', 492 v_align='center', 493 scale=0.8, 494 color=tally_color, 495 maxwidth=tally_maxwidth, 496 ) 497 v2 -= 30 498 499 v2 -= spc 500 ba.textwidget( 501 parent=w_parent, 502 position=(h2 + h_offs_tally - 10 - 40, v2 + 35), 503 size=(0, 0), 504 flatness=1.0, 505 shadow=0.0, 506 text=ba.Lstr(resource='finalScoreText'), 507 h_align='right', 508 v_align='center', 509 scale=0.9, 510 color=worth_color, 511 maxwidth=150, 512 ) 513 self._power_ranking_total_text = ba.textwidget( 514 parent=w_parent, 515 position=(h2 + h_offs_tally - 40, v2 + 35), 516 size=(0, 0), 517 flatness=1.0, 518 shadow=0.0, 519 text='-', 520 h_align='left', 521 v_align='center', 522 scale=0.9, 523 color=tally_color, 524 maxwidth=tally_maxwidth, 525 ) 526 527 self._season_show_text = ba.textwidget( 528 parent=w_parent, 529 position=(390 - 15, v - 20), 530 size=(0, 0), 531 color=(0.6, 0.6, 0.7), 532 maxwidth=200, 533 text=ba.Lstr(resource='showText'), 534 h_align='right', 535 v_align='center', 536 scale=0.8, 537 shadow=0, 538 flatness=1.0, 539 ) 540 541 self._league_title_text = ba.textwidget( 542 parent=w_parent, 543 position=(470, v - 97), 544 size=(0, 0), 545 color=(0.6, 0.6, 0.7), 546 maxwidth=230, 547 text='', 548 h_align='center', 549 v_align='center', 550 scale=0.9, 551 shadow=0, 552 flatness=1.0, 553 ) 554 555 self._league_text_scale = 1.8 556 self._league_text_maxwidth = 210 557 self._league_text = ba.textwidget( 558 parent=w_parent, 559 position=(470, v - 140), 560 size=(0, 0), 561 color=(1, 1, 1), 562 maxwidth=self._league_text_maxwidth, 563 text='-', 564 h_align='center', 565 v_align='center', 566 scale=self._league_text_scale, 567 shadow=1.0, 568 flatness=1.0, 569 ) 570 self._league_number_base_pos = (470, v - 140) 571 self._league_number_text = ba.textwidget( 572 parent=w_parent, 573 position=(470, v - 140), 574 size=(0, 0), 575 color=(1, 1, 1), 576 maxwidth=100, 577 text='', 578 h_align='left', 579 v_align='center', 580 scale=0.8, 581 shadow=1.0, 582 flatness=1.0, 583 ) 584 585 self._your_power_ranking_text = ba.textwidget( 586 parent=w_parent, 587 position=(470, v - 142 - 70), 588 size=(0, 0), 589 color=(0.6, 0.6, 0.7), 590 maxwidth=230, 591 text='', 592 h_align='center', 593 v_align='center', 594 scale=0.9, 595 shadow=0, 596 flatness=1.0, 597 ) 598 599 self._to_ranked_text = ba.textwidget( 600 parent=w_parent, 601 position=(470, v - 250 - 70), 602 size=(0, 0), 603 color=(0.6, 0.6, 0.7), 604 maxwidth=230, 605 text='', 606 h_align='center', 607 v_align='center', 608 scale=0.8, 609 shadow=0, 610 flatness=1.0, 611 ) 612 613 self._power_ranking_rank_text = ba.textwidget( 614 parent=w_parent, 615 position=(473, v - 210 - 70), 616 size=(0, 0), 617 big=False, 618 text='-', 619 h_align='center', 620 v_align='center', 621 scale=1.0, 622 ) 623 624 self._season_ends_text = ba.textwidget( 625 parent=w_parent, 626 position=(470, v - 380), 627 size=(0, 0), 628 color=(0.6, 0.6, 0.6), 629 maxwidth=230, 630 text='', 631 h_align='center', 632 v_align='center', 633 scale=0.9, 634 shadow=0, 635 flatness=1.0, 636 ) 637 self._trophy_counts_reset_text = ba.textwidget( 638 parent=w_parent, 639 position=(470, v - 410), 640 size=(0, 0), 641 color=(0.5, 0.5, 0.5), 642 maxwidth=230, 643 text='Trophy counts will reset next season.', 644 h_align='center', 645 v_align='center', 646 scale=0.8, 647 shadow=0, 648 flatness=1.0, 649 ) 650 651 self._power_ranking_score_widgets = [] 652 653 self._power_ranking_score_v = v - 56 654 655 h = 707 656 v -= 451 657 658 self._see_more_button = ba.buttonwidget( 659 parent=w_parent, 660 label=self._rdict.seeMoreText, 661 position=(h, v), 662 color=(0.5, 0.5, 0.6), 663 textcolor=(0.7, 0.7, 0.8), 664 size=(230, 60), 665 autoselect=True, 666 on_activate_call=ba.WeakCall(self._on_more_press), 667 ) 668 669 def _on_more_press(self) -> None: 670 our_login_id = ba.internal.get_public_login_id() 671 # our_login_id = _bs.get_account_misc_read_val_2( 672 # 'resolvedAccountID', None) 673 if not self._can_do_more_button or our_login_id is None: 674 ba.playsound(ba.getsound('error')) 675 ba.screenmessage( 676 ba.Lstr(resource='unavailableText'), color=(1, 0, 0) 677 ) 678 return 679 if self._season is None: 680 season_str = '' 681 else: 682 season_str = '&season=' + ( 683 'all_time' if self._season == 'a' else self._season 684 ) 685 if self._league_url_arg != '': 686 league_str = '&league=' + self._league_url_arg 687 else: 688 league_str = '' 689 ba.open_url( 690 ba.internal.get_master_server_address() 691 + '/highscores?list=powerRankings&v=2' 692 + league_str 693 + season_str 694 + '&player=' 695 + our_login_id 696 ) 697 698 def _update_for_league_rank_data(self, data: dict[str, Any] | None) -> None: 699 # pylint: disable=too-many-statements 700 # pylint: disable=too-many-branches 701 # pylint: disable=too-many-locals 702 if not self._root_widget: 703 return 704 accounts = ba.app.accounts_v1 705 in_top = data is not None and data['rank'] is not None 706 eq_text = self._rdict.powerRankingPointsEqualsText 707 pts_txt = self._rdict.powerRankingPointsText 708 num_text = ba.Lstr(resource='numberText').evaluate() 709 do_percent = False 710 finished_season_unranked = False 711 self._can_do_more_button = True 712 extra_text = '' 713 if ba.internal.get_v1_account_state() != 'signed_in': 714 status_text = ( 715 '(' + ba.Lstr(resource='notSignedInText').evaluate() + ')' 716 ) 717 elif in_top: 718 assert data is not None 719 status_text = num_text.replace('${NUMBER}', str(data['rank'])) 720 elif data is not None: 721 try: 722 # handle old seasons where we didn't wind up ranked 723 # at the end.. 724 if not data['scores']: 725 status_text = ( 726 self._rdict.powerRankingFinishedSeasonUnrankedText 727 ) 728 extra_text = '' 729 finished_season_unranked = True 730 self._can_do_more_button = False 731 else: 732 our_points = accounts.get_league_rank_points(data) 733 progress = float(our_points) / max(1, data['scores'][-1][1]) 734 status_text = str(int(progress * 100.0)) + '%' 735 extra_text = ( 736 '\n' 737 + self._rdict.powerRankingPointsToRankedText.replace( 738 '${CURRENT}', str(our_points) 739 ).replace('${REMAINING}', str(data['scores'][-1][1])) 740 ) 741 do_percent = True 742 except Exception: 743 ba.print_exception('Error updating power ranking.') 744 status_text = self._rdict.powerRankingNotInTopText.replace( 745 '${NUMBER}', str(data['listSize']) 746 ) 747 extra_text = '' 748 else: 749 status_text = '-' 750 751 self._season = data['s'] if data is not None else None 752 753 v = self._subcontainerheight - 20 754 popup_was_selected = False 755 if self._season_popup_menu is not None: 756 btn = self._season_popup_menu.get_button() 757 assert self._subcontainer 758 if self._subcontainer.get_selected_child() == btn: 759 popup_was_selected = True 760 btn.delete() 761 season_choices = [] 762 season_choices_display = [] 763 did_first = False 764 self._is_current_season = False 765 if data is not None: 766 # build our list of seasons we have available 767 for ssn in data['sl']: 768 season_choices.append(ssn) 769 if ssn != 'a' and not did_first: 770 season_choices_display.append( 771 ba.Lstr( 772 resource='league.currentSeasonText', 773 subs=[('${NUMBER}', ssn)], 774 ) 775 ) 776 did_first = True 777 # if we either did not specify a season or specified the 778 # first, we're looking at the current.. 779 if self._season in [ssn, None]: 780 self._is_current_season = True 781 elif ssn == 'a': 782 season_choices_display.append( 783 ba.Lstr(resource='league.allTimeText') 784 ) 785 else: 786 season_choices_display.append( 787 ba.Lstr( 788 resource='league.seasonText', 789 subs=[('${NUMBER}', ssn)], 790 ) 791 ) 792 assert self._subcontainer 793 self._season_popup_menu = popup_ui.PopupMenu( 794 parent=self._subcontainer, 795 position=(390, v - 45), 796 width=150, 797 button_size=(200, 50), 798 choices=season_choices, 799 on_value_change_call=ba.WeakCall(self._on_season_change), 800 choices_display=season_choices_display, 801 current_choice=self._season, 802 ) 803 if popup_was_selected: 804 ba.containerwidget( 805 edit=self._subcontainer, 806 selected_child=self._season_popup_menu.get_button(), 807 ) 808 ba.widget(edit=self._see_more_button, show_buffer_bottom=100) 809 ba.widget( 810 edit=self._season_popup_menu.get_button(), 811 up_widget=self._back_button, 812 ) 813 ba.widget( 814 edit=self._back_button, 815 down_widget=self._power_ranking_achievements_button, 816 right_widget=self._season_popup_menu.get_button(), 817 ) 818 819 ba.textwidget( 820 edit=self._league_title_text, 821 text='' 822 if self._season == 'a' 823 else ba.Lstr(resource='league.leagueText'), 824 ) 825 826 if data is None: 827 lname = '' 828 lnum = '' 829 lcolor = (1, 1, 1) 830 self._league_url_arg = '' 831 elif self._season == 'a': 832 lname = ba.Lstr(resource='league.allTimeText').evaluate() 833 lnum = '' 834 lcolor = (1, 1, 1) 835 self._league_url_arg = '' 836 else: 837 lnum = ('[' + str(data['l']['i']) + ']') if data['l']['i2'] else '' 838 lname = ba.Lstr( 839 translate=('leagueNames', data['l']['n']) 840 ).evaluate() 841 lcolor = data['l']['c'] 842 self._league_url_arg = ( 843 data['l']['n'] + '_' + str(data['l']['i']) 844 ).lower() 845 846 to_end_string: ba.Lstr | str 847 if data is None or self._season == 'a' or data['se'] is None: 848 to_end_string = '' 849 show_season_end = False 850 else: 851 show_season_end = True 852 days_to_end = data['se'][0] 853 minutes_to_end = data['se'][1] 854 if days_to_end > 0: 855 to_end_string = ba.Lstr( 856 resource='league.seasonEndsDaysText', 857 subs=[('${NUMBER}', str(days_to_end))], 858 ) 859 elif days_to_end == 0 and minutes_to_end >= 60: 860 to_end_string = ba.Lstr( 861 resource='league.seasonEndsHoursText', 862 subs=[('${NUMBER}', str(minutes_to_end // 60))], 863 ) 864 elif days_to_end == 0 and minutes_to_end >= 0: 865 to_end_string = ba.Lstr( 866 resource='league.seasonEndsMinutesText', 867 subs=[('${NUMBER}', str(minutes_to_end))], 868 ) 869 else: 870 to_end_string = ba.Lstr( 871 resource='league.seasonEndedDaysAgoText', 872 subs=[('${NUMBER}', str(-(days_to_end + 1)))], 873 ) 874 875 ba.textwidget(edit=self._season_ends_text, text=to_end_string) 876 ba.textwidget( 877 edit=self._trophy_counts_reset_text, 878 text=ba.Lstr(resource='league.trophyCountsResetText') 879 if self._is_current_season and show_season_end 880 else '', 881 ) 882 883 ba.textwidget(edit=self._league_text, text=lname, color=lcolor) 884 l_text_width = min( 885 self._league_text_maxwidth, 886 ba.internal.get_string_width(lname, suppress_warning=True) 887 * self._league_text_scale, 888 ) 889 ba.textwidget( 890 edit=self._league_number_text, 891 text=lnum, 892 color=lcolor, 893 position=( 894 self._league_number_base_pos[0] + l_text_width * 0.5 + 8, 895 self._league_number_base_pos[1] + 10, 896 ), 897 ) 898 ba.textwidget( 899 edit=self._to_ranked_text, 900 text=ba.Lstr(resource='coopSelectWindow.toRankedText').evaluate() 901 + '' 902 + extra_text 903 if do_percent 904 else '', 905 ) 906 907 ba.textwidget( 908 edit=self._your_power_ranking_text, 909 text=ba.Lstr( 910 resource='rankText', 911 fallback_resource='coopSelectWindow.yourPowerRankingText', 912 ) 913 if (not do_percent) 914 else '', 915 ) 916 917 ba.textwidget( 918 edit=self._power_ranking_rank_text, 919 position=(473, v - 70 - (170 if do_percent else 220)), 920 text=status_text, 921 big=(in_top or do_percent), 922 scale=3.0 923 if (in_top or do_percent) 924 else 0.7 925 if finished_season_unranked 926 else 1.0, 927 ) 928 929 if self._activity_mult_button is not None: 930 if data is None or data['act'] is None: 931 ba.buttonwidget( 932 edit=self._activity_mult_button, 933 textcolor=(0.7, 0.7, 0.8, 0.5), 934 icon_color=(0.5, 0, 0.5, 0.3), 935 ) 936 ba.textwidget(edit=self._activity_mult_text, text=' -') 937 else: 938 ba.buttonwidget( 939 edit=self._activity_mult_button, 940 textcolor=(0.7, 0.7, 0.8, 1.0), 941 icon_color=(0.5, 0, 0.5, 1.0), 942 ) 943 # pylint: disable=consider-using-f-string 944 ba.textwidget( 945 edit=self._activity_mult_text, 946 text='x ' + ('%.2f' % data['act']), 947 ) 948 949 have_pro = False if data is None else data['p'] 950 pro_mult = ( 951 1.0 952 + float( 953 ba.internal.get_v1_account_misc_read_val( 954 'proPowerRankingBoost', 0.0 955 ) 956 ) 957 * 0.01 958 ) 959 # pylint: disable=consider-using-f-string 960 ba.textwidget( 961 edit=self._pro_mult_text, 962 text=' -' 963 if (data is None or not have_pro) 964 else 'x ' + ('%.2f' % pro_mult), 965 ) 966 ba.buttonwidget( 967 edit=self._pro_mult_button, 968 textcolor=(0.7, 0.7, 0.8, (1.0 if have_pro else 0.5)), 969 icon_color=(0.5, 0, 0.5) if have_pro else (0.5, 0, 0.5, 0.2), 970 ) 971 ba.buttonwidget( 972 edit=self._power_ranking_achievements_button, 973 label=('' if data is None else (str(data['a']) + ' ')) 974 + ba.Lstr(resource='achievementsText').evaluate(), 975 ) 976 977 # for the achievement value, use the number they gave us for 978 # non-current seasons; otherwise calc our own 979 total_ach_value = 0 980 for ach in ba.app.ach.achievements: 981 if ach.complete: 982 total_ach_value += ach.power_ranking_value 983 if self._season != 'a' and not self._is_current_season: 984 if data is not None and 'at' in data: 985 total_ach_value = data['at'] 986 987 ba.textwidget( 988 edit=self._power_ranking_achievement_total_text, 989 text='-' 990 if data is None 991 else ('+ ' + pts_txt.replace('${NUMBER}', str(total_ach_value))), 992 ) 993 994 total_trophies_count = accounts.get_league_rank_points( 995 data, 'trophyCount' 996 ) 997 total_trophies_value = accounts.get_league_rank_points(data, 'trophies') 998 ba.buttonwidget( 999 edit=self._power_ranking_trophies_button, 1000 label=('' if data is None else (str(total_trophies_count) + ' ')) 1001 + ba.Lstr(resource='trophiesText').evaluate(), 1002 ) 1003 ba.textwidget( 1004 edit=self._power_ranking_trophies_total_text, 1005 text='-' 1006 if data is None 1007 else ( 1008 '+ ' + pts_txt.replace('${NUMBER}', str(total_trophies_value)) 1009 ), 1010 ) 1011 1012 ba.textwidget( 1013 edit=self._power_ranking_total_text, 1014 text='-' 1015 if data is None 1016 else eq_text.replace( 1017 '${NUMBER}', str(accounts.get_league_rank_points(data)) 1018 ), 1019 ) 1020 for widget in self._power_ranking_score_widgets: 1021 widget.delete() 1022 self._power_ranking_score_widgets = [] 1023 1024 scores = data['scores'] if data is not None else [] 1025 tally_color = (0.5, 0.6, 0.8) 1026 w_parent = self._subcontainer 1027 v2 = self._power_ranking_score_v 1028 1029 for score in scores: 1030 h2 = 680 1031 is_us = score[3] 1032 self._power_ranking_score_widgets.append( 1033 ba.textwidget( 1034 parent=w_parent, 1035 position=(h2 - 20, v2), 1036 size=(0, 0), 1037 color=(1, 1, 1) if is_us else (0.6, 0.6, 0.7), 1038 maxwidth=40, 1039 flatness=1.0, 1040 shadow=0.0, 1041 text=num_text.replace('${NUMBER}', str(score[0])), 1042 h_align='right', 1043 v_align='center', 1044 scale=0.5, 1045 ) 1046 ) 1047 self._power_ranking_score_widgets.append( 1048 ba.textwidget( 1049 parent=w_parent, 1050 position=(h2 + 20, v2), 1051 size=(0, 0), 1052 color=(1, 1, 1) if is_us else tally_color, 1053 maxwidth=60, 1054 text=str(score[1]), 1055 flatness=1.0, 1056 shadow=0.0, 1057 h_align='center', 1058 v_align='center', 1059 scale=0.7, 1060 ) 1061 ) 1062 txt = ba.textwidget( 1063 parent=w_parent, 1064 position=(h2 + 60, v2 - (28 * 0.5) / 0.9), 1065 size=(210 / 0.9, 28), 1066 color=(1, 1, 1) if is_us else (0.6, 0.6, 0.6), 1067 maxwidth=210, 1068 flatness=1.0, 1069 shadow=0.0, 1070 autoselect=True, 1071 selectable=True, 1072 click_activate=True, 1073 text=score[2], 1074 h_align='left', 1075 v_align='center', 1076 scale=0.9, 1077 ) 1078 self._power_ranking_score_widgets.append(txt) 1079 ba.textwidget( 1080 edit=txt, 1081 on_activate_call=ba.Call( 1082 self._show_account_info, score[4], txt 1083 ), 1084 ) 1085 assert self._season_popup_menu is not None 1086 ba.widget( 1087 edit=txt, left_widget=self._season_popup_menu.get_button() 1088 ) 1089 v2 -= 28 1090 1091 def _show_account_info( 1092 self, account_id: str, textwidget: ba.Widget 1093 ) -> None: 1094 from bastd.ui.account import viewer 1095 1096 ba.playsound(ba.getsound('swish')) 1097 viewer.AccountViewerWindow( 1098 account_id=account_id, position=textwidget.get_screen_space_center() 1099 ) 1100 1101 def _on_season_change(self, value: str) -> None: 1102 self._requested_season = value 1103 self._last_power_ranking_query_time = None # make sure we update asap 1104 self._update(show=True) 1105 1106 def _save_state(self) -> None: 1107 pass 1108 1109 def _back(self) -> None: 1110 from bastd.ui.coop.browser import CoopBrowserWindow 1111 1112 self._save_state() 1113 ba.containerwidget( 1114 edit=self._root_widget, transition=self._transition_out 1115 ) 1116 if not self._modal: 1117 ba.app.ui.set_main_menu_window( 1118 CoopBrowserWindow(transition='in_left').get_root_widget() 1119 )
class
LeagueRankWindow(ba.ui.Window):
20class LeagueRankWindow(ba.Window): 21 """Window for showing league rank.""" 22 23 def __init__( 24 self, 25 transition: str = 'in_right', 26 modal: bool = False, 27 origin_widget: ba.Widget | None = None, 28 ): 29 ba.set_analytics_screen('League Rank Window') 30 31 self._league_rank_data: dict[str, Any] | None = None 32 self._modal = modal 33 34 # If they provided an origin-widget, scale up from that. 35 scale_origin: tuple[float, float] | None 36 if origin_widget is not None: 37 self._transition_out = 'out_scale' 38 scale_origin = origin_widget.get_screen_space_center() 39 transition = 'in_scale' 40 else: 41 self._transition_out = 'out_right' 42 scale_origin = None 43 44 uiscale = ba.app.ui.uiscale 45 self._width = 1320 if uiscale is ba.UIScale.SMALL else 1120 46 x_inset = 100 if uiscale is ba.UIScale.SMALL else 0 47 self._height = ( 48 657 49 if uiscale is ba.UIScale.SMALL 50 else 710 51 if uiscale is ba.UIScale.MEDIUM 52 else 800 53 ) 54 self._r = 'coopSelectWindow' 55 self._rdict = ba.app.lang.get_resource(self._r) 56 top_extra = 20 if uiscale is ba.UIScale.SMALL else 0 57 58 self._league_url_arg = '' 59 60 self._is_current_season = False 61 self._can_do_more_button = True 62 63 super().__init__( 64 root_widget=ba.containerwidget( 65 size=(self._width, self._height + top_extra), 66 stack_offset=(0, -15) 67 if uiscale is ba.UIScale.SMALL 68 else (0, 10) 69 if uiscale is ba.UIScale.MEDIUM 70 else (0, 0), 71 transition=transition, 72 scale_origin_stack_offset=scale_origin, 73 scale=( 74 1.2 75 if uiscale is ba.UIScale.SMALL 76 else 0.93 77 if uiscale is ba.UIScale.MEDIUM 78 else 0.8 79 ), 80 ) 81 ) 82 83 self._back_button = btn = ba.buttonwidget( 84 parent=self._root_widget, 85 position=( 86 75 + x_inset, 87 self._height - 87 - (4 if uiscale is ba.UIScale.SMALL else 0), 88 ), 89 size=(120, 60), 90 scale=1.2, 91 autoselect=True, 92 label=ba.Lstr(resource='doneText' if self._modal else 'backText'), 93 button_type=None if self._modal else 'back', 94 on_activate_call=self._back, 95 ) 96 97 self._title_text = ba.textwidget( 98 parent=self._root_widget, 99 position=(self._width * 0.5, self._height - 56), 100 size=(0, 0), 101 text=ba.Lstr( 102 resource='league.leagueRankText', 103 fallback_resource='coopSelectWindow.powerRankingText', 104 ), 105 h_align='center', 106 color=ba.app.ui.title_color, 107 scale=1.4, 108 maxwidth=600, 109 v_align='center', 110 ) 111 112 ba.buttonwidget( 113 edit=btn, 114 button_type='backSmall', 115 position=( 116 75 + x_inset, 117 self._height - 87 - (2 if uiscale is ba.UIScale.SMALL else 0), 118 ), 119 size=(60, 55), 120 label=ba.charstr(ba.SpecialChar.BACK), 121 ) 122 123 self._scroll_width = self._width - (130 + 2 * x_inset) 124 self._scroll_height = self._height - 160 125 self._scrollwidget = ba.scrollwidget( 126 parent=self._root_widget, 127 highlight=False, 128 position=(65 + x_inset, 70), 129 size=(self._scroll_width, self._scroll_height), 130 center_small_content=True, 131 ) 132 ba.widget(edit=self._scrollwidget, autoselect=True) 133 ba.containerwidget(edit=self._scrollwidget, claims_left_right=True) 134 ba.containerwidget( 135 edit=self._root_widget, 136 cancel_button=self._back_button, 137 selected_child=self._back_button, 138 ) 139 140 self._last_power_ranking_query_time: float | None = None 141 self._doing_power_ranking_query = False 142 143 self._subcontainer: ba.Widget | None = None 144 self._subcontainerwidth = 800 145 self._subcontainerheight = 483 146 self._power_ranking_score_widgets: list[ba.Widget] = [] 147 148 self._season_popup_menu: popup_ui.PopupMenu | None = None 149 self._requested_season: str | None = None 150 self._season: str | None = None 151 152 # take note of our account state; we'll refresh later if this changes 153 self._account_state = ba.internal.get_v1_account_state() 154 155 self._refresh() 156 self._restore_state() 157 158 # if we've got cached power-ranking data already, display it 159 info = ba.app.accounts_v1.get_cached_league_rank_data() 160 if info is not None: 161 self._update_for_league_rank_data(info) 162 163 self._update_timer = ba.Timer( 164 1.0, 165 ba.WeakCall(self._update), 166 timetype=ba.TimeType.REAL, 167 repeat=True, 168 ) 169 self._update(show=(info is None)) 170 171 def _on_achievements_press(self) -> None: 172 from bastd.ui import achievements 173 174 # only allow this for all-time or the current season 175 # (we currently don't keep specific achievement data for old seasons) 176 if self._season == 'a' or self._is_current_season: 177 prab = self._power_ranking_achievements_button 178 achievements.AchievementsWindow( 179 position=prab.get_screen_space_center() 180 ) 181 else: 182 ba.screenmessage( 183 ba.Lstr( 184 resource='achievementsUnavailableForOldSeasonsText', 185 fallback_resource='unavailableText', 186 ), 187 color=(1, 0, 0), 188 ) 189 ba.playsound(ba.getsound('error')) 190 191 def _on_activity_mult_press(self) -> None: 192 from bastd.ui import confirm 193 194 txt = ba.Lstr( 195 resource='coopSelectWindow.activenessAllTimeInfoText' 196 if self._season == 'a' 197 else 'coopSelectWindow.activenessInfoText', 198 subs=[ 199 ( 200 '${MAX}', 201 str( 202 ba.internal.get_v1_account_misc_read_val( 203 'activenessMax', 1.0 204 ) 205 ), 206 ) 207 ], 208 ) 209 confirm.ConfirmWindow( 210 txt, 211 cancel_button=False, 212 width=460, 213 height=150, 214 origin_widget=self._activity_mult_button, 215 ) 216 217 def _on_pro_mult_press(self) -> None: 218 from bastd.ui import confirm 219 220 txt = ba.Lstr( 221 resource='coopSelectWindow.proMultInfoText', 222 subs=[ 223 ( 224 '${PERCENT}', 225 str( 226 ba.internal.get_v1_account_misc_read_val( 227 'proPowerRankingBoost', 10 228 ) 229 ), 230 ), 231 ( 232 '${PRO}', 233 ba.Lstr( 234 resource='store.bombSquadProNameText', 235 subs=[('${APP_NAME}', ba.Lstr(resource='titleText'))], 236 ), 237 ), 238 ], 239 ) 240 confirm.ConfirmWindow( 241 txt, 242 cancel_button=False, 243 width=460, 244 height=130, 245 origin_widget=self._pro_mult_button, 246 ) 247 248 def _on_trophies_press(self) -> None: 249 from bastd.ui.trophies import TrophiesWindow 250 251 info = self._league_rank_data 252 if info is not None: 253 prtb = self._power_ranking_trophies_button 254 TrophiesWindow( 255 position=prtb.get_screen_space_center(), 256 data=info, 257 ) 258 else: 259 ba.playsound(ba.getsound('error')) 260 261 def _on_power_ranking_query_response( 262 self, data: dict[str, Any] | None 263 ) -> None: 264 self._doing_power_ranking_query = False 265 # important: *only* cache this if we requested the current season.. 266 if data is not None and data.get('s', None) is None: 267 ba.app.accounts_v1.cache_league_rank_data(data) 268 # always store a copy locally though (even for other seasons) 269 self._league_rank_data = copy.deepcopy(data) 270 self._update_for_league_rank_data(data) 271 272 def _restore_state(self) -> None: 273 pass 274 275 def _update(self, show: bool = False) -> None: 276 277 cur_time = ba.time(ba.TimeType.REAL) 278 279 # if our account state has changed, refresh our UI 280 account_state = ba.internal.get_v1_account_state() 281 if account_state != self._account_state: 282 self._account_state = account_state 283 self._save_state() 284 self._refresh() 285 286 # and power ranking too... 287 if not self._doing_power_ranking_query: 288 self._last_power_ranking_query_time = None 289 290 # send off a new power-ranking query if its been long enough or our 291 # requested season has changed or whatnot.. 292 if not self._doing_power_ranking_query and ( 293 self._last_power_ranking_query_time is None 294 or cur_time - self._last_power_ranking_query_time > 30.0 295 ): 296 try: 297 if show: 298 ba.textwidget(edit=self._league_title_text, text='') 299 ba.textwidget(edit=self._league_text, text='') 300 ba.textwidget(edit=self._league_number_text, text='') 301 ba.textwidget( 302 edit=self._your_power_ranking_text, 303 text=ba.Lstr( 304 value='${A}...', 305 subs=[('${A}', ba.Lstr(resource='loadingText'))], 306 ), 307 ) 308 ba.textwidget(edit=self._to_ranked_text, text='') 309 ba.textwidget(edit=self._power_ranking_rank_text, text='') 310 ba.textwidget(edit=self._season_ends_text, text='') 311 ba.textwidget(edit=self._trophy_counts_reset_text, text='') 312 except Exception: 313 ba.print_exception('Error showing updated rank info.') 314 315 self._last_power_ranking_query_time = cur_time 316 self._doing_power_ranking_query = True 317 ba.internal.power_ranking_query( 318 season=self._requested_season, 319 callback=ba.WeakCall(self._on_power_ranking_query_response), 320 ) 321 322 def _refresh(self) -> None: 323 # pylint: disable=too-many-statements 324 325 # (re)create the sub-container if need be.. 326 if self._subcontainer is not None: 327 self._subcontainer.delete() 328 self._subcontainer = ba.containerwidget( 329 parent=self._scrollwidget, 330 size=(self._subcontainerwidth, self._subcontainerheight), 331 background=False, 332 ) 333 334 w_parent = self._subcontainer 335 v = self._subcontainerheight - 20 336 337 v -= 0 338 339 h2 = 80 340 v2 = v - 60 341 worth_color = (0.6, 0.6, 0.65) 342 tally_color = (0.5, 0.6, 0.8) 343 spc = 43 344 345 h_offs_tally = 150 346 tally_maxwidth = 120 347 v2 -= 70 348 349 ba.textwidget( 350 parent=w_parent, 351 position=(h2 - 60, v2 + 106), 352 size=(0, 0), 353 flatness=1.0, 354 shadow=0.0, 355 text=ba.Lstr(resource='coopSelectWindow.pointsText'), 356 h_align='left', 357 v_align='center', 358 scale=0.8, 359 color=(1, 1, 1, 0.3), 360 maxwidth=200, 361 ) 362 363 self._power_ranking_achievements_button = ba.buttonwidget( 364 parent=w_parent, 365 position=(h2 - 60, v2 + 10), 366 size=(200, 80), 367 icon=ba.gettexture('achievementsIcon'), 368 autoselect=True, 369 on_activate_call=ba.WeakCall(self._on_achievements_press), 370 up_widget=self._back_button, 371 left_widget=self._back_button, 372 color=(0.5, 0.5, 0.6), 373 textcolor=(0.7, 0.7, 0.8), 374 label='', 375 ) 376 377 self._power_ranking_achievement_total_text = ba.textwidget( 378 parent=w_parent, 379 position=(h2 + h_offs_tally, v2 + 45), 380 size=(0, 0), 381 flatness=1.0, 382 shadow=0.0, 383 text='-', 384 h_align='left', 385 v_align='center', 386 scale=0.8, 387 color=tally_color, 388 maxwidth=tally_maxwidth, 389 ) 390 391 v2 -= 80 392 393 self._power_ranking_trophies_button = ba.buttonwidget( 394 parent=w_parent, 395 position=(h2 - 60, v2 + 10), 396 size=(200, 80), 397 icon=ba.gettexture('medalSilver'), 398 autoselect=True, 399 on_activate_call=ba.WeakCall(self._on_trophies_press), 400 left_widget=self._back_button, 401 color=(0.5, 0.5, 0.6), 402 textcolor=(0.7, 0.7, 0.8), 403 label='', 404 ) 405 self._power_ranking_trophies_total_text = ba.textwidget( 406 parent=w_parent, 407 position=(h2 + h_offs_tally, v2 + 45), 408 size=(0, 0), 409 flatness=1.0, 410 shadow=0.0, 411 text='-', 412 h_align='left', 413 v_align='center', 414 scale=0.8, 415 color=tally_color, 416 maxwidth=tally_maxwidth, 417 ) 418 419 v2 -= 100 420 421 ba.textwidget( 422 parent=w_parent, 423 position=(h2 - 60, v2 + 86), 424 size=(0, 0), 425 flatness=1.0, 426 shadow=0.0, 427 text=ba.Lstr(resource='coopSelectWindow.multipliersText'), 428 h_align='left', 429 v_align='center', 430 scale=0.8, 431 color=(1, 1, 1, 0.3), 432 maxwidth=200, 433 ) 434 435 self._activity_mult_button: ba.Widget | None 436 if ba.internal.get_v1_account_misc_read_val('act', False): 437 self._activity_mult_button = ba.buttonwidget( 438 parent=w_parent, 439 position=(h2 - 60, v2 + 10), 440 size=(200, 60), 441 icon=ba.gettexture('heart'), 442 icon_color=(0.5, 0, 0.5), 443 label=ba.Lstr(resource='coopSelectWindow.activityText'), 444 autoselect=True, 445 on_activate_call=ba.WeakCall(self._on_activity_mult_press), 446 left_widget=self._back_button, 447 color=(0.5, 0.5, 0.6), 448 textcolor=(0.7, 0.7, 0.8), 449 ) 450 451 self._activity_mult_text = ba.textwidget( 452 parent=w_parent, 453 position=(h2 + h_offs_tally, v2 + 40), 454 size=(0, 0), 455 flatness=1.0, 456 shadow=0.0, 457 text='-', 458 h_align='left', 459 v_align='center', 460 scale=0.8, 461 color=tally_color, 462 maxwidth=tally_maxwidth, 463 ) 464 v2 -= 65 465 else: 466 self._activity_mult_button = None 467 468 self._pro_mult_button = ba.buttonwidget( 469 parent=w_parent, 470 position=(h2 - 60, v2 + 10), 471 size=(200, 60), 472 icon=ba.gettexture('logo'), 473 icon_color=(0.3, 0, 0.3), 474 label=ba.Lstr( 475 resource='store.bombSquadProNameText', 476 subs=[('${APP_NAME}', ba.Lstr(resource='titleText'))], 477 ), 478 autoselect=True, 479 on_activate_call=ba.WeakCall(self._on_pro_mult_press), 480 left_widget=self._back_button, 481 color=(0.5, 0.5, 0.6), 482 textcolor=(0.7, 0.7, 0.8), 483 ) 484 485 self._pro_mult_text = ba.textwidget( 486 parent=w_parent, 487 position=(h2 + h_offs_tally, v2 + 40), 488 size=(0, 0), 489 flatness=1.0, 490 shadow=0.0, 491 text='-', 492 h_align='left', 493 v_align='center', 494 scale=0.8, 495 color=tally_color, 496 maxwidth=tally_maxwidth, 497 ) 498 v2 -= 30 499 500 v2 -= spc 501 ba.textwidget( 502 parent=w_parent, 503 position=(h2 + h_offs_tally - 10 - 40, v2 + 35), 504 size=(0, 0), 505 flatness=1.0, 506 shadow=0.0, 507 text=ba.Lstr(resource='finalScoreText'), 508 h_align='right', 509 v_align='center', 510 scale=0.9, 511 color=worth_color, 512 maxwidth=150, 513 ) 514 self._power_ranking_total_text = ba.textwidget( 515 parent=w_parent, 516 position=(h2 + h_offs_tally - 40, v2 + 35), 517 size=(0, 0), 518 flatness=1.0, 519 shadow=0.0, 520 text='-', 521 h_align='left', 522 v_align='center', 523 scale=0.9, 524 color=tally_color, 525 maxwidth=tally_maxwidth, 526 ) 527 528 self._season_show_text = ba.textwidget( 529 parent=w_parent, 530 position=(390 - 15, v - 20), 531 size=(0, 0), 532 color=(0.6, 0.6, 0.7), 533 maxwidth=200, 534 text=ba.Lstr(resource='showText'), 535 h_align='right', 536 v_align='center', 537 scale=0.8, 538 shadow=0, 539 flatness=1.0, 540 ) 541 542 self._league_title_text = ba.textwidget( 543 parent=w_parent, 544 position=(470, v - 97), 545 size=(0, 0), 546 color=(0.6, 0.6, 0.7), 547 maxwidth=230, 548 text='', 549 h_align='center', 550 v_align='center', 551 scale=0.9, 552 shadow=0, 553 flatness=1.0, 554 ) 555 556 self._league_text_scale = 1.8 557 self._league_text_maxwidth = 210 558 self._league_text = ba.textwidget( 559 parent=w_parent, 560 position=(470, v - 140), 561 size=(0, 0), 562 color=(1, 1, 1), 563 maxwidth=self._league_text_maxwidth, 564 text='-', 565 h_align='center', 566 v_align='center', 567 scale=self._league_text_scale, 568 shadow=1.0, 569 flatness=1.0, 570 ) 571 self._league_number_base_pos = (470, v - 140) 572 self._league_number_text = ba.textwidget( 573 parent=w_parent, 574 position=(470, v - 140), 575 size=(0, 0), 576 color=(1, 1, 1), 577 maxwidth=100, 578 text='', 579 h_align='left', 580 v_align='center', 581 scale=0.8, 582 shadow=1.0, 583 flatness=1.0, 584 ) 585 586 self._your_power_ranking_text = ba.textwidget( 587 parent=w_parent, 588 position=(470, v - 142 - 70), 589 size=(0, 0), 590 color=(0.6, 0.6, 0.7), 591 maxwidth=230, 592 text='', 593 h_align='center', 594 v_align='center', 595 scale=0.9, 596 shadow=0, 597 flatness=1.0, 598 ) 599 600 self._to_ranked_text = ba.textwidget( 601 parent=w_parent, 602 position=(470, v - 250 - 70), 603 size=(0, 0), 604 color=(0.6, 0.6, 0.7), 605 maxwidth=230, 606 text='', 607 h_align='center', 608 v_align='center', 609 scale=0.8, 610 shadow=0, 611 flatness=1.0, 612 ) 613 614 self._power_ranking_rank_text = ba.textwidget( 615 parent=w_parent, 616 position=(473, v - 210 - 70), 617 size=(0, 0), 618 big=False, 619 text='-', 620 h_align='center', 621 v_align='center', 622 scale=1.0, 623 ) 624 625 self._season_ends_text = ba.textwidget( 626 parent=w_parent, 627 position=(470, v - 380), 628 size=(0, 0), 629 color=(0.6, 0.6, 0.6), 630 maxwidth=230, 631 text='', 632 h_align='center', 633 v_align='center', 634 scale=0.9, 635 shadow=0, 636 flatness=1.0, 637 ) 638 self._trophy_counts_reset_text = ba.textwidget( 639 parent=w_parent, 640 position=(470, v - 410), 641 size=(0, 0), 642 color=(0.5, 0.5, 0.5), 643 maxwidth=230, 644 text='Trophy counts will reset next season.', 645 h_align='center', 646 v_align='center', 647 scale=0.8, 648 shadow=0, 649 flatness=1.0, 650 ) 651 652 self._power_ranking_score_widgets = [] 653 654 self._power_ranking_score_v = v - 56 655 656 h = 707 657 v -= 451 658 659 self._see_more_button = ba.buttonwidget( 660 parent=w_parent, 661 label=self._rdict.seeMoreText, 662 position=(h, v), 663 color=(0.5, 0.5, 0.6), 664 textcolor=(0.7, 0.7, 0.8), 665 size=(230, 60), 666 autoselect=True, 667 on_activate_call=ba.WeakCall(self._on_more_press), 668 ) 669 670 def _on_more_press(self) -> None: 671 our_login_id = ba.internal.get_public_login_id() 672 # our_login_id = _bs.get_account_misc_read_val_2( 673 # 'resolvedAccountID', None) 674 if not self._can_do_more_button or our_login_id is None: 675 ba.playsound(ba.getsound('error')) 676 ba.screenmessage( 677 ba.Lstr(resource='unavailableText'), color=(1, 0, 0) 678 ) 679 return 680 if self._season is None: 681 season_str = '' 682 else: 683 season_str = '&season=' + ( 684 'all_time' if self._season == 'a' else self._season 685 ) 686 if self._league_url_arg != '': 687 league_str = '&league=' + self._league_url_arg 688 else: 689 league_str = '' 690 ba.open_url( 691 ba.internal.get_master_server_address() 692 + '/highscores?list=powerRankings&v=2' 693 + league_str 694 + season_str 695 + '&player=' 696 + our_login_id 697 ) 698 699 def _update_for_league_rank_data(self, data: dict[str, Any] | None) -> None: 700 # pylint: disable=too-many-statements 701 # pylint: disable=too-many-branches 702 # pylint: disable=too-many-locals 703 if not self._root_widget: 704 return 705 accounts = ba.app.accounts_v1 706 in_top = data is not None and data['rank'] is not None 707 eq_text = self._rdict.powerRankingPointsEqualsText 708 pts_txt = self._rdict.powerRankingPointsText 709 num_text = ba.Lstr(resource='numberText').evaluate() 710 do_percent = False 711 finished_season_unranked = False 712 self._can_do_more_button = True 713 extra_text = '' 714 if ba.internal.get_v1_account_state() != 'signed_in': 715 status_text = ( 716 '(' + ba.Lstr(resource='notSignedInText').evaluate() + ')' 717 ) 718 elif in_top: 719 assert data is not None 720 status_text = num_text.replace('${NUMBER}', str(data['rank'])) 721 elif data is not None: 722 try: 723 # handle old seasons where we didn't wind up ranked 724 # at the end.. 725 if not data['scores']: 726 status_text = ( 727 self._rdict.powerRankingFinishedSeasonUnrankedText 728 ) 729 extra_text = '' 730 finished_season_unranked = True 731 self._can_do_more_button = False 732 else: 733 our_points = accounts.get_league_rank_points(data) 734 progress = float(our_points) / max(1, data['scores'][-1][1]) 735 status_text = str(int(progress * 100.0)) + '%' 736 extra_text = ( 737 '\n' 738 + self._rdict.powerRankingPointsToRankedText.replace( 739 '${CURRENT}', str(our_points) 740 ).replace('${REMAINING}', str(data['scores'][-1][1])) 741 ) 742 do_percent = True 743 except Exception: 744 ba.print_exception('Error updating power ranking.') 745 status_text = self._rdict.powerRankingNotInTopText.replace( 746 '${NUMBER}', str(data['listSize']) 747 ) 748 extra_text = '' 749 else: 750 status_text = '-' 751 752 self._season = data['s'] if data is not None else None 753 754 v = self._subcontainerheight - 20 755 popup_was_selected = False 756 if self._season_popup_menu is not None: 757 btn = self._season_popup_menu.get_button() 758 assert self._subcontainer 759 if self._subcontainer.get_selected_child() == btn: 760 popup_was_selected = True 761 btn.delete() 762 season_choices = [] 763 season_choices_display = [] 764 did_first = False 765 self._is_current_season = False 766 if data is not None: 767 # build our list of seasons we have available 768 for ssn in data['sl']: 769 season_choices.append(ssn) 770 if ssn != 'a' and not did_first: 771 season_choices_display.append( 772 ba.Lstr( 773 resource='league.currentSeasonText', 774 subs=[('${NUMBER}', ssn)], 775 ) 776 ) 777 did_first = True 778 # if we either did not specify a season or specified the 779 # first, we're looking at the current.. 780 if self._season in [ssn, None]: 781 self._is_current_season = True 782 elif ssn == 'a': 783 season_choices_display.append( 784 ba.Lstr(resource='league.allTimeText') 785 ) 786 else: 787 season_choices_display.append( 788 ba.Lstr( 789 resource='league.seasonText', 790 subs=[('${NUMBER}', ssn)], 791 ) 792 ) 793 assert self._subcontainer 794 self._season_popup_menu = popup_ui.PopupMenu( 795 parent=self._subcontainer, 796 position=(390, v - 45), 797 width=150, 798 button_size=(200, 50), 799 choices=season_choices, 800 on_value_change_call=ba.WeakCall(self._on_season_change), 801 choices_display=season_choices_display, 802 current_choice=self._season, 803 ) 804 if popup_was_selected: 805 ba.containerwidget( 806 edit=self._subcontainer, 807 selected_child=self._season_popup_menu.get_button(), 808 ) 809 ba.widget(edit=self._see_more_button, show_buffer_bottom=100) 810 ba.widget( 811 edit=self._season_popup_menu.get_button(), 812 up_widget=self._back_button, 813 ) 814 ba.widget( 815 edit=self._back_button, 816 down_widget=self._power_ranking_achievements_button, 817 right_widget=self._season_popup_menu.get_button(), 818 ) 819 820 ba.textwidget( 821 edit=self._league_title_text, 822 text='' 823 if self._season == 'a' 824 else ba.Lstr(resource='league.leagueText'), 825 ) 826 827 if data is None: 828 lname = '' 829 lnum = '' 830 lcolor = (1, 1, 1) 831 self._league_url_arg = '' 832 elif self._season == 'a': 833 lname = ba.Lstr(resource='league.allTimeText').evaluate() 834 lnum = '' 835 lcolor = (1, 1, 1) 836 self._league_url_arg = '' 837 else: 838 lnum = ('[' + str(data['l']['i']) + ']') if data['l']['i2'] else '' 839 lname = ba.Lstr( 840 translate=('leagueNames', data['l']['n']) 841 ).evaluate() 842 lcolor = data['l']['c'] 843 self._league_url_arg = ( 844 data['l']['n'] + '_' + str(data['l']['i']) 845 ).lower() 846 847 to_end_string: ba.Lstr | str 848 if data is None or self._season == 'a' or data['se'] is None: 849 to_end_string = '' 850 show_season_end = False 851 else: 852 show_season_end = True 853 days_to_end = data['se'][0] 854 minutes_to_end = data['se'][1] 855 if days_to_end > 0: 856 to_end_string = ba.Lstr( 857 resource='league.seasonEndsDaysText', 858 subs=[('${NUMBER}', str(days_to_end))], 859 ) 860 elif days_to_end == 0 and minutes_to_end >= 60: 861 to_end_string = ba.Lstr( 862 resource='league.seasonEndsHoursText', 863 subs=[('${NUMBER}', str(minutes_to_end // 60))], 864 ) 865 elif days_to_end == 0 and minutes_to_end >= 0: 866 to_end_string = ba.Lstr( 867 resource='league.seasonEndsMinutesText', 868 subs=[('${NUMBER}', str(minutes_to_end))], 869 ) 870 else: 871 to_end_string = ba.Lstr( 872 resource='league.seasonEndedDaysAgoText', 873 subs=[('${NUMBER}', str(-(days_to_end + 1)))], 874 ) 875 876 ba.textwidget(edit=self._season_ends_text, text=to_end_string) 877 ba.textwidget( 878 edit=self._trophy_counts_reset_text, 879 text=ba.Lstr(resource='league.trophyCountsResetText') 880 if self._is_current_season and show_season_end 881 else '', 882 ) 883 884 ba.textwidget(edit=self._league_text, text=lname, color=lcolor) 885 l_text_width = min( 886 self._league_text_maxwidth, 887 ba.internal.get_string_width(lname, suppress_warning=True) 888 * self._league_text_scale, 889 ) 890 ba.textwidget( 891 edit=self._league_number_text, 892 text=lnum, 893 color=lcolor, 894 position=( 895 self._league_number_base_pos[0] + l_text_width * 0.5 + 8, 896 self._league_number_base_pos[1] + 10, 897 ), 898 ) 899 ba.textwidget( 900 edit=self._to_ranked_text, 901 text=ba.Lstr(resource='coopSelectWindow.toRankedText').evaluate() 902 + '' 903 + extra_text 904 if do_percent 905 else '', 906 ) 907 908 ba.textwidget( 909 edit=self._your_power_ranking_text, 910 text=ba.Lstr( 911 resource='rankText', 912 fallback_resource='coopSelectWindow.yourPowerRankingText', 913 ) 914 if (not do_percent) 915 else '', 916 ) 917 918 ba.textwidget( 919 edit=self._power_ranking_rank_text, 920 position=(473, v - 70 - (170 if do_percent else 220)), 921 text=status_text, 922 big=(in_top or do_percent), 923 scale=3.0 924 if (in_top or do_percent) 925 else 0.7 926 if finished_season_unranked 927 else 1.0, 928 ) 929 930 if self._activity_mult_button is not None: 931 if data is None or data['act'] is None: 932 ba.buttonwidget( 933 edit=self._activity_mult_button, 934 textcolor=(0.7, 0.7, 0.8, 0.5), 935 icon_color=(0.5, 0, 0.5, 0.3), 936 ) 937 ba.textwidget(edit=self._activity_mult_text, text=' -') 938 else: 939 ba.buttonwidget( 940 edit=self._activity_mult_button, 941 textcolor=(0.7, 0.7, 0.8, 1.0), 942 icon_color=(0.5, 0, 0.5, 1.0), 943 ) 944 # pylint: disable=consider-using-f-string 945 ba.textwidget( 946 edit=self._activity_mult_text, 947 text='x ' + ('%.2f' % data['act']), 948 ) 949 950 have_pro = False if data is None else data['p'] 951 pro_mult = ( 952 1.0 953 + float( 954 ba.internal.get_v1_account_misc_read_val( 955 'proPowerRankingBoost', 0.0 956 ) 957 ) 958 * 0.01 959 ) 960 # pylint: disable=consider-using-f-string 961 ba.textwidget( 962 edit=self._pro_mult_text, 963 text=' -' 964 if (data is None or not have_pro) 965 else 'x ' + ('%.2f' % pro_mult), 966 ) 967 ba.buttonwidget( 968 edit=self._pro_mult_button, 969 textcolor=(0.7, 0.7, 0.8, (1.0 if have_pro else 0.5)), 970 icon_color=(0.5, 0, 0.5) if have_pro else (0.5, 0, 0.5, 0.2), 971 ) 972 ba.buttonwidget( 973 edit=self._power_ranking_achievements_button, 974 label=('' if data is None else (str(data['a']) + ' ')) 975 + ba.Lstr(resource='achievementsText').evaluate(), 976 ) 977 978 # for the achievement value, use the number they gave us for 979 # non-current seasons; otherwise calc our own 980 total_ach_value = 0 981 for ach in ba.app.ach.achievements: 982 if ach.complete: 983 total_ach_value += ach.power_ranking_value 984 if self._season != 'a' and not self._is_current_season: 985 if data is not None and 'at' in data: 986 total_ach_value = data['at'] 987 988 ba.textwidget( 989 edit=self._power_ranking_achievement_total_text, 990 text='-' 991 if data is None 992 else ('+ ' + pts_txt.replace('${NUMBER}', str(total_ach_value))), 993 ) 994 995 total_trophies_count = accounts.get_league_rank_points( 996 data, 'trophyCount' 997 ) 998 total_trophies_value = accounts.get_league_rank_points(data, 'trophies') 999 ba.buttonwidget( 1000 edit=self._power_ranking_trophies_button, 1001 label=('' if data is None else (str(total_trophies_count) + ' ')) 1002 + ba.Lstr(resource='trophiesText').evaluate(), 1003 ) 1004 ba.textwidget( 1005 edit=self._power_ranking_trophies_total_text, 1006 text='-' 1007 if data is None 1008 else ( 1009 '+ ' + pts_txt.replace('${NUMBER}', str(total_trophies_value)) 1010 ), 1011 ) 1012 1013 ba.textwidget( 1014 edit=self._power_ranking_total_text, 1015 text='-' 1016 if data is None 1017 else eq_text.replace( 1018 '${NUMBER}', str(accounts.get_league_rank_points(data)) 1019 ), 1020 ) 1021 for widget in self._power_ranking_score_widgets: 1022 widget.delete() 1023 self._power_ranking_score_widgets = [] 1024 1025 scores = data['scores'] if data is not None else [] 1026 tally_color = (0.5, 0.6, 0.8) 1027 w_parent = self._subcontainer 1028 v2 = self._power_ranking_score_v 1029 1030 for score in scores: 1031 h2 = 680 1032 is_us = score[3] 1033 self._power_ranking_score_widgets.append( 1034 ba.textwidget( 1035 parent=w_parent, 1036 position=(h2 - 20, v2), 1037 size=(0, 0), 1038 color=(1, 1, 1) if is_us else (0.6, 0.6, 0.7), 1039 maxwidth=40, 1040 flatness=1.0, 1041 shadow=0.0, 1042 text=num_text.replace('${NUMBER}', str(score[0])), 1043 h_align='right', 1044 v_align='center', 1045 scale=0.5, 1046 ) 1047 ) 1048 self._power_ranking_score_widgets.append( 1049 ba.textwidget( 1050 parent=w_parent, 1051 position=(h2 + 20, v2), 1052 size=(0, 0), 1053 color=(1, 1, 1) if is_us else tally_color, 1054 maxwidth=60, 1055 text=str(score[1]), 1056 flatness=1.0, 1057 shadow=0.0, 1058 h_align='center', 1059 v_align='center', 1060 scale=0.7, 1061 ) 1062 ) 1063 txt = ba.textwidget( 1064 parent=w_parent, 1065 position=(h2 + 60, v2 - (28 * 0.5) / 0.9), 1066 size=(210 / 0.9, 28), 1067 color=(1, 1, 1) if is_us else (0.6, 0.6, 0.6), 1068 maxwidth=210, 1069 flatness=1.0, 1070 shadow=0.0, 1071 autoselect=True, 1072 selectable=True, 1073 click_activate=True, 1074 text=score[2], 1075 h_align='left', 1076 v_align='center', 1077 scale=0.9, 1078 ) 1079 self._power_ranking_score_widgets.append(txt) 1080 ba.textwidget( 1081 edit=txt, 1082 on_activate_call=ba.Call( 1083 self._show_account_info, score[4], txt 1084 ), 1085 ) 1086 assert self._season_popup_menu is not None 1087 ba.widget( 1088 edit=txt, left_widget=self._season_popup_menu.get_button() 1089 ) 1090 v2 -= 28 1091 1092 def _show_account_info( 1093 self, account_id: str, textwidget: ba.Widget 1094 ) -> None: 1095 from bastd.ui.account import viewer 1096 1097 ba.playsound(ba.getsound('swish')) 1098 viewer.AccountViewerWindow( 1099 account_id=account_id, position=textwidget.get_screen_space_center() 1100 ) 1101 1102 def _on_season_change(self, value: str) -> None: 1103 self._requested_season = value 1104 self._last_power_ranking_query_time = None # make sure we update asap 1105 self._update(show=True) 1106 1107 def _save_state(self) -> None: 1108 pass 1109 1110 def _back(self) -> None: 1111 from bastd.ui.coop.browser import CoopBrowserWindow 1112 1113 self._save_state() 1114 ba.containerwidget( 1115 edit=self._root_widget, transition=self._transition_out 1116 ) 1117 if not self._modal: 1118 ba.app.ui.set_main_menu_window( 1119 CoopBrowserWindow(transition='in_left').get_root_widget() 1120 )
Window for showing league rank.
LeagueRankWindow( transition: str = 'in_right', modal: bool = False, origin_widget: _ba.Widget | None = None)
23 def __init__( 24 self, 25 transition: str = 'in_right', 26 modal: bool = False, 27 origin_widget: ba.Widget | None = None, 28 ): 29 ba.set_analytics_screen('League Rank Window') 30 31 self._league_rank_data: dict[str, Any] | None = None 32 self._modal = modal 33 34 # If they provided an origin-widget, scale up from that. 35 scale_origin: tuple[float, float] | None 36 if origin_widget is not None: 37 self._transition_out = 'out_scale' 38 scale_origin = origin_widget.get_screen_space_center() 39 transition = 'in_scale' 40 else: 41 self._transition_out = 'out_right' 42 scale_origin = None 43 44 uiscale = ba.app.ui.uiscale 45 self._width = 1320 if uiscale is ba.UIScale.SMALL else 1120 46 x_inset = 100 if uiscale is ba.UIScale.SMALL else 0 47 self._height = ( 48 657 49 if uiscale is ba.UIScale.SMALL 50 else 710 51 if uiscale is ba.UIScale.MEDIUM 52 else 800 53 ) 54 self._r = 'coopSelectWindow' 55 self._rdict = ba.app.lang.get_resource(self._r) 56 top_extra = 20 if uiscale is ba.UIScale.SMALL else 0 57 58 self._league_url_arg = '' 59 60 self._is_current_season = False 61 self._can_do_more_button = True 62 63 super().__init__( 64 root_widget=ba.containerwidget( 65 size=(self._width, self._height + top_extra), 66 stack_offset=(0, -15) 67 if uiscale is ba.UIScale.SMALL 68 else (0, 10) 69 if uiscale is ba.UIScale.MEDIUM 70 else (0, 0), 71 transition=transition, 72 scale_origin_stack_offset=scale_origin, 73 scale=( 74 1.2 75 if uiscale is ba.UIScale.SMALL 76 else 0.93 77 if uiscale is ba.UIScale.MEDIUM 78 else 0.8 79 ), 80 ) 81 ) 82 83 self._back_button = btn = ba.buttonwidget( 84 parent=self._root_widget, 85 position=( 86 75 + x_inset, 87 self._height - 87 - (4 if uiscale is ba.UIScale.SMALL else 0), 88 ), 89 size=(120, 60), 90 scale=1.2, 91 autoselect=True, 92 label=ba.Lstr(resource='doneText' if self._modal else 'backText'), 93 button_type=None if self._modal else 'back', 94 on_activate_call=self._back, 95 ) 96 97 self._title_text = ba.textwidget( 98 parent=self._root_widget, 99 position=(self._width * 0.5, self._height - 56), 100 size=(0, 0), 101 text=ba.Lstr( 102 resource='league.leagueRankText', 103 fallback_resource='coopSelectWindow.powerRankingText', 104 ), 105 h_align='center', 106 color=ba.app.ui.title_color, 107 scale=1.4, 108 maxwidth=600, 109 v_align='center', 110 ) 111 112 ba.buttonwidget( 113 edit=btn, 114 button_type='backSmall', 115 position=( 116 75 + x_inset, 117 self._height - 87 - (2 if uiscale is ba.UIScale.SMALL else 0), 118 ), 119 size=(60, 55), 120 label=ba.charstr(ba.SpecialChar.BACK), 121 ) 122 123 self._scroll_width = self._width - (130 + 2 * x_inset) 124 self._scroll_height = self._height - 160 125 self._scrollwidget = ba.scrollwidget( 126 parent=self._root_widget, 127 highlight=False, 128 position=(65 + x_inset, 70), 129 size=(self._scroll_width, self._scroll_height), 130 center_small_content=True, 131 ) 132 ba.widget(edit=self._scrollwidget, autoselect=True) 133 ba.containerwidget(edit=self._scrollwidget, claims_left_right=True) 134 ba.containerwidget( 135 edit=self._root_widget, 136 cancel_button=self._back_button, 137 selected_child=self._back_button, 138 ) 139 140 self._last_power_ranking_query_time: float | None = None 141 self._doing_power_ranking_query = False 142 143 self._subcontainer: ba.Widget | None = None 144 self._subcontainerwidth = 800 145 self._subcontainerheight = 483 146 self._power_ranking_score_widgets: list[ba.Widget] = [] 147 148 self._season_popup_menu: popup_ui.PopupMenu | None = None 149 self._requested_season: str | None = None 150 self._season: str | None = None 151 152 # take note of our account state; we'll refresh later if this changes 153 self._account_state = ba.internal.get_v1_account_state() 154 155 self._refresh() 156 self._restore_state() 157 158 # if we've got cached power-ranking data already, display it 159 info = ba.app.accounts_v1.get_cached_league_rank_data() 160 if info is not None: 161 self._update_for_league_rank_data(info) 162 163 self._update_timer = ba.Timer( 164 1.0, 165 ba.WeakCall(self._update), 166 timetype=ba.TimeType.REAL, 167 repeat=True, 168 ) 169 self._update(show=(info is None))
Inherited Members
- ba.ui.Window
- get_root_widget