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