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