bauiv1lib.league.rankwindow

UI related to league rank.

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

Window for showing league rank.

LeagueRankWindow( transition: str = 'in_right', modal: bool = False, origin_widget: _bauiv1.Widget | None = None)
 23    def __init__(
 24        self,
 25        transition: str = 'in_right',
 26        modal: bool = False,
 27        origin_widget: bui.Widget | None = None,
 28    ):
 29        # pylint: disable=too-many-statements
 30        plus = bui.app.plus
 31        assert plus is not None
 32
 33        bui.set_analytics_screen('League Rank Window')
 34
 35        self._league_rank_data: dict[str, Any] | None = None
 36        self._modal = modal
 37
 38        self._power_ranking_achievements_button: bui.Widget | None = None
 39        self._pro_mult_button: bui.Widget | None = None
 40        self._power_ranking_trophies_button: bui.Widget | None = None
 41        self._league_title_text: bui.Widget | None = None
 42        self._league_text: bui.Widget | None = None
 43        self._league_number_text: bui.Widget | None = None
 44        self._your_power_ranking_text: bui.Widget | None = None
 45        self._season_ends_text: bui.Widget | None = None
 46        self._power_ranking_rank_text: bui.Widget | None = None
 47        self._to_ranked_text: bui.Widget | None = None
 48        self._trophy_counts_reset_text: bui.Widget | None = None
 49
 50        # If they provided an origin-widget, scale up from that.
 51        scale_origin: tuple[float, float] | None
 52        if origin_widget is not None:
 53            self._transition_out = 'out_scale'
 54            scale_origin = origin_widget.get_screen_space_center()
 55            transition = 'in_scale'
 56        else:
 57            self._transition_out = 'out_right'
 58            scale_origin = None
 59
 60        assert bui.app.classic is not None
 61        uiscale = bui.app.ui_v1.uiscale
 62        self._width = 1320 if uiscale is bui.UIScale.SMALL else 1120
 63        x_inset = 100 if uiscale is bui.UIScale.SMALL else 0
 64        self._height = (
 65            657
 66            if uiscale is bui.UIScale.SMALL
 67            else 710 if uiscale is bui.UIScale.MEDIUM else 800
 68        )
 69        self._r = 'coopSelectWindow'
 70        self._rdict = bui.app.lang.get_resource(self._r)
 71        top_extra = 20 if uiscale is bui.UIScale.SMALL else 0
 72
 73        self._league_url_arg = ''
 74
 75        self._is_current_season = False
 76        self._can_do_more_button = True
 77
 78        super().__init__(
 79            root_widget=bui.containerwidget(
 80                size=(self._width, self._height + top_extra),
 81                stack_offset=(
 82                    (0, -15)
 83                    if uiscale is bui.UIScale.SMALL
 84                    else (0, 10) if uiscale is bui.UIScale.MEDIUM else (0, 0)
 85                ),
 86                transition=transition,
 87                scale_origin_stack_offset=scale_origin,
 88                scale=(
 89                    1.2
 90                    if uiscale is bui.UIScale.SMALL
 91                    else 0.93 if uiscale is bui.UIScale.MEDIUM else 0.8
 92                ),
 93            )
 94        )
 95
 96        self._back_button = btn = bui.buttonwidget(
 97            parent=self._root_widget,
 98            position=(
 99                75 + x_inset,
100                self._height - 87 - (4 if uiscale is bui.UIScale.SMALL else 0),
101            ),
102            size=(120, 60),
103            scale=1.2,
104            autoselect=True,
105            label=bui.Lstr(resource='doneText' if self._modal else 'backText'),
106            button_type=None if self._modal else 'back',
107            on_activate_call=self._back,
108        )
109
110        self._title_text = bui.textwidget(
111            parent=self._root_widget,
112            position=(self._width * 0.5, self._height - 56),
113            size=(0, 0),
114            text=bui.Lstr(
115                resource='league.leagueRankText',
116                fallback_resource='coopSelectWindow.powerRankingText',
117            ),
118            h_align='center',
119            color=bui.app.ui_v1.title_color,
120            scale=1.4,
121            maxwidth=600,
122            v_align='center',
123        )
124
125        bui.buttonwidget(
126            edit=btn,
127            button_type='backSmall',
128            position=(
129                75 + x_inset,
130                self._height - 87 - (2 if uiscale is bui.UIScale.SMALL else 0),
131            ),
132            size=(60, 55),
133            label=bui.charstr(bui.SpecialChar.BACK),
134        )
135
136        self._scroll_width = self._width - (130 + 2 * x_inset)
137        self._scroll_height = self._height - 160
138        self._scrollwidget = bui.scrollwidget(
139            parent=self._root_widget,
140            highlight=False,
141            position=(65 + x_inset, 70),
142            size=(self._scroll_width, self._scroll_height),
143            center_small_content=True,
144        )
145        bui.widget(edit=self._scrollwidget, autoselect=True)
146        bui.containerwidget(edit=self._scrollwidget, claims_left_right=True)
147        bui.containerwidget(
148            edit=self._root_widget,
149            cancel_button=self._back_button,
150            selected_child=self._back_button,
151        )
152
153        self._last_power_ranking_query_time: float | None = None
154        self._doing_power_ranking_query = False
155
156        self._subcontainer: bui.Widget | None = None
157        self._subcontainerwidth = 800
158        self._subcontainerheight = 483
159        self._power_ranking_score_widgets: list[bui.Widget] = []
160
161        self._season_popup_menu: PopupMenu | None = None
162        self._requested_season: str | None = None
163        self._season: str | None = None
164
165        # take note of our account state; we'll refresh later if this changes
166        self._account_state = plus.get_v1_account_state()
167
168        self._refresh()
169        self._restore_state()
170
171        # if we've got cached power-ranking data already, display it
172        assert bui.app.classic is not None
173        info = bui.app.classic.accounts.get_cached_league_rank_data()
174        if info is not None:
175            self._update_for_league_rank_data(info)
176
177        self._update_timer = bui.AppTimer(
178            1.0, bui.WeakCall(self._update), repeat=True
179        )
180        self._update(show=info is None)
Inherited Members
bauiv1._uitypes.Window
get_root_widget