Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Broadcast player results screen #1253

Merged
merged 21 commits into from
Dec 18, 2024

Conversation

julien4215
Copy link
Contributor

@julien4215 julien4215 commented Dec 11, 2024

broadcast_results.webm

@julien4215 julien4215 force-pushed the broadcast-player-screen branch 4 times, most recently from 03d785c to e948d04 Compare December 11, 2024 15:02
@ijm8710
Copy link

ijm8710 commented Dec 11, 2024

Hey Julian, 2 requests.

  1. mobile web green/reds wins and losses (the 0 and 1s) so that material results stand out. I like this and we should probably do same.
  2. on mobile web, above the results list, they have the player bio (ranks across variants, player age, fide id that links to their fide player page,etc). I'd like to also have this too shown outright either above or below the results list you're adding.

This is awesome tho!

@julien4215 julien4215 force-pushed the broadcast-player-screen branch from e948d04 to de1b7ba Compare December 11, 2024 23:40
@julien4215 julien4215 force-pushed the broadcast-player-screen branch from de1b7ba to 1e8253b Compare December 12, 2024 00:31
@julien4215 julien4215 marked this pull request as ready for review December 12, 2024 11:09
child: CircularProgressIndicator.adaptive(),
),
),
_ => const BroadcastPreview.loading()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed this on purpose. It was displaying a flash of shimmer boards in FIDE WC where only one board is displayed.

So it's better to not have it.

Copy link
Contributor Author

@julien4215 julien4215 Dec 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the board shimmer looks better than the circular indicator.

In the issue #1255 you can see that the flash is a black screen. This is because the circular indicator is not in the Scaffold widget but at the top.

Also I believe this loading is never reached because we are already listen higher in the tree to the round state (broadcast_round_screen).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there is a way to know in advance the number of boards, then we can use the shimmer. Otherwise I think it is ugly to see a flash of 10 shimmer boards where in fact only one is show eventually.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having only one board in a round is pretty rare. In the majority of cases I think the board shimmer looks nicer than the circular indicator.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately the world championship is the most watch broadcast... even if it is not the majority it will be seen much more times than other tournaments with more boards.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I definitely agree with Julien here. The shimmer looks and feels much better. Also, the wch match is over, and the next one will take place in about two years.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does unless there is only one or two board and you see a flash of shimmer if the request completes very quickly.

@@ -79,11 +81,15 @@ class _BroadcastGameScreenState extends ConsumerState<BroadcastGameScreen>
Widget build(BuildContext context) {
final broadcastGameState = ref
.watch(broadcastGameControllerProvider(widget.roundId, widget.gameId));
final broadcastRoundState =
ref.watch(broadcastRoundControllerProvider(widget.roundId));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we don't want to rebuild the whole screen if any of the other game of the round is updated, so you need to use .selectAsync.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But see this other comment, we should have all the state in a single controller.

Copy link
Contributor Author

@julien4215 julien4215 Dec 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used select instead because selectAsync returns a Future which makes it unpractical to use inside a widget.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In order to use selectAsync you need to create a dedicated provider to retrieve the title. This is the way to do it with riverpod.

Copy link
Contributor Author

@julien4215 julien4215 Dec 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But what is the advantage of creating a new provider instead of using select like this ?

final title = ref.watch(
      broadcastRoundControllerProvider(widget.roundId)
          .select((round) => round.value?.round.name),
    );

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's mostly a problem of typing. Here you're mixing the async value which represent an asynchronous value which may be not here yet, with a nullable value that you derives from another asynchronous value.

By creating another provider that returns an AsyncValue for the title you're making it clear of what you expect. It is ok to declare a new provider for that. It is like a cached computed value, but async. Doing that is recommended in the riverpod doc (but I don't remember where).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note also that using .value? directly you're not handling the error, it will be rethrown in the widget build method making it crash.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok thanks for the detailed explanation. I'll make a title provider.

I believe I have already done this in previous PR but I'll make sure to create a provider in the future

onTap: () {
pushPlatformRoute(
context,
builder: (context) => BroadcastGameScreen(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we can now open a screen from another context, this should be refactored:

// TODO
// we'll probably want to remove this and get the game state from a single controller
// this won't work with deep links for instance
final game = ref.watch(
broadcastRoundControllerProvider(roundId)
.select((round) => round.requireValue.games[gameId]!),
);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why this would not work with deep link. The two controllers are independent, they just listen to the same route because there is only one for broadcast.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you can load a game by itself you don't want to load the whole round, right? In a tournament where you have 100 board you'd load 99 boards (and listen to their updates) for nothing.

Copy link
Contributor Author

@julien4215 julien4215 Dec 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with that but I have done it this way because in the API there are no endpoints to get the player information for a specific board.

Maybe this refactoring can be done in an other branch once there is an API endpoint for that ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes let's do it in another PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code is also problematic because you assume you assume the round controller is loaded: select((round) => round.requireValue.games[gameId]!)

I'm not sure it is a good practice to mix select and requireValue in riverpod. So far we know it is loaded because the only way to access the game screen was through the round screen.

Now that you can access the game screen from the player result screen directly, can you be sure the round screen will be loaded? If you can access a game from another round it won't be the case. This is the main reason why it must be refactored.

Copy link
Contributor Author

@julien4215 julien4215 Dec 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed the requireValue. Do you still want to do the refactoring in another branch ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After talking with Thibault, it's decided that it is ok to load the full round to display a single game. So no refactoring after all.

But we need to ensure the round controller is loaded before the game controller in the game screen. (So we can do a requireValue)

@@ -118,7 +121,7 @@ class _PlayersListState extends ConsumerState<PlayersList> {
@override
Widget build(BuildContext context) {
final double eloWidth = max(MediaQuery.sizeOf(context).width * 0.2, 100);
final double scoreWidth = max(MediaQuery.sizeOf(context).width * 0.15, 70);
final double scoreWidth = max(MediaQuery.sizeOf(context).width * 0.15, 90);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this change? Have you noticed a case where it was too small?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is because I changed the score from 'x/y' to 'x / y'.

color: Theme.of(context).platform == TargetPlatform.iOS
? index.isEven
? (index - 1).isEven
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it was fine like that, you should leave it as is. I want the color appear in this order on iOS.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was to have the same color order as in the opening explorer

@julien4215
Copy link
Contributor Author

I think I have addressed all of your comments

final title = widget.title ??
(switch (ref.watch(broadcastGameScreenTitleProvider(widget.roundId))) {
AsyncData(value: final title) => title,
_ => 'Broadcast Game',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather have a SizedBox.shrink() here than a default title.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@julien4215 julien4215 force-pushed the broadcast-player-screen branch from 3edcebe to c5d8fdc Compare December 16, 2024 09:40
@veloce veloce merged commit 5ad9246 into lichess-org:main Dec 18, 2024
1 check passed
@julien4215 julien4215 deleted the broadcast-player-screen branch December 19, 2024 14:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants