bauiv1lib.league.rankwindow

UI related to league rank.

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

Window for showing league rank.

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

Create a MainWindow given a root widget and transition info.

Automatically handles in and out transitions on the provided widget, so there is no need to set transitions when creating it.

Inherited Members
bauiv1._uitypes.MainWindow
main_window_back_state
main_window_is_top_level
main_window_close
main_window_has_control
main_window_back
main_window_replace
on_main_window_close
get_main_window_state
bauiv1._uitypes.Window
get_root_widget