mobile icon indicating copy to clipboard operation
mobile copied to clipboard

feat: add study list screen

Open tom-anders opened this issue 1 year ago • 16 comments

@veloce Since studies are such a huge feature, I'd suggest we split it up and start with this PR that only will add the study list screen. This also makes it easier for others to take over development from me if necessary. After review, we can hide the button until the study feature is fully implemented.

tom-anders avatar Sep 06 '24 21:09 tom-anders

I like the big icons they show on web. Makes it easier to quickly differentiate between studies

ijm8710 avatar Sep 07 '24 00:09 ijm8710

study_list.webm

tom-anders avatar Sep 08 '24 22:09 tom-anders

@veloce Since studies are such a huge feature, I'd suggest we split it up and start with this PR that only will add the study list screen. This also makes it easier for others to take over development from me if necessary. After review, we can hide the button until the study feature is fully implemented.

@tom-anders yeah great initiative! we should split this one as much as possible; I prefer to review small PRs :)

veloce avatar Sep 09 '24 07:09 veloce

@veloce Since studies are such a huge feature, I'd suggest we split it up and start with this PR that only will add the study list screen. This also makes it easier for others to take over development from me if necessary. After review, we can hide the button until the study feature is fully implemented.

@tom-anders yeah great initiative! we should split this one as much as possible; I prefer to review small PRs :)

Perfect 👍 I'll further split up this PR as well.

tom-anders avatar Sep 09 '24 08:09 tom-anders

Thanks for adding the icons :)

2 more

A few times in video the names become ... prob because too long. But on mobile web I don't see it. So I'm assuming (because names are prob capped anyway) should be able to fit them always without truncation

I do slightly prefer how mobile web the chosen filter sort is actively shown (ie "hot" studies) rather than having to open the filter to see the specified choice

ijm8710 avatar Sep 09 '24 10:09 ijm8710

Thanks for adding the icons :)

2 more

A few times in video the names become ... prob because too long. But on mobile web I don't see it. So I'm assuming (because names are prob capped anyway) should be able to fit them always without truncation

I guess that depends on the on the screen size, you probably always have cases where names are to long. But we can tweak the layout and font size too make it a bit less likely.

I do slightly prefer how mobile web the chosen filter sort is actively shown (ie "hot" studies) rather than having to open the filter to see the specified choice

Good point - I don't want the buttons to be visible always, but adjusting the title of the top bar would probably be the best solution. Something like "Study - All - Popular"

tom-anders avatar Sep 09 '24 10:09 tom-anders

(converted back to a draft, as I'll split some code into smaller independent PRs

tom-anders avatar Sep 09 '24 19:09 tom-anders

@veloce I'm currently thinking about how we should implement the analysis board for studies. We probably want to reuse as much of the existing AnalysisController, but it currently expects a PGN string being passed in its build method. I guess we can either...

  1. Convert the study analysis object returned by the API into a PGN and then use that to call analysisControllerProvider(pgn, options), but it feels weird, because the controller will then parse the PGN again and turn it into its own Root object representation
  2. Refactor analysisControllerProvider, so that you can either pass a PGN, or an existing Root object (that we convert the study json into). I'm not really sure what's the most idiomatic way to do this though, do we simply use two nullable parameters and require that one of them has to be non-null?

Or maybe there's another approach I'm missing? Let me know what you think when you find the time :)

tom-anders avatar Sep 11 '24 20:09 tom-anders

I think the StudyController should be completely separate from the analysis controller and should have its own logic.

Over reusing a controller is not a good idea. I plan to write a dedicated controller for the opening explorer for instance, because almost all the logic of the analysis controller is not needed in the explorer.

Once we have several controller that share some logic, we can think about refactoring, using mixins probably. This kind of refactoring is not that easy to do, so we'd better way for things to stabilise.

veloce avatar Sep 11 '24 20:09 veloce

That being said, if you fancy that kind of refactoring and want to create a Notififier mixin to handle basic operations like navigating in the tree, fell free to try. But I'm not sure it is easy, because each screen has different needs.

Refactor analysisControllerProvider, so that you can either pass a PGN, or an existing Root object (that we convert the study json into). I'm not really sure what's the most idiomatic way to do this though, do we simply use two nullable parameters and require that one of them has to be non-null?

Is there a direct way to convert the study JSON to a Node? We need a tree structure in study for sure, but study doesn't have the same need as analysis controller. A couple of notes:

  • analysis controller takes a PGN because it aims to support lichess analysis and standalone analysis (PGN input)
  • performance wise, you don't want to supply large objects to a riverpod Notifier family instance (such a an IList, or a large object), because provider will compute the hash each time the widget is built, and the hash of a large object is expensive to compute. Riverpod's doc warns agains this also (should only provide primitives to a provider family)

For this reason, the study notifier should take only the study ID as parameter, and be asynchronous.

veloce avatar Sep 11 '24 20:09 veloce

Thanks for the quick and helpful reply!

I think the StudyController should be completely separate from the analysis controller and should have its own logic.

Over reusing a controller is not a good idea. I plan to write a dedicated controller for the opening explorer for instance, because almost all the logic of the analysis controller is not needed in the explorer.

Once we have several controller that share some logic, we can think about refactoring, using mixins probably. This kind of refactoring is not that easy to do, so we'd better way for things to stabilise.

Ah, the opening explorer was actually the code that gave me this idea of reusing the controller in the first place. Ok, then I agree that we should write a separate study controller, and (maybe) do the refactoring in the future.

Is there a direct way to convert the study JSON to a Node?

Haven't tried yet, but the layout looked similar enough. But maybe it's better to use a dedicated StudyNode class instead, we'll see.

  • performance wise, you don't want to supply large objects to a riverpod Notifier family instance (such a an IList, or a large object), because provider will compute the hash each time the widget is built, and the hash of a large object is expensive to compute. Riverpod's doc warns agains this also (should only provide primitives to a provider family)

For this reason, the study notifier should take only the study ID as parameter, and be asynchronous.

Good hint, will keep this in mind 👍

tom-anders avatar Sep 11 '24 22:09 tom-anders

For the broadcast feature, I made a different screen for the analysis board but I reused the analysis controller because I thought the logic was almost the same. I also went for this because the api returns a pgn https://lichess.org/api#tag/Studies/operation/studyChapterPgn so I don't understand why you said tom-anders that you need to pass a Root object to the analysis controller. By the way I think the study and broadcast feature might have some code in common because the broadcast is implemented as a study on the backend side.

julien4215 avatar Sep 15 '24 12:09 julien4215

For the broadcast feature, I made a different screen for the analysis board but I reused the analysis controller because I thought the logic was almost the same. I also went for this because the api returns a pgn https://lichess.org/api#tag/Studies/operation/studyChapterPgn so I don't understand why you said tom-anders that you need to pass a Root object to the analysis controller.

Oh wow, I must have completely missed that API endpoint when looking through the docs. Currently I'm using lichess.org/study/<id>/<chapter> (run curl -X GET 'https://lichess.org/study/U3guoz56/byuyr1dH' -H "Accept: application/json" | jq --color-output | less for an example), which returns a tree-like structure instead of a PGN. That's why I was talking about nodes etc.

tom-anders avatar Sep 15 '24 15:09 tom-anders

Marking this as "Ready to Review" again, as I don't think I can split this up further

tom-anders avatar Sep 17 '24 20:09 tom-anders

I rebased against main to fix conflicts with the build_runner PR, also adjusted the formatting of study chapters/members a bit, to avoid the names getting cut off.

Here's an updated video:

study_list.webm

tom-anders avatar Oct 18 '24 09:10 tom-anders

Excited for this Tom. The one thing I find that's goofy is the open circle bullets for each chapter. I know that's how it is on mobile web but as Veloce says they don't always have to mirror.

The one thing I'd ask is do they serve any point. If those circles get filled in or checked off when a study is completed then they do make some sense. If they don't currently, is that even possible to do even if web doesn't since it adds decent utility? If not, do you think there's a better formatting marker to use instead?

I know that's two decently long paragraphs for such a minor formatting marker and no clue why they look so goofy to me lol

ijm8710 avatar Oct 18 '24 12:10 ijm8710

Also, you mentioned splitting this pr and only starting with study list screen itself. I assume the favorite studies and other options of the like are part of a later phase, is that correct? Totally cool and more than happy to have a slightly limited alpha version at first, just curious if that's part of what you were implying earlier?

ijm8710 avatar Oct 18 '24 12:10 ijm8710

The one thing I find that's goofy is the open circle bullets for each chapter. I know that's how it is on mobile web but as Veloce says they don't always have to mirror.

Sure, no strong opinions about this, I guess a simple - would also do.

The one thing I'd ask is do they serve any point. If those circles get filled in or checked off when a study is completed then they do make some sense.

Doesn't look like it

Also, you mentioned splitting this pr and only starting with study list screen itself. I assume the favorite studies and other options of the like are part of a later phase, is that correct? Totally cool and more than happy to have a slightly limited alpha version at first, just curious if that's part of what you were implying earlier?

Ah, showing favorite studies (and also other categories like "My studies") is already part of this PR, but it's not visible in the screen recording since I wasn't logged in.

tom-anders avatar Oct 18 '24 12:10 tom-anders

Thanks Tom,

Any chance to see both the - and the • as a comparison 😀

Is having circles get filled as you complete a chapter even possible? I think it'd be really cool!! If not no worries

Awesome about the favorite studies comment. So then what's a small preview of what's left for studies. You hinted it's a huge pr and this was just the first piece of it, or did you actually do most of it already since you're awesome

ijm8710 avatar Oct 18 '24 13:10 ijm8710

Thanks Tom,

Any chance to see both the - and the • as a comparison 😀

I'll wait for @veloce's input here first

Is having circles get filled as you complete a chapter even possible? I think it'd be really cool!! If not no worries

Does not look like the API supports it

Awesome about the favorite studies comment. So then what's a small preview of what's left for studies. You hinted it's a huge pr and this was just the first piece of it, or did you actually do most of it already since you're awesome

I have a branch that implements the study screen, but it's not ready for review yet. Next after that would be a follow-up PR adding support for interactive studies.

tom-anders avatar Oct 22 '24 21:10 tom-anders

I've noticed a strange UI freeze when pushing to study screen: Enregistrement.de.l.ecran.2024-10-29.a.09.34.22.mov

I don't know what is causing this. It is also on android.

Also if you want to use the real study icon from lichess, I've pushed it, you can rebase to main to get it.

Oh, that's not actually a freeze, sorry for not mentioning that, it's just a dummy study screen I added here: https://github.com/lichess-org/mobile/pull/990/files#diff-d6c82c9cf2716bd768ab5fc1abfc30ce85567b52d36230ebdf68f2c616388d56

The intention was to make https://github.com/lichess-org/mobile/pull/1111 (which adds the "real" study screen) independent from the study list screen PR.

tom-anders avatar Oct 29 '24 09:10 tom-anders

Oh, that's not actually a freeze, sorry for not mentioning that, it's just a dummy study screen I added here: https://github.com/lichess-org/mobile/pull/990/files#diff-d6c82c9cf2716bd768ab5fc1abfc30ce85567b52d36230ebdf68f2c616388d56

The intention was to make #1111 (which adds the "real" study screen) independent from the study list screen PR.

I know it's an empty study screen. What I meant by freeze is that the animation starts then stops abruptly at about 25% after it started, it stays blocked during a short time then resume. That's not normal, it should be smooth and continuous all the time.

veloce avatar Oct 29 '24 09:10 veloce

Oh, that's not actually a freeze, sorry for not mentioning that, it's just a dummy study screen I added here: https://github.com/lichess-org/mobile/pull/990/files#diff-d6c82c9cf2716bd768ab5fc1abfc30ce85567b52d36230ebdf68f2c616388d56 The intention was to make #1111 (which adds the "real" study screen) independent from the study list screen PR.

I know it's an empty study screen. What I meant by freeze is that the animation starts then stops abruptly at about 25% after it started, it stays blocked during a short time then resume. That's not normal, it should be smooth and continuous all the time.

Ah, got it, I can reproduce as well. But I still think it's related to the empty screen - If I take #1111 and rebase it onto this branch (Pass -Xtheirs to git rebase), then the freeze is gone

tom-anders avatar Oct 29 '24 10:10 tom-anders

The search bar is sticky so it should be part of the page header, it will look much better. On Android it is very easy, on iOS we have to workaround a little. You can see how it's done in the opening explorer screen.

I must add that another simpler solution is to make the search bar non sticky. This is perhaps even better.

veloce avatar Oct 30 '24 19:10 veloce

The search bar is sticky so it should be part of the page header, it will look much better. On Android it is very easy, on iOS we have to workaround a little. You can see how it's done in the opening explorer screen.

I must add that another simpler solution is to make the search bar non sticky. This is perhaps even better.

Done, I wrapped the column with a SingleChildScrollView such that the search bar is scrolled as well. This broke the ScrollListener in the ListView though, so I had to move it up to _Body

tom-anders avatar Oct 30 '24 22:10 tom-anders

I tested it on a low end device to check if embedding a ListView inside a SingleChildScrollView would not cause performance issues.

Turn out that the answer is yes... I suppose the ListView has to be the primary scrollable to be efficient.

A simple way to deal with it I think:

itemBuilder: (context, index) {
  if (index == 0) {
    return SearchBar();
  } else {
      final study = studies.studies[index - 1];
      ....
  }

veloce avatar Oct 31 '24 16:10 veloce

I tested it on a low end device to check if embedding a ListView inside a SingleChildScrollView would not cause performance issues.

Turn out that the answer is yes... I suppose the ListView has to be the primary scrollable to be efficient.

A simple way to deal with it I think:

itemBuilder: (context, index) {
  if (index == 0) {
    return SearchBar();
  } else {
      final study = studies.studies[index - 1];
      ....
  }

Ah yes, that seems more elegant anyway. Done.

tom-anders avatar Oct 31 '24 22:10 tom-anders