-
-
Notifications
You must be signed in to change notification settings - Fork 196
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
Introduce preset messages into the app #825
base: main
Are you sure you want to change the base?
Conversation
Thanks for the initiative and for this very detailed PR description. I'll review asap. As for the SQL migration, I haven't checked the code but if it's a new table it should be pretty straightforward to test. You can build and use a version of the app prior to your PR and then build again with the version change of your code. Now I'm not sure to understand why sql is needed for this feature? If I understand correctly, once you selected a preset, it automatically adds it for each game, that's right? |
Apologies for the length of this message... There's no rush for you to respond 😅 :
Ah, thanks, that makes sense :)
it's not a configuration setting that automatically sends/adds preset messages per game. It's a bunch of buttons that appear in the chat at the start / end of games to automatically send 'good luck!' or 'good game', etc. The buttons change at the start / end of games. Here's a gif of what it looks like at the moment. The app is closed in the middle and reopened to show that it remembers what button you already clicked for the game (due to the database entry.) (The gif sits on my home screen for a while while the app is redeployed to the debugger) (Note: annoyingly, there's a bug here where it doesn't display the end messages for some reason after resignation that I'd have to look into 😅 .) This approach also has the side effect that when the chat widget is closed / reopened from the game screen it remembers what you'd clicked. Without the database it forgets the state each time the 'chat' route is closed because the 'chat preset' provider is no longer being listened to by anything and is removed and forgets its state: Each time the chat route is opened the 'chatcontroller' and the 'chat presets controller' are started from scratch. I do think the database is overkill just to remember those button states between app closes / game switches in correspondence when 99.999% of the time the user isn't going to return to chat when the game ends and the 'start' messages disappear after a few moves. There's a halfway solution where the state is remembered when you close the chat widget and open it again while still in the game - I'm just finding it challenging to work out the best way to achieve that with flutter / riverpod with the 'chat' route being independent from the 'game view' and its provider states being forgotten on close. I'm a bit of a UI noob in general... One approach I tried was using You have a lot more flutter/riverpod experience than me - have you ran into a scenario where a route is 'downstream' of another route and you want that route to remember some state each time its opened as long as the 'parent' is still open further up the stack? (I'm not sure if that makes any sense at all 😅 .) But maybe I'm overthinking this and that 2nd gif is actually good enough? The website currently forgets the state when you refresh the page afterall 😅 . |
So the SQL is definitely overkill yes. I'd rather have the buttons to always be displayed, no matter you clicked them already or not. If you want to remember the state across games I'd use a dedicated memory store that'd be reset when the app is restarted. But I don't think such feature is necessary, let's keep things simple for now. |
4e9a5a2
to
4390ef4
Compare
…s) to send preset messages such as 'good luck' and 'have fun' on game start and 'gg' on game end. This functionality mirrors that currently on the website. Limitations: * No internationalisation support (this is also the case on the website and would be a separate piece of work requiring updates to both the phone app and website to make the messages appear in both users' languages.) * Whether a preset has already been set can't be synced up with the website / other devices (I don't think this is a big deal :P.) * State forgotten when closing the app and returning to game Message Bubble Bug Fix Prior to this PR, the message bubble functionality didn't take into account that anonymous players can send these preset messages and the bubble 'else' case makes it look like it was the phone player who sent these even if it was the other player. I added a change to expose the "colour" field (`c`) in the websocket message. State Persistence The state is written to sqlite so it is retained when games are opened again after the app is closed (or the game is moved away from - I don't think this is possible at the moment but it perhaps could be in the future to navigate between multiple correspondence games if it isn't possible already.) If you think this is heavy handed let me know and I could explore just retaining it for the lifetime of the game widget. Being a flutter noob, I'd have to work out how to pipe that state together as the chat widget state is built from scratch each time the chat button is clicked and creates a 'router change event'. I thought putting it in SQLlite was probably fine because the chat widget does similar for new / read messages, etc. Scenarios Tested * Chat bubbles still work as expected after adding in the 'look at the anonymous player's colour if they're not logged in' change. * Clicking the preset buttons makes them disappear. * Pressing 2 buttons on either game start or end makes all the bubbles disappear. * The chat buttons move from the 'start' buttons to 'end' buttons when the game has ended in less than 4 moves * The 'start' chat buttons disappear after 4 moves have been played. * The 'end' buttons appear if the user clicks that chat after the game ends * The end buttons appear if the user is on the chat while the game ends * The start buttons disappear if the user clicks the chat after the 4th move * The start buttons disappear if the user is on the chat when the 4th move has been played
4390ef4
to
c54f395
Compare
@veloce Makes sense to me :). I've made those changes and pushed so the PR is ready for review now whenever you get the chance. This was my approach for keeping the state tied to a game as the chat is opened or closed: https://github.com/lichess-org/mobile/pull/825/files#diff-4921abb96f5f54e0628bbb3f807f679ebe816c62f7e06499fadbed2bbe9b6de6R428 (the provider won't be removed by flutter when the chat is closed because there's still a listener.) Let me know if you have any better ideas around that or want me to rethink it. |
I'm surprised that you have to do that to keep the state. Looks like a workaround, and in theory we should not need to do this (or it indicates that it can be done differently). mobile/lib/src/view/game/game_body.dart Lines 430 to 432 in c8219b5
so we can display the unread count chip in the bottom bar. So as I understand it the state is watched all the time the game is shown, which means it should stay available. But maybe I'm missing something? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok now I understand why the state is invalidated.
I think the easiest way to fix this is to remove the chatPresetController
and put its logic in the chatController
. This will simplify things hopefully as this logic belongs to the chat controller, and you won't have to worry about state invalidation anymore.
|
||
@override | ||
Future<ChatPresetsState> build(GameFullId id) async { | ||
_gameId = id; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure to understand why you need a private local var here.
|
||
final gameState = ref.read(gameControllerProvider(_gameId)).value; | ||
|
||
ref.listen(gameControllerProvider(_gameId), _handleGameStateChange); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here I don't think ref.listen
is the best way to handle this.
Since we want to act upon the game state, ref.watch(gameControllerProvider(id))
feels more like what we want.
We don't want to rebuild the chat state each time the game state changes, so you can also use selectAsync to filter rebuild by returning only PresetMessageGroup
when they change.
Hey @veloce . Yeah, the same thought actually occurred to me (moving the functionality to 'chat controller' which retains its state in order to display the 'count chip.') I've went ahead and moved it, got rid of the 'chat presets controller' and pushed :) I used I also wanted to note that I added the |
@Happy0 I think you've hit a tricky case but you couldn't know it before so it's not your fault ;) There is indeed an issue with the initialisation of the providers and the fact that the socket API is designed as such the The original mistake was made by me actually. Because of that websocket API, the To fix this situation I think the mobile/lib/src/model/common/socket.dart Line 52 in 2f1f9c8
Also the This is more or less how it's done on the website actually. So the chat controller must be refactored. It should have a new method to set all messages at once (that the game controller will call when receiving the The socket pool must be updated too, I'll take care of this and ping you when it's ready. |
Thanks a lot @veloce :). I'll make those changes soon |
@Happy0 actually you can already use send a message to whatever socket client is connected: ref.read(socketPoolProvider).currentClient.send('talk', 'hello'); No need to modify |
Hullo @veloce_ :D. Sorry about the delay - I got a bit ill / busy for a bit. I'm currently trying to implement your suggested changes here. The bit I'm having difficult with is giving the This isn't super surprising as both gameController and chatController have a lot of async operations going on so they're being interleaved with each other. I'm just not sure what to do about it and whether I'm missing some flutter / riverpod knowledge that might lead me in the right direction 😅 . I made this temporary branch here to show you the changes I've made: Happy0/lichess-mobile@preset_messages_v2...Happy0:lichess-mobile:preset_messages_v5 I was wondering if you had any advice?
I think this second option maybe makes sense to me... It also gets rid of the circular dependency between |
You're right, it's not a good idea to set the messages in the chat controller like I suggested. Because it violates a riverpod rule: https://riverpod.dev/docs/essentials/do_dont#dont-perform-side-effects-during-the-initialization-of-a-provider I have to think about it. Letting the game controller handle the chat messages would work of course, but I'd rather avoid it if possible. I wish the socket api was designed such as not having this |
The new app is looking great :D. Well done :).
Note: I won't be offended if you don't want this. For me this was mostly a learning exercise in flutter and dart and I've learned a lot in the process and could probably do something more useful for the app :P.
Preset messages allow players (including anonymous non-logged in users) to send preset messages such as 'good luck' and 'have fun' on game start and 'gg' on game end.
This functionality mirrors that currently on the website.
Limitations:
Message Bubble Bug Fix
Prior to this PR, the message bubble functionality didn't take into account that anonymous players can send these preset messages and the bubble 'else' case makes it look like it was the phone player who sent these even if it was the other player. I added a change to expose the "colour" field (
c
) in the websocket message.State Persistence
The state is written to sqlite so it is retained when games are opened again after the app is closed (or the game is moved away from - I don't think this is possible at the moment but it perhaps could be in the future to navigate between multiple correspondence games if it isn't possible already.)
If you think this is heavy handed let me know and I could explore just retaining it for the lifetime of the game widget. Being a flutter noob, I'd have to work out how to pipe that state together as the chat widget state is built from scratch each time the chat button is clicked and creates a 'router change event'.
I thought putting it in SQLlite was probably fine because the chat widget does similar for new / read messages, etc.
Screenshots
Scenarios Tested