bauiv1lib.league.rankbutton

Provides a button showing league rank.

  1# Released under the MIT License. See LICENSE for details.
  2#
  3"""Provides a button showing league rank."""
  4
  5from __future__ import annotations
  6
  7import logging
  8from typing import TYPE_CHECKING
  9
 10import bauiv1 as bui
 11
 12if TYPE_CHECKING:
 13    from typing import Any, Callable
 14
 15
 16class LeagueRankButton:
 17    """Button showing league rank."""
 18
 19    def __init__(
 20        self,
 21        parent: bui.Widget,
 22        position: tuple[float, float],
 23        size: tuple[float, float],
 24        scale: float,
 25        *,
 26        on_activate_call: Callable[[], Any] | None = None,
 27        transition_delay: float | None = None,
 28        color: tuple[float, float, float] | None = None,
 29        textcolor: tuple[float, float, float] | None = None,
 30        smooth_update_delay: float | None = None,
 31    ):
 32        if on_activate_call is None:
 33            on_activate_call = bui.WeakCall(self._default_on_activate_call)
 34        self._on_activate_call = on_activate_call
 35        if smooth_update_delay is None:
 36            smooth_update_delay = 1.0
 37        self._smooth_update_delay = smooth_update_delay
 38        self._size = size
 39        self._scale = scale
 40        if color is None:
 41            color = (0.5, 0.6, 0.5)
 42        if textcolor is None:
 43            textcolor = (1, 1, 1)
 44        self._color = color
 45        self._textcolor = textcolor
 46        self._header_color = (0.8, 0.8, 2.0)
 47        self._parent = parent
 48        self._position: tuple[float, float] = (0.0, 0.0)
 49
 50        self._button = bui.buttonwidget(
 51            parent=parent,
 52            size=size,
 53            label='',
 54            button_type='square',
 55            scale=scale,
 56            autoselect=True,
 57            on_activate_call=self._on_activate,
 58            transition_delay=transition_delay,
 59            color=color,
 60        )
 61
 62        self._title_text = bui.textwidget(
 63            parent=parent,
 64            size=(0, 0),
 65            draw_controller=self._button,
 66            h_align='center',
 67            v_align='center',
 68            maxwidth=size[0] * scale * 0.85,
 69            text=bui.Lstr(
 70                resource='league.leagueRankText',
 71                fallback_resource='coopSelectWindow.powerRankingText',
 72            ),
 73            color=self._header_color,
 74            flatness=1.0,
 75            shadow=1.0,
 76            scale=scale * 0.5,
 77            transition_delay=transition_delay,
 78        )
 79
 80        self._value_text = bui.textwidget(
 81            parent=parent,
 82            size=(0, 0),
 83            h_align='center',
 84            v_align='center',
 85            maxwidth=size[0] * scale * 0.85,
 86            text='-',
 87            draw_controller=self._button,
 88            big=True,
 89            scale=scale,
 90            transition_delay=transition_delay,
 91            color=textcolor,
 92        )
 93
 94        plus = bui.app.plus
 95        assert plus is not None
 96
 97        self._smooth_percent: float | None = None
 98        self._percent: int | None = None
 99        self._smooth_rank: float | None = None
100        self._rank: int | None = None
101        self._ticking_sound: bui.Sound | None = None
102        self._smooth_increase_speed = 1.0
103        self._league: str | None = None
104        self._improvement_text: str | None = None
105
106        self._smooth_update_timer: bui.AppTimer | None = None
107
108        # Take note of our account state; we'll refresh later if this changes.
109        self._account_state_num = plus.get_v1_account_state_num()
110        self._last_power_ranking_query_time: float | None = None
111        self._doing_power_ranking_query = False
112        self.set_position(position)
113        self._bg_flash = False
114        self._update_timer = bui.AppTimer(
115            1.0, bui.WeakCall(self._update), repeat=True
116        )
117        self._update()
118
119        # If we've got cached power-ranking data already, apply it.
120        assert bui.app.classic is not None
121        data = bui.app.classic.accounts.get_cached_league_rank_data()
122        if data is not None:
123            self._update_for_league_rank_data(data)
124
125    def _on_activate(self) -> None:
126        bui.increment_analytics_count('League rank button press')
127        self._on_activate_call()
128
129    def __del__(self) -> None:
130        if self._ticking_sound is not None:
131            self._ticking_sound.stop()
132            self._ticking_sound = None
133
134    def _start_smooth_update(self) -> None:
135        self._smooth_update_timer = bui.AppTimer(
136            0.05, bui.WeakCall(self._smooth_update), repeat=True
137        )
138
139    def _smooth_update(self) -> None:
140        # pylint: disable=too-many-branches
141        # pylint: disable=too-many-statements
142        try:
143            if not self._button:
144                return
145            if self._ticking_sound is None:
146                self._ticking_sound = bui.getsound('scoreIncrease')
147                self._ticking_sound.play()
148            self._bg_flash = not self._bg_flash
149            color_used = (
150                (self._color[0] * 2, self._color[1] * 2, self._color[2] * 2)
151                if self._bg_flash
152                else self._color
153            )
154            textcolor_used = (1, 1, 1) if self._bg_flash else self._textcolor
155            header_color_used = (
156                (1, 1, 1) if self._bg_flash else self._header_color
157            )
158
159            if self._rank is not None:
160                assert self._smooth_rank is not None
161                self._smooth_rank -= 1.0 * self._smooth_increase_speed
162                finished = int(self._smooth_rank) <= self._rank
163            elif self._smooth_percent is not None:
164                self._smooth_percent += 1.0 * self._smooth_increase_speed
165                assert self._percent is not None
166                finished = int(self._smooth_percent) >= self._percent
167            else:
168                finished = True
169            if finished:
170                if self._rank is not None:
171                    self._smooth_rank = float(self._rank)
172                elif self._percent is not None:
173                    self._smooth_percent = float(self._percent)
174                color_used = self._color
175                textcolor_used = self._textcolor
176                self._smooth_update_timer = None
177                if self._ticking_sound is not None:
178                    self._ticking_sound.stop()
179                    self._ticking_sound = None
180                bui.getsound('cashRegister2').play()
181                assert self._improvement_text is not None
182                diff_text = bui.textwidget(
183                    parent=self._parent,
184                    size=(0, 0),
185                    h_align='center',
186                    v_align='center',
187                    text='+' + self._improvement_text + '!',
188                    position=(
189                        self._position[0] + self._size[0] * 0.5 * self._scale,
190                        self._position[1] + self._size[1] * -0.2 * self._scale,
191                    ),
192                    color=(0, 1, 0),
193                    flatness=1.0,
194                    shadow=0.0,
195                    scale=self._scale * 0.7,
196                )
197
198                def safe_delete(widget: bui.Widget) -> None:
199                    if widget:
200                        widget.delete()
201
202                bui.apptimer(2.0, bui.Call(safe_delete, diff_text))
203            status_text: str | bui.Lstr
204            if self._rank is not None:
205                assert self._smooth_rank is not None
206                status_text = bui.Lstr(
207                    resource='numberText',
208                    subs=[('${NUMBER}', str(int(self._smooth_rank)))],
209                )
210            elif self._smooth_percent is not None:
211                status_text = str(int(self._smooth_percent)) + '%'
212            else:
213                status_text = '-'
214            bui.textwidget(
215                edit=self._value_text, text=status_text, color=textcolor_used
216            )
217            bui.textwidget(edit=self._title_text, color=header_color_used)
218            bui.buttonwidget(edit=self._button, color=color_used)
219
220        except Exception:
221            logging.exception('Error doing smooth update.')
222            self._smooth_update_timer = None
223
224    def _update_for_league_rank_data(self, data: dict[str, Any] | None) -> None:
225        # pylint: disable=too-many-branches
226        # pylint: disable=too-many-statements
227
228        plus = bui.app.plus
229        assert plus is not None
230
231        # If our button has died, ignore.
232        if not self._button:
233            return
234
235        status_text: str | bui.Lstr
236
237        in_top = data is not None and data['rank'] is not None
238        do_percent = False
239        if data is None or plus.get_v1_account_state() != 'signed_in':
240            self._percent = self._rank = None
241            status_text = '-'
242        elif in_top:
243            self._percent = None
244            self._rank = data['rank']
245            prev_league = self._league
246            self._league = data['l']
247
248            # If this is the first set, league has changed, or rank has gotten
249            # worse, snap the smooth value immediately.
250            assert self._rank is not None
251            if (
252                self._smooth_rank is None
253                or prev_league != self._league
254                or self._rank > int(self._smooth_rank)
255            ):
256                self._smooth_rank = float(self._rank)
257            status_text = bui.Lstr(
258                resource='numberText',
259                subs=[('${NUMBER}', str(int(self._smooth_rank)))],
260            )
261        else:
262            try:
263                if not data['scores'] or data['scores'][-1][1] <= 0:
264                    self._percent = self._rank = None
265                    status_text = '-'
266                else:
267                    assert bui.app.classic is not None
268                    our_points = (
269                        bui.app.classic.accounts.get_league_rank_points(data)
270                    )
271                    progress = float(our_points) / data['scores'][-1][1]
272                    self._percent = int(progress * 100.0)
273                    self._rank = None
274                    do_percent = True
275                    prev_league = self._league
276                    self._league = data['l']
277
278                    # If this is the first set, league has changed, or percent
279                    # has decreased, snap the smooth value immediately.
280                    if (
281                        self._smooth_percent is None
282                        or prev_league != self._league
283                        or self._percent < int(self._smooth_percent)
284                    ):
285                        self._smooth_percent = float(self._percent)
286                    status_text = str(int(self._smooth_percent)) + '%'
287
288            except Exception:
289                logging.exception('Error updating power ranking.')
290                self._percent = self._rank = None
291                status_text = '-'
292
293        # If we're doing a smooth update, set a timer.
294        if (
295            self._rank is not None
296            and self._smooth_rank is not None
297            and int(self._smooth_rank) != self._rank
298        ):
299            self._improvement_text = str(
300                -(int(self._rank) - int(self._smooth_rank))
301            )
302            diff = abs(self._rank - self._smooth_rank)
303            if diff > 100:
304                self._smooth_increase_speed = diff / 80.0
305            elif diff > 50:
306                self._smooth_increase_speed = diff / 70.0
307            elif diff > 25:
308                self._smooth_increase_speed = diff / 55.0
309            else:
310                self._smooth_increase_speed = diff / 40.0
311            self._smooth_increase_speed = max(0.4, self._smooth_increase_speed)
312            bui.apptimer(
313                self._smooth_update_delay,
314                bui.WeakCall(self._start_smooth_update),
315            )
316
317        if (
318            self._percent is not None
319            and self._smooth_percent is not None
320            and int(self._smooth_percent) != self._percent
321        ):
322            self._improvement_text = str(
323                (int(self._percent) - int(self._smooth_percent))
324            )
325            self._smooth_increase_speed = 0.3
326            bui.apptimer(
327                self._smooth_update_delay,
328                bui.WeakCall(self._start_smooth_update),
329            )
330
331        if do_percent:
332            bui.textwidget(
333                edit=self._title_text,
334                text=bui.Lstr(resource='coopSelectWindow.toRankedText'),
335            )
336        else:
337            try:
338                assert data is not None
339                txt = bui.Lstr(
340                    resource='league.leagueFullText',
341                    subs=[
342                        (
343                            '${NAME}',
344                            bui.Lstr(translate=('leagueNames', data['l']['n'])),
345                        ),
346                    ],
347                )
348                t_color = data['l']['c']
349            except Exception:
350                txt = bui.Lstr(
351                    resource='league.leagueRankText',
352                    fallback_resource='coopSelectWindow.powerRankingText',
353                )
354                assert bui.app.classic is not None
355                t_color = bui.app.ui_v1.title_color
356            bui.textwidget(edit=self._title_text, text=txt, color=t_color)
357        bui.textwidget(edit=self._value_text, text=status_text)
358
359    def _on_power_ranking_query_response(
360        self, data: dict[str, Any] | None
361    ) -> None:
362        self._doing_power_ranking_query = False
363        assert bui.app.classic is not None
364        bui.app.classic.accounts.cache_league_rank_data(data)
365        self._update_for_league_rank_data(data)
366
367    def _update(self) -> None:
368        cur_time = bui.apptime()
369
370        plus = bui.app.plus
371        assert plus is not None
372
373        # If our account state has changed, refresh our UI.
374        account_state_num = plus.get_v1_account_state_num()
375        if account_state_num != self._account_state_num:
376            self._account_state_num = account_state_num
377
378            # And power ranking too...
379            if not self._doing_power_ranking_query:
380                self._last_power_ranking_query_time = None
381
382        # Send off a new power-ranking query if its been
383        # long enough or whatnot.
384        if not self._doing_power_ranking_query and (
385            self._last_power_ranking_query_time is None
386            or cur_time - self._last_power_ranking_query_time > 30.0
387        ):
388            self._last_power_ranking_query_time = cur_time
389            self._doing_power_ranking_query = True
390            plus.power_ranking_query(
391                callback=bui.WeakCall(self._on_power_ranking_query_response)
392            )
393
394    def _default_on_activate_call(self) -> None:
395        # pylint: disable=cyclic-import
396        # from bauiv1lib.league.rankwindow import LeagueRankWindow
397
398        raise RuntimeError()
399        # LeagueRankWindow(modal=True, origin_widget=self._button)
400
401    def set_position(self, position: tuple[float, float]) -> None:
402        """Set the button's position."""
403        self._position = position
404        if not self._button:
405            return
406        bui.buttonwidget(edit=self._button, position=self._position)
407        bui.textwidget(
408            edit=self._title_text,
409            position=(
410                self._position[0] + self._size[0] * 0.5 * self._scale,
411                self._position[1] + self._size[1] * 0.82 * self._scale,
412            ),
413        )
414        bui.textwidget(
415            edit=self._value_text,
416            position=(
417                self._position[0] + self._size[0] * 0.5 * self._scale,
418                self._position[1] + self._size[1] * 0.36 * self._scale,
419            ),
420        )
421
422    def get_button(self) -> bui.Widget:
423        """Return the underlying button bui.Widget>"""
424        return self._button
class LeagueRankButton:
 17class LeagueRankButton:
 18    """Button showing league rank."""
 19
 20    def __init__(
 21        self,
 22        parent: bui.Widget,
 23        position: tuple[float, float],
 24        size: tuple[float, float],
 25        scale: float,
 26        *,
 27        on_activate_call: Callable[[], Any] | None = None,
 28        transition_delay: float | None = None,
 29        color: tuple[float, float, float] | None = None,
 30        textcolor: tuple[float, float, float] | None = None,
 31        smooth_update_delay: float | None = None,
 32    ):
 33        if on_activate_call is None:
 34            on_activate_call = bui.WeakCall(self._default_on_activate_call)
 35        self._on_activate_call = on_activate_call
 36        if smooth_update_delay is None:
 37            smooth_update_delay = 1.0
 38        self._smooth_update_delay = smooth_update_delay
 39        self._size = size
 40        self._scale = scale
 41        if color is None:
 42            color = (0.5, 0.6, 0.5)
 43        if textcolor is None:
 44            textcolor = (1, 1, 1)
 45        self._color = color
 46        self._textcolor = textcolor
 47        self._header_color = (0.8, 0.8, 2.0)
 48        self._parent = parent
 49        self._position: tuple[float, float] = (0.0, 0.0)
 50
 51        self._button = bui.buttonwidget(
 52            parent=parent,
 53            size=size,
 54            label='',
 55            button_type='square',
 56            scale=scale,
 57            autoselect=True,
 58            on_activate_call=self._on_activate,
 59            transition_delay=transition_delay,
 60            color=color,
 61        )
 62
 63        self._title_text = bui.textwidget(
 64            parent=parent,
 65            size=(0, 0),
 66            draw_controller=self._button,
 67            h_align='center',
 68            v_align='center',
 69            maxwidth=size[0] * scale * 0.85,
 70            text=bui.Lstr(
 71                resource='league.leagueRankText',
 72                fallback_resource='coopSelectWindow.powerRankingText',
 73            ),
 74            color=self._header_color,
 75            flatness=1.0,
 76            shadow=1.0,
 77            scale=scale * 0.5,
 78            transition_delay=transition_delay,
 79        )
 80
 81        self._value_text = bui.textwidget(
 82            parent=parent,
 83            size=(0, 0),
 84            h_align='center',
 85            v_align='center',
 86            maxwidth=size[0] * scale * 0.85,
 87            text='-',
 88            draw_controller=self._button,
 89            big=True,
 90            scale=scale,
 91            transition_delay=transition_delay,
 92            color=textcolor,
 93        )
 94
 95        plus = bui.app.plus
 96        assert plus is not None
 97
 98        self._smooth_percent: float | None = None
 99        self._percent: int | None = None
100        self._smooth_rank: float | None = None
101        self._rank: int | None = None
102        self._ticking_sound: bui.Sound | None = None
103        self._smooth_increase_speed = 1.0
104        self._league: str | None = None
105        self._improvement_text: str | None = None
106
107        self._smooth_update_timer: bui.AppTimer | None = None
108
109        # Take note of our account state; we'll refresh later if this changes.
110        self._account_state_num = plus.get_v1_account_state_num()
111        self._last_power_ranking_query_time: float | None = None
112        self._doing_power_ranking_query = False
113        self.set_position(position)
114        self._bg_flash = False
115        self._update_timer = bui.AppTimer(
116            1.0, bui.WeakCall(self._update), repeat=True
117        )
118        self._update()
119
120        # If we've got cached power-ranking data already, apply it.
121        assert bui.app.classic is not None
122        data = bui.app.classic.accounts.get_cached_league_rank_data()
123        if data is not None:
124            self._update_for_league_rank_data(data)
125
126    def _on_activate(self) -> None:
127        bui.increment_analytics_count('League rank button press')
128        self._on_activate_call()
129
130    def __del__(self) -> None:
131        if self._ticking_sound is not None:
132            self._ticking_sound.stop()
133            self._ticking_sound = None
134
135    def _start_smooth_update(self) -> None:
136        self._smooth_update_timer = bui.AppTimer(
137            0.05, bui.WeakCall(self._smooth_update), repeat=True
138        )
139
140    def _smooth_update(self) -> None:
141        # pylint: disable=too-many-branches
142        # pylint: disable=too-many-statements
143        try:
144            if not self._button:
145                return
146            if self._ticking_sound is None:
147                self._ticking_sound = bui.getsound('scoreIncrease')
148                self._ticking_sound.play()
149            self._bg_flash = not self._bg_flash
150            color_used = (
151                (self._color[0] * 2, self._color[1] * 2, self._color[2] * 2)
152                if self._bg_flash
153                else self._color
154            )
155            textcolor_used = (1, 1, 1) if self._bg_flash else self._textcolor
156            header_color_used = (
157                (1, 1, 1) if self._bg_flash else self._header_color
158            )
159
160            if self._rank is not None:
161                assert self._smooth_rank is not None
162                self._smooth_rank -= 1.0 * self._smooth_increase_speed
163                finished = int(self._smooth_rank) <= self._rank
164            elif self._smooth_percent is not None:
165                self._smooth_percent += 1.0 * self._smooth_increase_speed
166                assert self._percent is not None
167                finished = int(self._smooth_percent) >= self._percent
168            else:
169                finished = True
170            if finished:
171                if self._rank is not None:
172                    self._smooth_rank = float(self._rank)
173                elif self._percent is not None:
174                    self._smooth_percent = float(self._percent)
175                color_used = self._color
176                textcolor_used = self._textcolor
177                self._smooth_update_timer = None
178                if self._ticking_sound is not None:
179                    self._ticking_sound.stop()
180                    self._ticking_sound = None
181                bui.getsound('cashRegister2').play()
182                assert self._improvement_text is not None
183                diff_text = bui.textwidget(
184                    parent=self._parent,
185                    size=(0, 0),
186                    h_align='center',
187                    v_align='center',
188                    text='+' + self._improvement_text + '!',
189                    position=(
190                        self._position[0] + self._size[0] * 0.5 * self._scale,
191                        self._position[1] + self._size[1] * -0.2 * self._scale,
192                    ),
193                    color=(0, 1, 0),
194                    flatness=1.0,
195                    shadow=0.0,
196                    scale=self._scale * 0.7,
197                )
198
199                def safe_delete(widget: bui.Widget) -> None:
200                    if widget:
201                        widget.delete()
202
203                bui.apptimer(2.0, bui.Call(safe_delete, diff_text))
204            status_text: str | bui.Lstr
205            if self._rank is not None:
206                assert self._smooth_rank is not None
207                status_text = bui.Lstr(
208                    resource='numberText',
209                    subs=[('${NUMBER}', str(int(self._smooth_rank)))],
210                )
211            elif self._smooth_percent is not None:
212                status_text = str(int(self._smooth_percent)) + '%'
213            else:
214                status_text = '-'
215            bui.textwidget(
216                edit=self._value_text, text=status_text, color=textcolor_used
217            )
218            bui.textwidget(edit=self._title_text, color=header_color_used)
219            bui.buttonwidget(edit=self._button, color=color_used)
220
221        except Exception:
222            logging.exception('Error doing smooth update.')
223            self._smooth_update_timer = None
224
225    def _update_for_league_rank_data(self, data: dict[str, Any] | None) -> None:
226        # pylint: disable=too-many-branches
227        # pylint: disable=too-many-statements
228
229        plus = bui.app.plus
230        assert plus is not None
231
232        # If our button has died, ignore.
233        if not self._button:
234            return
235
236        status_text: str | bui.Lstr
237
238        in_top = data is not None and data['rank'] is not None
239        do_percent = False
240        if data is None or plus.get_v1_account_state() != 'signed_in':
241            self._percent = self._rank = None
242            status_text = '-'
243        elif in_top:
244            self._percent = None
245            self._rank = data['rank']
246            prev_league = self._league
247            self._league = data['l']
248
249            # If this is the first set, league has changed, or rank has gotten
250            # worse, snap the smooth value immediately.
251            assert self._rank is not None
252            if (
253                self._smooth_rank is None
254                or prev_league != self._league
255                or self._rank > int(self._smooth_rank)
256            ):
257                self._smooth_rank = float(self._rank)
258            status_text = bui.Lstr(
259                resource='numberText',
260                subs=[('${NUMBER}', str(int(self._smooth_rank)))],
261            )
262        else:
263            try:
264                if not data['scores'] or data['scores'][-1][1] <= 0:
265                    self._percent = self._rank = None
266                    status_text = '-'
267                else:
268                    assert bui.app.classic is not None
269                    our_points = (
270                        bui.app.classic.accounts.get_league_rank_points(data)
271                    )
272                    progress = float(our_points) / data['scores'][-1][1]
273                    self._percent = int(progress * 100.0)
274                    self._rank = None
275                    do_percent = True
276                    prev_league = self._league
277                    self._league = data['l']
278
279                    # If this is the first set, league has changed, or percent
280                    # has decreased, snap the smooth value immediately.
281                    if (
282                        self._smooth_percent is None
283                        or prev_league != self._league
284                        or self._percent < int(self._smooth_percent)
285                    ):
286                        self._smooth_percent = float(self._percent)
287                    status_text = str(int(self._smooth_percent)) + '%'
288
289            except Exception:
290                logging.exception('Error updating power ranking.')
291                self._percent = self._rank = None
292                status_text = '-'
293
294        # If we're doing a smooth update, set a timer.
295        if (
296            self._rank is not None
297            and self._smooth_rank is not None
298            and int(self._smooth_rank) != self._rank
299        ):
300            self._improvement_text = str(
301                -(int(self._rank) - int(self._smooth_rank))
302            )
303            diff = abs(self._rank - self._smooth_rank)
304            if diff > 100:
305                self._smooth_increase_speed = diff / 80.0
306            elif diff > 50:
307                self._smooth_increase_speed = diff / 70.0
308            elif diff > 25:
309                self._smooth_increase_speed = diff / 55.0
310            else:
311                self._smooth_increase_speed = diff / 40.0
312            self._smooth_increase_speed = max(0.4, self._smooth_increase_speed)
313            bui.apptimer(
314                self._smooth_update_delay,
315                bui.WeakCall(self._start_smooth_update),
316            )
317
318        if (
319            self._percent is not None
320            and self._smooth_percent is not None
321            and int(self._smooth_percent) != self._percent
322        ):
323            self._improvement_text = str(
324                (int(self._percent) - int(self._smooth_percent))
325            )
326            self._smooth_increase_speed = 0.3
327            bui.apptimer(
328                self._smooth_update_delay,
329                bui.WeakCall(self._start_smooth_update),
330            )
331
332        if do_percent:
333            bui.textwidget(
334                edit=self._title_text,
335                text=bui.Lstr(resource='coopSelectWindow.toRankedText'),
336            )
337        else:
338            try:
339                assert data is not None
340                txt = bui.Lstr(
341                    resource='league.leagueFullText',
342                    subs=[
343                        (
344                            '${NAME}',
345                            bui.Lstr(translate=('leagueNames', data['l']['n'])),
346                        ),
347                    ],
348                )
349                t_color = data['l']['c']
350            except Exception:
351                txt = bui.Lstr(
352                    resource='league.leagueRankText',
353                    fallback_resource='coopSelectWindow.powerRankingText',
354                )
355                assert bui.app.classic is not None
356                t_color = bui.app.ui_v1.title_color
357            bui.textwidget(edit=self._title_text, text=txt, color=t_color)
358        bui.textwidget(edit=self._value_text, text=status_text)
359
360    def _on_power_ranking_query_response(
361        self, data: dict[str, Any] | None
362    ) -> None:
363        self._doing_power_ranking_query = False
364        assert bui.app.classic is not None
365        bui.app.classic.accounts.cache_league_rank_data(data)
366        self._update_for_league_rank_data(data)
367
368    def _update(self) -> None:
369        cur_time = bui.apptime()
370
371        plus = bui.app.plus
372        assert plus is not None
373
374        # If our account state has changed, refresh our UI.
375        account_state_num = plus.get_v1_account_state_num()
376        if account_state_num != self._account_state_num:
377            self._account_state_num = account_state_num
378
379            # And power ranking too...
380            if not self._doing_power_ranking_query:
381                self._last_power_ranking_query_time = None
382
383        # Send off a new power-ranking query if its been
384        # long enough or whatnot.
385        if not self._doing_power_ranking_query and (
386            self._last_power_ranking_query_time is None
387            or cur_time - self._last_power_ranking_query_time > 30.0
388        ):
389            self._last_power_ranking_query_time = cur_time
390            self._doing_power_ranking_query = True
391            plus.power_ranking_query(
392                callback=bui.WeakCall(self._on_power_ranking_query_response)
393            )
394
395    def _default_on_activate_call(self) -> None:
396        # pylint: disable=cyclic-import
397        # from bauiv1lib.league.rankwindow import LeagueRankWindow
398
399        raise RuntimeError()
400        # LeagueRankWindow(modal=True, origin_widget=self._button)
401
402    def set_position(self, position: tuple[float, float]) -> None:
403        """Set the button's position."""
404        self._position = position
405        if not self._button:
406            return
407        bui.buttonwidget(edit=self._button, position=self._position)
408        bui.textwidget(
409            edit=self._title_text,
410            position=(
411                self._position[0] + self._size[0] * 0.5 * self._scale,
412                self._position[1] + self._size[1] * 0.82 * self._scale,
413            ),
414        )
415        bui.textwidget(
416            edit=self._value_text,
417            position=(
418                self._position[0] + self._size[0] * 0.5 * self._scale,
419                self._position[1] + self._size[1] * 0.36 * self._scale,
420            ),
421        )
422
423    def get_button(self) -> bui.Widget:
424        """Return the underlying button bui.Widget>"""
425        return self._button

Button showing league rank.

LeagueRankButton( parent: _bauiv1.Widget, position: tuple[float, float], size: tuple[float, float], scale: float, *, on_activate_call: Optional[Callable[[], Any]] = None, transition_delay: float | None = None, color: tuple[float, float, float] | None = None, textcolor: tuple[float, float, float] | None = None, smooth_update_delay: float | None = None)
 20    def __init__(
 21        self,
 22        parent: bui.Widget,
 23        position: tuple[float, float],
 24        size: tuple[float, float],
 25        scale: float,
 26        *,
 27        on_activate_call: Callable[[], Any] | None = None,
 28        transition_delay: float | None = None,
 29        color: tuple[float, float, float] | None = None,
 30        textcolor: tuple[float, float, float] | None = None,
 31        smooth_update_delay: float | None = None,
 32    ):
 33        if on_activate_call is None:
 34            on_activate_call = bui.WeakCall(self._default_on_activate_call)
 35        self._on_activate_call = on_activate_call
 36        if smooth_update_delay is None:
 37            smooth_update_delay = 1.0
 38        self._smooth_update_delay = smooth_update_delay
 39        self._size = size
 40        self._scale = scale
 41        if color is None:
 42            color = (0.5, 0.6, 0.5)
 43        if textcolor is None:
 44            textcolor = (1, 1, 1)
 45        self._color = color
 46        self._textcolor = textcolor
 47        self._header_color = (0.8, 0.8, 2.0)
 48        self._parent = parent
 49        self._position: tuple[float, float] = (0.0, 0.0)
 50
 51        self._button = bui.buttonwidget(
 52            parent=parent,
 53            size=size,
 54            label='',
 55            button_type='square',
 56            scale=scale,
 57            autoselect=True,
 58            on_activate_call=self._on_activate,
 59            transition_delay=transition_delay,
 60            color=color,
 61        )
 62
 63        self._title_text = bui.textwidget(
 64            parent=parent,
 65            size=(0, 0),
 66            draw_controller=self._button,
 67            h_align='center',
 68            v_align='center',
 69            maxwidth=size[0] * scale * 0.85,
 70            text=bui.Lstr(
 71                resource='league.leagueRankText',
 72                fallback_resource='coopSelectWindow.powerRankingText',
 73            ),
 74            color=self._header_color,
 75            flatness=1.0,
 76            shadow=1.0,
 77            scale=scale * 0.5,
 78            transition_delay=transition_delay,
 79        )
 80
 81        self._value_text = bui.textwidget(
 82            parent=parent,
 83            size=(0, 0),
 84            h_align='center',
 85            v_align='center',
 86            maxwidth=size[0] * scale * 0.85,
 87            text='-',
 88            draw_controller=self._button,
 89            big=True,
 90            scale=scale,
 91            transition_delay=transition_delay,
 92            color=textcolor,
 93        )
 94
 95        plus = bui.app.plus
 96        assert plus is not None
 97
 98        self._smooth_percent: float | None = None
 99        self._percent: int | None = None
100        self._smooth_rank: float | None = None
101        self._rank: int | None = None
102        self._ticking_sound: bui.Sound | None = None
103        self._smooth_increase_speed = 1.0
104        self._league: str | None = None
105        self._improvement_text: str | None = None
106
107        self._smooth_update_timer: bui.AppTimer | None = None
108
109        # Take note of our account state; we'll refresh later if this changes.
110        self._account_state_num = plus.get_v1_account_state_num()
111        self._last_power_ranking_query_time: float | None = None
112        self._doing_power_ranking_query = False
113        self.set_position(position)
114        self._bg_flash = False
115        self._update_timer = bui.AppTimer(
116            1.0, bui.WeakCall(self._update), repeat=True
117        )
118        self._update()
119
120        # If we've got cached power-ranking data already, apply it.
121        assert bui.app.classic is not None
122        data = bui.app.classic.accounts.get_cached_league_rank_data()
123        if data is not None:
124            self._update_for_league_rank_data(data)
def set_position(self, position: tuple[float, float]) -> None:
402    def set_position(self, position: tuple[float, float]) -> None:
403        """Set the button's position."""
404        self._position = position
405        if not self._button:
406            return
407        bui.buttonwidget(edit=self._button, position=self._position)
408        bui.textwidget(
409            edit=self._title_text,
410            position=(
411                self._position[0] + self._size[0] * 0.5 * self._scale,
412                self._position[1] + self._size[1] * 0.82 * self._scale,
413            ),
414        )
415        bui.textwidget(
416            edit=self._value_text,
417            position=(
418                self._position[0] + self._size[0] * 0.5 * self._scale,
419                self._position[1] + self._size[1] * 0.36 * self._scale,
420            ),
421        )

Set the button's position.

def get_button(self) -> _bauiv1.Widget:
423    def get_button(self) -> bui.Widget:
424        """Return the underlying button bui.Widget>"""
425        return self._button

Return the underlying button bui.Widget>