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

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
 68            if uiscale is bui.UIScale.MEDIUM
 69            else 800
 70        )
 71        self._r = 'coopSelectWindow'
 72        self._rdict = bui.app.lang.get_resource(self._r)
 73        top_extra = 20 if uiscale is bui.UIScale.SMALL else 0
 74
 75        self._league_url_arg = ''
 76
 77        self._is_current_season = False
 78        self._can_do_more_button = True
 79
 80        super().__init__(
 81            root_widget=bui.containerwidget(
 82                size=(self._width, self._height + top_extra),
 83                stack_offset=(0, -15)
 84                if uiscale is bui.UIScale.SMALL
 85                else (0, 10)
 86                if uiscale is bui.UIScale.MEDIUM
 87                else (0, 0),
 88                transition=transition,
 89                scale_origin_stack_offset=scale_origin,
 90                scale=(
 91                    1.2
 92                    if uiscale is bui.UIScale.SMALL
 93                    else 0.93
 94                    if uiscale is bui.UIScale.MEDIUM
 95                    else 0.8
 96                ),
 97            )
 98        )
 99
100        self._back_button = btn = bui.buttonwidget(
101            parent=self._root_widget,
102            position=(
103                75 + x_inset,
104                self._height - 87 - (4 if uiscale is bui.UIScale.SMALL else 0),
105            ),
106            size=(120, 60),
107            scale=1.2,
108            autoselect=True,
109            label=bui.Lstr(resource='doneText' if self._modal else 'backText'),
110            button_type=None if self._modal else 'back',
111            on_activate_call=self._back,
112        )
113
114        self._title_text = bui.textwidget(
115            parent=self._root_widget,
116            position=(self._width * 0.5, self._height - 56),
117            size=(0, 0),
118            text=bui.Lstr(
119                resource='league.leagueRankText',
120                fallback_resource='coopSelectWindow.powerRankingText',
121            ),
122            h_align='center',
123            color=bui.app.ui_v1.title_color,
124            scale=1.4,
125            maxwidth=600,
126            v_align='center',
127        )
128
129        bui.buttonwidget(
130            edit=btn,
131            button_type='backSmall',
132            position=(
133                75 + x_inset,
134                self._height - 87 - (2 if uiscale is bui.UIScale.SMALL else 0),
135            ),
136            size=(60, 55),
137            label=bui.charstr(bui.SpecialChar.BACK),
138        )
139
140        self._scroll_width = self._width - (130 + 2 * x_inset)
141        self._scroll_height = self._height - 160
142        self._scrollwidget = bui.scrollwidget(
143            parent=self._root_widget,
144            highlight=False,
145            position=(65 + x_inset, 70),
146            size=(self._scroll_width, self._scroll_height),
147            center_small_content=True,
148        )
149        bui.widget(edit=self._scrollwidget, autoselect=True)
150        bui.containerwidget(edit=self._scrollwidget, claims_left_right=True)
151        bui.containerwidget(
152            edit=self._root_widget,
153            cancel_button=self._back_button,
154            selected_child=self._back_button,
155        )
156
157        self._last_power_ranking_query_time: float | None = None
158        self._doing_power_ranking_query = False
159
160        self._subcontainer: bui.Widget | None = None
161        self._subcontainerwidth = 800
162        self._subcontainerheight = 483
163        self._power_ranking_score_widgets: list[bui.Widget] = []
164
165        self._season_popup_menu: PopupMenu | None = None
166        self._requested_season: str | None = None
167        self._season: str | None = None
168
169        # take note of our account state; we'll refresh later if this changes
170        self._account_state = plus.get_v1_account_state()
171
172        self._refresh()
173        self._restore_state()
174
175        # if we've got cached power-ranking data already, display it
176        assert bui.app.classic is not None
177        info = bui.app.classic.accounts.get_cached_league_rank_data()
178        if info is not None:
179            self._update_for_league_rank_data(info)
180
181        self._update_timer = bui.AppTimer(
182            1.0, bui.WeakCall(self._update), repeat=True
183        )
184        self._update(show=info is None)
Inherited Members
bauiv1._uitypes.Window
get_root_widget