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

Set the button's position.

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

Return the underlying button bui.Widget>