From 9457b06f09f9a4091bc9ea5327d5d08c03036d30 Mon Sep 17 00:00:00 2001 From: uliana57 Date: Mon, 25 Nov 2019 00:45:55 +0300 Subject: [PATCH] Made basic wordComplaining --- lib/app_state.dart | 54 ++++++++++++-- lib/dictionary.dart | 5 +- lib/game_state.dart | 31 +++++--- lib/game_state.g.dart | 17 +++++ lib/main.dart | 6 +- lib/match.dart | 7 +- lib/turn.dart | 169 +++++++++++++++++++++++++++++++----------- pubspec.lock | 4 +- pubspec.yaml | 1 + 9 files changed, 223 insertions(+), 71 deletions(-) diff --git a/lib/app_state.dart b/lib/app_state.dart index 9ce7c8b..575d250 100644 --- a/lib/app_state.dart +++ b/lib/app_state.dart @@ -5,6 +5,7 @@ import 'package:http/http.dart' as http; import 'package:mobx/mobx.dart'; import 'package:path_provider/path_provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import 'package:uuid/uuid.dart'; import 'dictionary.dart'; import 'game_state.dart'; @@ -17,6 +18,12 @@ abstract class _AppState with Store { @observable bool loaded = false; + @observable + var uuid = Uuid(); + + @observable + String deviceId; + @action void saveGameLog(gameLog) { if (!File('$documentsPath/gameLogs.json').existsSync()) { @@ -25,8 +32,8 @@ abstract class _AppState with Store { File('$documentsPath/gameLogs.json') .writeAsStringSync(jsonEncode(gameLogs)); } else { - List gameLogs = jsonDecode(File('$documentsPath/gameLogs.json') - .readAsStringSync()); + List gameLogs = + jsonDecode(File('$documentsPath/gameLogs.json').readAsStringSync()); gameLogs.add(gameLog); File('$documentsPath/gameLogs.json') .writeAsStringSync(jsonEncode(gameLogs)); @@ -42,8 +49,8 @@ abstract class _AppState with Store { @action Future sendSavedGameLogs() async { if (File('$documentsPath/gameLogs.json').existsSync()) { - List gameLogs = jsonDecode( - File('$documentsPath/gameLogs.json').readAsStringSync()); + List gameLogs = + jsonDecode(File('$documentsPath/gameLogs.json').readAsStringSync()); Set sentLogs = Set(); for (var gameLog in gameLogs) { var response = await sendGameLog(gameLog); @@ -54,15 +61,39 @@ abstract class _AppState with Store { for (var gameLog in sentLogs) { gameLogs.remove(gameLog); } - if (gameLogs.isEmpty) + if (gameLogs.isEmpty) { File('$documentsPath/gameLogs.json').deleteSync(); - else { - File('$documentsPath/gameLogs.json').writeAsStringSync( - jsonEncode(gameLogs)); + } else { + File('$documentsPath/gameLogs.json') + .writeAsStringSync(jsonEncode(gameLogs)); } } } + @action + Future sendSavedWordsComplains() async { + if (File('$documentsPath/wordsComplains.json').existsSync()) { + var response = await http.post( + 'http://the-hat-dev.appspot.com/$deviceId/complain', + body: File('$documentsPath/wordsComplains.json').readAsStringSync()); + if (response.statusCode == 200) + File('$documentsPath/wordsComplains.json').deleteSync(); + } + } + + @action + void saveWordsComplains(wordsComplains) { + List savedWordsComplains; + if (File('$documentsPath/wordsComplains.json').existsSync()) { + savedWordsComplains = jsonDecode( + File('$documentsPath/wordsComplains.json').readAsStringSync()); + } else { + savedWordsComplains = List(); + } + File('$documentsPath/wordsComplains.json') + .writeAsStringSync(jsonEncode(savedWordsComplains + wordsComplains)); + } + @observable GameState gameState; @@ -87,6 +118,13 @@ abstract class _AppState with Store { await sendSavedGameLogs(); dictionary = Dictionary(prefs, documentsPath); await dictionary.load(); + if (prefs.getString('deviceId') == null) { + deviceId = uuid.v4(); + prefs.setString('deviceId', deviceId); + } else { + deviceId = prefs.getString('deviceId'); + } + await sendSavedWordsComplains(); loaded = true; } } diff --git a/lib/dictionary.dart b/lib/dictionary.dart index 71b75d7..0238fc1 100644 --- a/lib/dictionary.dart +++ b/lib/dictionary.dart @@ -67,8 +67,9 @@ class Dictionary { List usedWords = getUsedWords(); int usedWordsIter = getUsedWordsIter(); for (var i = 0; i < size; i++) { - int bucketIdx = (Normal.generate(1)[0] / 3 * difficultyDispersion + - difficulty).round(); + int bucketIdx = + (Normal.generate(1)[0] / 3 * difficultyDispersion + difficulty) + .round(); while (bucketIdx < 0 || bucketIdx > 100) { bucketIdx = (Normal.generate(1)[0] / 3 * difficultyDispersion + difficulty) diff --git a/lib/game_state.dart b/lib/game_state.dart index 3ddd4b7..7ac9d82 100644 --- a/lib/game_state.dart +++ b/lib/game_state.dart @@ -21,10 +21,14 @@ abstract class _GameState with Store { lastStateLength = prefs.getInt('lastStateLength'); mainStateLength = prefs.getInt('mainStateLength'); fixTeams = prefs.getBool('fixTeams'); - audioPlayer.loadAll(['round_start_timer_tick.wav', - 'round_start_timer_timeout.wav', 'round_timer_timeout.wav', - 'word_outcome_fail.wav', 'word_outcome_ok.wav', - 'word_outcome_timeout.wav']); + audioPlayer.loadAll([ + 'round_start_timer_tick.wav', + 'round_start_timer_timeout.wav', + 'round_timer_timeout.wav', + 'word_outcome_fail.wav', + 'word_outcome_ok.wav', + 'word_outcome_timeout.wav' + ]); } @observable @@ -49,6 +53,9 @@ abstract class _GameState with Store { 'attempts': [] }; + @observable + List wordComplains = []; + @observable int mainStateLength; @@ -232,13 +239,13 @@ abstract class _GameState with Store { newTurnTimer = Timer.periodic(Duration(seconds: 1), (Timer _timeout) { newTurnTimerSecondPass(); if (newTurnTimerCnt == 0) { - audioPlayer.play( - 'round_start_timer_timeout.wav', mode: PlayerMode.LOW_LATENCY); + audioPlayer.play('round_start_timer_timeout.wav', + mode: PlayerMode.LOW_LATENCY); _timeout.cancel(); newTurn(); } else { - audioPlayer.play( - 'round_start_timer_tick.wav', mode: PlayerMode.LOW_LATENCY); + audioPlayer.play('round_start_timer_tick.wav', + mode: PlayerMode.LOW_LATENCY); } }); } @@ -255,8 +262,8 @@ abstract class _GameState with Store { } else if (timer == 0) { timeSpent = stopwatch.elapsedMilliseconds; if (lastStateLength != 0) { - audioPlayer.play( - 'round_timer_timeout.wav', mode: PlayerMode.LOW_LATENCY); + audioPlayer.play('round_timer_timeout.wav', + mode: PlayerMode.LOW_LATENCY); } stopwatch.reset(); changeState('last'); @@ -269,8 +276,8 @@ abstract class _GameState with Store { 'time': timeSpent, 'extra_time': lastStateLength, }); - audioPlayer.play( - 'round_start_timer_timeout.wav', mode: PlayerMode.LOW_LATENCY); + audioPlayer.play('round_start_timer_timeout.wav', + mode: PlayerMode.LOW_LATENCY); changeState('verdict'); stopwatch.stop(); } diff --git a/lib/game_state.g.dart b/lib/game_state.g.dart index a55fa6a..ddc825a 100644 --- a/lib/game_state.g.dart +++ b/lib/game_state.g.dart @@ -115,6 +115,23 @@ mixin _$GameState on _GameState, Store { }, _$gameLogAtom, name: '${_$gameLogAtom.name}_set'); } + final _$wordComplainsAtom = Atom(name: '_GameState.wordComplains'); + + @override + List get wordComplains { + _$wordComplainsAtom.context.enforceReadPolicy(_$wordComplainsAtom); + _$wordComplainsAtom.reportObserved(); + return super.wordComplains; + } + + @override + set wordComplains(List value) { + _$wordComplainsAtom.context.conditionallyRunInAction(() { + super.wordComplains = value; + _$wordComplainsAtom.reportChanged(); + }, _$wordComplainsAtom, name: '${_$wordComplainsAtom.name}_set'); + } + final _$mainStateLengthAtom = Atom(name: '_GameState.mainStateLength'); @override diff --git a/lib/main.dart b/lib/main.dart index 8fc6559..cf2a0d4 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -69,7 +69,8 @@ class MyApp extends StatelessWidget { ); }, child: Text('Настройки', - style: TextStyle(color: Colors.blue, + style: TextStyle( + color: Colors.blue, fontSize: 25))))) ]), TableRow(children: [ @@ -104,7 +105,8 @@ class MyApp extends StatelessWidget { builder: (context) => Info())); }, child: Text('Правила и доп. информация', - style: TextStyle(color: Colors.blue, + style: TextStyle( + color: Colors.blue, fontSize: 25))))) ]) ])); diff --git a/lib/match.dart b/lib/match.dart index a57d0a9..55e9a74 100644 --- a/lib/match.dart +++ b/lib/match.dart @@ -86,9 +86,10 @@ class Match extends StatelessWidget { if (currentGameState.validateAll()) { currentGameState.createHat(currentAppState.dictionary); currentGameState.timer = currentGameState.mainStateLength; - currentGameState.gameLog['start_timestamp'] = DateTime - .now() - .millisecondsSinceEpoch; + currentGameState.gameLog['start_timestamp'] = + DateTime + .now() + .millisecondsSinceEpoch; Navigator.pushAndRemoveUntil( context, MaterialPageRoute( diff --git a/lib/turn.dart b/lib/turn.dart index 79b4527..74d4d5e 100644 --- a/lib/turn.dart +++ b/lib/turn.dart @@ -23,10 +23,12 @@ class Turn extends StatelessWidget { backgroundColor: Color(0xFFDEA90C), child: Icon(Icons.arrow_forward), onPressed: () { - currentState.gameLog['end_timestamp'] = DateTime - .now() - .millisecondsSinceEpoch; + currentState.gameLog['end_timestamp'] = + DateTime + .now() + .millisecondsSinceEpoch; currentAppState.saveGameLog(currentState.gameLog); + currentAppState.saveWordsComplains(currentState.wordComplains); Navigator.pushAndRemoveUntil( context, MaterialPageRoute( @@ -130,10 +132,9 @@ class Turn extends StatelessWidget { appBar: AppBar( title: Text('Шляпа'), ), - body: Center(child: Text( - currentState.newTurnTimerCnt.toString(), - style: TextStyle(fontSize: 157)))) - ); + body: Center( + child: Text(currentState.newTurnTimerCnt.toString(), + style: TextStyle(fontSize: 157))))); } else { return Scaffold( appBar: AppBar( @@ -231,7 +232,7 @@ class GuessedRightButton extends StatelessWidget { style: TextStyle(color: Colors.white), ), icon: Icon( - Icons.thumb_up, + Icons.check, color: Colors.white, ), ); @@ -246,7 +247,7 @@ class GuessedWrongButton extends StatelessWidget { .gameState; return FlatButton.icon( - icon: Icon(Icons.thumb_down, color: Colors.white), + icon: Icon(Icons.close, color: Colors.white), onPressed: () { currentState.concede(); }, @@ -263,7 +264,7 @@ class ConcedeButton extends StatelessWidget { .gameState; return FlatButton.icon( - icon: Icon(Icons.thumb_down, color: Colors.white), + icon: Icon(Icons.close, color: Colors.white), onPressed: () { currentState.concede(); }, @@ -322,38 +323,52 @@ class _RoundEditingState extends State { if (shownNotGuessedIdx.contains(idx)) { return Card( child: ListTile( - leading: Icon(Icons.thumb_down), + leading: Icon(Icons.close), title: Text(currentState.turnLog[idx]['word']), - trailing: DropdownButton( - value: 'Не угадано', - onChanged: (value) { - setState(() { - if (value == 'Угадано') { - currentState.turnLog[idx]['outcome'] = - 'guessed'; - currentState.players[currentState.playerOneID] - .explainedRight(); - currentState.players[currentState.playerTwoID] - .guessedRight(); - } else if (value == 'Ошибка') { - currentState.turnLog[idx]['outcome'] = 'failed'; - currentState.hat - .removeWord( - currentState.turnLog[idx]['word']); - } - }); - }, - items: ['Угадано', 'Не угадано', 'Ошибка'] - .map>((String value) { - return DropdownMenuItem( - value: value, - child: Text(value), - ); - }).toList()))); + trailing: IntrinsicWidth( + child: Row(children: [ + IconButton( + icon: Icon(Icons.thumb_down), + onPressed: () { + return showDialog( + context: context, + builder: (BuildContext context) => + WordComplainDialog()); + }), + DropdownButton( + value: 'Не угадано', + onChanged: (value) { + setState(() { + if (value == 'Угадано') { + currentState.turnLog[idx]['outcome'] = + 'guessed'; + currentState.players[currentState + .playerOneID] + .explainedRight(); + currentState.players[currentState + .playerTwoID] + .guessedRight(); + } else if (value == 'Ошибка') { + currentState.turnLog[idx]['outcome'] = + 'failed'; + currentState.hat.removeWord( + currentState.turnLog[idx]['word']); + } + }); + }, + items: ['Угадано', 'Не угадано', 'Ошибка'] + .map>(( + String value) { + return DropdownMenuItem( + value: value, + child: Text(value), + ); + }).toList()) + ])))); } else { return Card( child: ListTile( - leading: Icon(Icons.thumb_down), + leading: Icon(Icons.close), title: FlatButton( child: Text('Показать слово', style: TextStyle(fontSize: 15)), @@ -367,7 +382,7 @@ class _RoundEditingState extends State { } else if (currentState.turnLog[idx]['outcome'] == 'guessed') { return Card( child: ListTile( - leading: Icon(Icons.thumb_up, color: Colors.green), + leading: Icon(Icons.check, color: Colors.green), title: Text(currentState.turnLog[idx]['word']), trailing: DropdownButton( value: 'Угадано', @@ -381,9 +396,8 @@ class _RoundEditingState extends State { .guessedWrong(); } else if (value == 'Ошибка') { currentState.turnLog[idx]['outcome'] = 'failed'; - currentState.hat - .removeWord(currentState - .turnLog[idx]['word']); + currentState.hat.removeWord( + currentState.turnLog[idx]['word']); currentState.players[currentState.playerOneID] .explainedWrong(); currentState.players[currentState.playerTwoID] @@ -431,3 +445,74 @@ class _RoundEditingState extends State { }); } } + +class WordComplainDialog extends StatefulWidget { + final String word; + + const WordComplainDialog({Key key, this.word}) : super(key: key); + + @override + _WordComplainDialogState createState() => _WordComplainDialogState(); +} + +class _WordComplainDialogState extends State { + String word; + String reason = 'non_noun'; + + @override + void initState() { + word = widget.word; + super.initState(); + } + + @override + Widget build(BuildContext context) { + final currentState = Provider + .of(context) + .gameState; + return AlertDialog( + title: Text('Пожаловаться на слово'), + content: Container( + width: double.maxFinite, + child: ListView( + shrinkWrap: true, + children: [ + ListTile( + title: Text('Не существительное'), + leading: Radio( + value: 'non_noun', + groupValue: reason, + onChanged: (value) { + setState(() { + reason = value; + }); + })), + ListTile( + title: Text('Несловарное слово'), + leading: Radio( + value: 'non_dict', + groupValue: reason, + onChanged: (value) { + setState(() { + reason = value; + }); + })) + ], + )), + actions: [ + FlatButton( + child: Text('Отмена'), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + FlatButton( + child: Text('Готово'), + onPressed: () { + currentState.wordComplains + .add({'word': word, 'reason': reason}); + Navigator.of(context).pop(); + }) + ]); + } +} diff --git a/pubspec.lock b/pubspec.lock index 00f01b1..7308233 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -491,7 +491,7 @@ packages: name: sqflite url: "https://pub.dartlang.org" source: hosted - version: "1.1.7+2" + version: "1.1.7+3" stack_trace: dependency: transitive description: @@ -570,7 +570,7 @@ packages: source: hosted version: "1.0.1" uuid: - dependency: transitive + dependency: "direct main" description: name: uuid url: "https://pub.dartlang.org" diff --git a/pubspec.yaml b/pubspec.yaml index 9502108..4c82011 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -29,6 +29,7 @@ dependencies: path_provider: ^1.3.1 audioplayers: 0.13.2 url_launcher: ^5.2.5 + uuid: ^2.0.4 # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^0.1.2