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