-
-
Notifications
You must be signed in to change notification settings - Fork 366
Introduce preset messages into the app #825
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
base: main
Are you sure you want to change the base?
Changes from 1 commit
c54f395
211ca61
281a607
04a192d
8a3146f
c38eff9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,107 @@ | ||
| import 'package:freezed_annotation/freezed_annotation.dart'; | ||
| import 'package:lichess_mobile/src/model/common/id.dart'; | ||
| import 'package:lichess_mobile/src/model/game/chat_controller.dart'; | ||
| import 'package:lichess_mobile/src/model/game/game_controller.dart'; | ||
| import 'package:lichess_mobile/src/model/game/message_presets.dart'; | ||
| import 'package:riverpod_annotation/riverpod_annotation.dart'; | ||
|
|
||
| part 'chat_presets_controller.freezed.dart'; | ||
| part 'chat_presets_controller.g.dart'; | ||
|
|
||
| @riverpod | ||
| class ChatPresetsController extends _$ChatPresetsController { | ||
| late GameFullId _gameId; | ||
|
|
||
| static const Map<PresetMessageGroup, List<PresetMessage>> _presetMessages = { | ||
| PresetMessageGroup.start: [ | ||
| (label: 'HI', value: 'Hello'), | ||
| (label: 'GL', value: 'Good luck'), | ||
| (label: 'HF', value: 'Have fun!'), | ||
| (label: 'U2', value: 'You too!'), | ||
| ], | ||
| PresetMessageGroup.end: [ | ||
| (label: 'GG', value: 'Good game'), | ||
| (label: 'WP', value: 'Well played'), | ||
| (label: 'TY', value: 'Thank you'), | ||
| (label: 'GTG', value: "I've got to go"), | ||
| (label: 'BYE', value: 'Bye!'), | ||
| ], | ||
| }; | ||
|
|
||
| @override | ||
| Future<ChatPresetsState> build(GameFullId id) async { | ||
| _gameId = id; | ||
|
||
|
|
||
| final gameState = ref.read(gameControllerProvider(_gameId)).value; | ||
|
|
||
| ref.listen(gameControllerProvider(_gameId), _handleGameStateChange); | ||
|
||
|
|
||
| if (gameState != null) { | ||
| final presetMessageGroup = PresetMessageGroup.fromGame(gameState.game); | ||
|
|
||
| const List<PresetMessage> alreadySaid = []; | ||
|
|
||
| final initialState = ChatPresetsState( | ||
| presets: _presetMessages, | ||
| gameId: _gameId, | ||
| alreadySaid: alreadySaid, | ||
| currentPresetMessageGroup: presetMessageGroup, | ||
| ); | ||
|
|
||
| return initialState; | ||
| } else { | ||
| return ChatPresetsState( | ||
| presets: _presetMessages, | ||
| gameId: _gameId, | ||
| alreadySaid: [], | ||
| currentPresetMessageGroup: null, | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| void _handleGameStateChange( | ||
| AsyncValue<GameState>? previousGame, | ||
| AsyncValue<GameState> currentGame, | ||
| ) { | ||
| final newGameState = currentGame.value; | ||
|
|
||
| if (newGameState != null) { | ||
| final newMessageGroup = PresetMessageGroup.fromGame(newGameState.game); | ||
|
|
||
| final currentMessageGroup = state.value?.currentPresetMessageGroup; | ||
|
|
||
| if (newMessageGroup != currentMessageGroup) { | ||
| state = state.whenData((s) { | ||
| final newState = s.copyWith( | ||
| currentPresetMessageGroup: newMessageGroup, | ||
| alreadySaid: [], | ||
| ); | ||
|
|
||
| return newState; | ||
| }); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| void sendPreset(PresetMessage message) { | ||
| final chatController = ref.read(chatControllerProvider(_gameId).notifier); | ||
| chatController.sendMessage(message.value); | ||
|
|
||
| state = state.whenData((s) { | ||
| final state = s.copyWith(alreadySaid: [...s.alreadySaid, message]); | ||
| return state; | ||
| }); | ||
| } | ||
| } | ||
|
|
||
| @freezed | ||
| class ChatPresetsState with _$ChatPresetsState { | ||
| const ChatPresetsState._(); | ||
|
|
||
| const factory ChatPresetsState({ | ||
| required Map<PresetMessageGroup, List<PresetMessage>> presets, | ||
| required GameFullId gameId, | ||
| required List<PresetMessage> alreadySaid, | ||
| required PresetMessageGroup? currentPresetMessageGroup, | ||
| }) = _ChatPresetsState; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| import 'package:lichess_mobile/src/model/game/game_status.dart'; | ||
| import 'package:lichess_mobile/src/model/game/playable_game.dart'; | ||
|
|
||
| enum PresetMessageGroup { | ||
| start, | ||
| end; | ||
|
|
||
| static PresetMessageGroup? fromString(String groupName) { | ||
Happy0 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if (groupName == 'start') { | ||
| return start; | ||
| } else if (groupName == 'end') { | ||
| return end; | ||
| } else { | ||
| return null; | ||
| } | ||
| } | ||
|
|
||
| static PresetMessageGroup? fromGame(PlayableGame game) { | ||
| if (game.status.value <= GameStatus.mate.value && game.steps.length < 4) { | ||
| return start; | ||
| } else if (game.status.value >= GameStatus.mate.value) { | ||
| return end; | ||
| } else { | ||
| return null; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| typedef PresetMessage = ({String label, String value}); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| import 'package:flutter/cupertino.dart'; | ||
| import 'package:flutter_riverpod/flutter_riverpod.dart'; | ||
| import 'package:lichess_mobile/src/model/common/id.dart'; | ||
| import 'package:lichess_mobile/src/model/game/message_presets.dart'; | ||
| import 'package:lichess_mobile/src/widgets/buttons.dart'; | ||
|
|
||
| class PresetMessages extends ConsumerWidget { | ||
| final GameFullId gameId; | ||
| final List<PresetMessage> alreadySaid; | ||
| final PresetMessageGroup? presetMessageGroup; | ||
| final Map<PresetMessageGroup, List<PresetMessage>> presetMessages; | ||
| final void Function(PresetMessage presetMessage) sendChatPreset; | ||
|
|
||
| const PresetMessages({ | ||
| required this.gameId, | ||
| required this.alreadySaid, | ||
| required this.presetMessageGroup, | ||
| required this.presetMessages, | ||
| required this.sendChatPreset, | ||
| }); | ||
|
|
||
| @override | ||
| Widget build(BuildContext context, WidgetRef ref) { | ||
| final messages = presetMessages[presetMessageGroup] ?? []; | ||
|
|
||
| if (messages.isEmpty || alreadySaid.length >= 2) { | ||
| return const SizedBox.shrink(); | ||
| } | ||
|
|
||
| final notAlreadySaid = | ||
| messages.where((message) => !alreadySaid.contains(message)); | ||
|
|
||
| return Row( | ||
| children: notAlreadySaid | ||
| .map((preset) => _renderPresetMessageButton(preset, ref)) | ||
| .toList(), | ||
| ); | ||
| } | ||
|
|
||
| Widget _renderPresetMessageButton(PresetMessage preset, WidgetRef ref) { | ||
| return Padding( | ||
| padding: const EdgeInsets.all(4.0), | ||
| child: SecondaryButton( | ||
| semanticsLabel: preset.label, | ||
| onPressed: () { | ||
| sendChatPreset(preset); | ||
| }, | ||
| child: Text( | ||
| preset.label, | ||
| textAlign: TextAlign.center, | ||
| ), | ||
| ), | ||
| ); | ||
| } | ||
| } |
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
chatPresetControllerand put its logic in thechatController. This will simplify things hopefully as this logic belongs to the chat controller, and you won't have to worry about state invalidation anymore.