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

Opening explorer #836

Merged
merged 82 commits into from
Aug 28, 2024
Merged

Opening explorer #836

merged 82 commits into from
Aug 28, 2024

Conversation

Mauritz8
Copy link
Contributor

@Mauritz8 Mauritz8 commented Jul 6, 2024

Only supports the master database for now. Thought it'd be a good idea to create a pr before I go any further, in order to get your thoughts.
demo:

Screencast.from.2024-07-06.22.35.13.webm

close #456
close #872

@HaonRekcef
Copy link
Contributor

Hi Mauritz
Thanks, looks promising.
I was working on the opening explorer feature a few months back, but had to stop due to other personal obligations. Unfortunately, I don't expect this to change in the next few months :(. I have published my progress here, so maybe you can take some inspiration:
https://github.com/HaonRekcef/lichess-mobile/tree/opening-explorer
Here's a screen recording of how it looked:

opening-explorer.mp4

Note that the code and the design are not polished. If I remember correctly, the communication with the server is not done well, and there are some other things not implemented.

Some feedback and points to discuss:

  1. I am not sure if there is space for the opening explorer in the analysis board, even though I loved it there in the old app. If there is some notation and the engine is turned on, it won’t fit.
  2. I experimented with different types of Flutter tables a lot, and I think the data table widget takes up too much space vertically. I managed to get a working version with the Table widget that uses less space while still having the ink behavior of the data table widget (highlighting the whole row). See here: https://github.com/HaonRekcef/lichess-mobile/blob/e65893273b07b3bfb2512dc084a3ad75e060d44f/lib/src/view/explorer/opening_explorer.dart#L106C23-L224C23
  3. In my opinion, an opening explorer without a way to view games is incomplete.

@Mauritz8
Copy link
Contributor Author

Mauritz8 commented Jul 7, 2024

Hi! Thanks for taking the time to share your thoughts and give feedback, I appreciate it more than you know.

To address your points:

  1. I agree that it should be a separate screen, right now you have to scroll a lot and it's hard to get a good overview.
  2. I agree on this one as well, I think the less scrolling needed the better. I'll check out the way you used the table widget.
  3. Definitely, I will add it.

On a side note, I tried to get each color block in the percentage graph to have widths according to their percentage, but I had a lot of problems with the table changing size depending on the data and sometimes going of screen, and I couldn't really figure out why. Do you remember if you had any similar problems?

From what I can see in your video, the opening explorer is only available as a standalone tool, separate from the analysis board. I think that it's a must that it's a part of the analysis board, so you can use it when analyzing games.

I think designing the ui is the difficult part. The table itself takes up a lot of space, and you also need to be able to switch between the masters, lichess, and player db, and the different settings for each of them. All while still being available from within the analysis board.

One option that comes to mind is to be able to swipe between the move list and the opening explorer. It has the benefit of always being able to see the board, which I think would be a big plus, but it leaves less space for the explorer compared to having a whole screen dedicated to it. Any and all ideas are appreciated, since I feel like it can be quite tricky to get it right.

@veloce
Copy link
Contributor

veloce commented Jul 9, 2024

This one will wait in the queue for the review, until I've dealt with older PRs.

Just a couple of quick notes from what I've read here:

  • a separate dedicated screen is a must have indeed (I think accessed from the analysis screen with a bottom bar icon, and also separately from the tools tab)
  • but it doesn't prevent having a split view in the analysis screen as you did (with a settings disabled by default I'd say); can be useful for devices where vertical space is not an issue
  • for wins/draws/loss, width according to percentage is a must have
  • we should try to reduce the vertical padding of table rows but we shouldn't shrink them too much (as in the 2nd video), since these rows are also tappable targets.

@Mauritz8 Mauritz8 marked this pull request as draft July 12, 2024 10:35
@tom-anders tom-anders mentioned this pull request Jul 17, 2024
@Mauritz8
Copy link
Contributor Author

I've refactored the cache implementation, it's still exposing a stream though (see my previous comment). I also added a move number cap to try and fetch the wikibooks url, and now it selects the current user as default for the player db.

I added a few widget tests as well, that check that the data loads for each db type. I'm not sure what the preferred way to mock a provider is, when it needs different state between test cases. I did a bit of a hack to change the database type between tests, but there's probably a better way.

);

openingExplorerStreamFuture.then(
(openingExplorerStream) => openingExplorerStream.listen(
Copy link
Contributor

Choose a reason for hiding this comment

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

Here you want to save the StreamSubscription and cancel it on dispose. It is perhaps easier to do with an async/await.

import '../../test_app.dart';
import '../../test_utils.dart';

MockClient client(OpeningDatabase db) => MockClient((request) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of mocking a client per database, you can mock a client that handles every possible urls (masters, lichess, etc..) and override default value in shared preferences to set the default database selected.

This way we are really testing the logic of sending the right request according to settings.

To override preferences you can do sth like:

  SharedPreferences.setMockInitialValues({});

  final sharedPreferences = await SharedPreferences.getInstance();

...
 overrides: [
          sharedPreferencesProvider.overrideWithValue(sharedPreferences),
  ],
 ...

To simplify things I suppose another optional parameter Map<String, Object> defaultPreferences can be added to the buildTestApp function.

Copy link
Contributor

Choose a reason for hiding this comment

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

Once this is setup it will be easier to add more tests later, where we can test change of settings through the UI.

return response.stream
.map(utf8.decode)
.where((e) => e.isNotEmpty && e != '\n')
.map((e) => jsonDecode(e) as Map<String, dynamic>)
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of having 3 map I think we can combine them for more efficiency:

return response.stream
  .where((e) => e.isNotEmpty && e != '\n')
  .map((e) {
        final json = jsonUtf8Decoder.convert(e);
        return mapper(json);
});
``

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 think we have to convert the bytes to a string first in order to do the where, but the other two can be combined:

return response.stream
    .map(utf8.decode)
    .where((e) => e.isNotEmpty && e != '\n')
    .map((e) {
      final json = jsonDecode(e) as Map<String, dynamic>;
      return mapper(json);
    });

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah probably. I wonder if the e != '\n' is really necessary btw. I don't remember why I put that in the first place.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes it's needed, as empty lines may be sent to avoid timeouts.

final request = Request('GET', url);
if (headers != null) request.headers.addAll(headers);
final response = await send(request);
if (response.statusCode > 400) {
Copy link
Contributor

Choose a reason for hiding this comment

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

There is already a _checkResponseSuccess helper that I think we can reuse here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That function needs a Response but we have a StreamedResponse, which is not a subtype. It checks the body of the response, which is not available in a StreamedResponse.


@override
Widget build(BuildContext context) {
final ctrlProvider =
Copy link
Contributor

Choose a reason for hiding this comment

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

Since this is assigned with the return of ref.watch the name is not good here. What we have is the state of analysisController. So analysisState would be the proper name.

@Mauritz8
Copy link
Contributor Author

I've updated everything now.

@veloce veloce merged commit b1c7270 into lichess-org:main Aug 28, 2024
1 check passed
@veloce
Copy link
Contributor

veloce commented Aug 28, 2024

I must thank you again for your work @Mauritz8 . It is really awesome to see the explorer in the app finally 🎉

I've added only cosmetic changes to your PR, and improved the loading effect (it doesn't blink anymore).

@Mauritz8 Mauritz8 deleted the opening-explorer branch August 28, 2024 10:52
@ijm8710
Copy link

ijm8710 commented Sep 5, 2024

Hey @Mauritz8 had two questions?

  1. when clicking a popular opening in mobile web, I see some openings open a page like this (so not directly wikibooks but a more comprehensive native page; in fact this page then links to wikibooks). Should the app do similarly? image
  2. I've noticed that if I use opening explorer to analyze an opening, then open up like a masters game, that subsequent masters game if I go to game review and then click the opening explorer from there, the title of the opening does not open wikibooks same way it would if I came directly from the opening explorer itself. It's kinda like opening an opening explorer from
    An opening explorer. Should it? The opening explorer screens look the same so would expect them to operate the same regardless if you're in one inside another.

@Mauritz8
Copy link
Contributor Author

Mauritz8 commented Sep 5, 2024

  1. Having a native wikibooks page would definitely provide better and more seamless experience. I might not have time to work on it anytime soon though, but feel free to open an issue and I might get around to working on it.
  2. Unfortunately (or fortunately?) I'm unable to reproduce this, for me the link opens just fine either way.

@ijm8710
Copy link

ijm8710 commented Sep 5, 2024

  1. Having a native wikibooks page would definitely provide better and more seamless experience. I might not have time to work on it anytime soon though, but feel free to open an issue and I might get around to working on it.

Sorry not necessarily more native. But what I mean is the page that opens first in mobile web is not the wikibooks page. There's a more dedicated page that opens first that has a link to wikibooks page. Basically wondering if that's the page we should first have access to. If you try on mobile web perhaps you'll see what page I mean . It's just a different link I was curious about.

  1. Unfortunately (or fortunately?) I'm unable to reproduce this, for me the link opens just fine either way.

I think the bug is if you go far enough I , like 8 moves sometimes, clicking the opening doesn't do anything in app. But putting the exact same opening sequence in mobile web, the link is clickable. If you need a recording lmk

@EmmetSchuler
Copy link

@ijm8710 I think this will eventually be its own tool, instead of only linking to the opening explorer. Currently in Beta, it's Lichess's way of offering their own crowdsourced explanations to openings and their variations without relying on the (in my opinion) often vague wiki books explanations.
Because this feature is relatively new even for the website, unless someone really wants to make a PR for it I don't think it's too high on priority.

@EmmetSchuler
Copy link

Right now I believe it uses wikibooks as a baseline and are slowly filling it in with original content

@ijm8710
Copy link

ijm8710 commented Sep 5, 2024

I'm not asking for it to be more native. I'm saying currently it's just a web redirect but the page provided is different from mobile web. Shouldn't we use the same one?

@Mauritz8
Copy link
Contributor Author

Mauritz8 commented Sep 5, 2024

I see, it should just link to the lichess.org page instead. I like that, and it seems like an easy thing to change.

A recording of the bug would be appreciated.

@EmmetSchuler
Copy link

I'm not asking for it to be more native. I'm saying currently it's just a web redirect but the page provided is different from mobile web. Shouldn't we use the same one?

I see, sorry for the misunderstanding

@ijm8710
Copy link

ijm8710 commented Sep 5, 2024

I see, it should just link to the lichess.org page instead. I like that, and it seems like an easy thing to change.

A recording of the bug would be appreciated.

Awesome glad you agree and here's video of other. When there's a pause it doesn't open link

trim.FA61F938-A557-4850-865F-55F87986D0D9.MOV

@Mauritz8
Copy link
Contributor Author

Mauritz8 commented Sep 5, 2024

This recording doesn't show what you described with opening master games. Do you have an example where it works for a certain position one time, but not after opening the explorer from a master game? If not, it seems like it's an issue with certain openings at all times, such as the moscow variation you showed.

@ijm8710
Copy link

ijm8710 commented Sep 6, 2024

Perhaps that's a better way of describing the issue. I probably interpreted it wrong. Either way Moscow does work in mobile and has a wiki book so would assume it should work.

@ijm8710
Copy link

ijm8710 commented Sep 6, 2024

Actually yes I have an example. If you go to the 8th master game from top (the ones that show up without making a first move) and from analysis you jump right to c5?! It will not work. But if you move one move back it will work. But both have the exact same name I believe

@Mauritz8
Copy link
Contributor Author

Mauritz8 commented Sep 6, 2024

Wikibooks has a different page for each sequence of moves, so even if two positions have the same opening name in lichess they will have different wikibook pages. In this case, after c5 there is no wikibook page.

@ijm8710
Copy link

ijm8710 commented Sep 6, 2024

Ah okay that makes sense! Apologies for the long road to show you that.

On mobile web, since it opens that OTHER beta page I referenced rather than wikibooks directly, it opens up "Indian Defence with e6, Nf3"

If you were to use this OTHER beta page, would it be able to do it even in the app too off of c5?! As well or is there some extra magic they do to basically go off move name rather than the entire sequence if there's an innacurzcy to the sequence line opening?

@Mauritz8
Copy link
Contributor Author

Mauritz8 commented Sep 6, 2024

Linking to the lichess.org page, like the website does, should be quite easy. Then there will be a link even after the move c5.

@Mauritz8
Copy link
Contributor Author

Mauritz8 commented Sep 6, 2024

I created a pr now #989

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.

Opening explorer Opening explorer
5 participants