Skip to content

Commit

Permalink
feat: modularize dict_parser & restartable games
Browse files Browse the repository at this point in the history
- make dict_parser more modular to support more languages
- add custom entries to dict_parser
- add next starting character hint to text field
- add restart button to game
  • Loading branch information
jeroen-meijer committed Jul 26, 2020
1 parent 62a1273 commit 2c86c2e
Show file tree
Hide file tree
Showing 12 changed files with 255 additions and 166 deletions.
2 changes: 1 addition & 1 deletion app/assets/dicts/dict_ja.json

Large diffs are not rendered by default.

14 changes: 6 additions & 8 deletions app/lib/backend/models/game.dart
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ class Game extends ChangeNotifier {
final int startingPlayerIndex;
final Map<int, Set<Guess>> guessesByPlayerIndex;

Language get language => settings.dictionary.language;

int get winningPlayerIndex => _winningPlayerIndex;
int _winningPlayerIndex;

Expand All @@ -68,8 +70,6 @@ class Game extends ChangeNotifier {

_log(0, 'query: "$query"');

final language = settings.dictionary.language;

_log(1, 'startingCharacterForNextGuess: $startingCharacterForNextGuess');
final followsPattern = startingCharacterForNextGuess ==
language.selectStartingCharacter(query);
Expand Down Expand Up @@ -141,9 +141,8 @@ class Game extends ChangeNotifier {
guessesByPlayerIndex[1] = guessesByPlayerIndex[1]
..add(
Guess(
query: nextWord.phoneticSpellings
.where(settings.dictionary.language.validate)
.random,
query:
nextWord.phoneticSpellings.where(language.validate).random,
validity: GuessValidity.valid,
entry: nextWord,
),
Expand Down Expand Up @@ -202,11 +201,10 @@ class Game extends ChangeNotifier {
return null;
}

return settings.dictionary.language
.selectEndingCharacter(lastGuess.right.query);
return language.selectEndingCharacter(lastGuess.right.query);
}

String transformGuess(String guess) {
return settings.dictionary.language.mapToLanguage(guess);
return language.mapToLanguage(guess);
}
}
18 changes: 4 additions & 14 deletions app/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,19 @@ import 'package:shiritori/backend/backend.dart';
import 'assets/assets.dart';

void main() async {
var level = 0;
void _log(String message) {
log(
message,
name: 'main',
sequenceNumber: level++,
time: DateTime.now(),
);
}

_log('Initializing bindings...');
log('Initializing bindings...');

final initStopwatch = Stopwatch()..start();
WidgetsFlutterBinding.ensureInitialized();
_log('Loading background image...');
log('Loading background image...');
final backgroundImage = await Images.loadBackground();
_log('Loading dictionaries...');
log('Loading dictionaries...');
// Poor phone :(
final dictionaries = await Dictionaries.loadFromDisk();
initStopwatch.stop();

final seconds = (initStopwatch.elapsedMilliseconds / 1000).toStringAsFixed(3);
_log('Initialization done. (took $seconds seconds)');
log('Initialization done. (took $seconds seconds)');

runApp(
AppRoot(
Expand Down
81 changes: 53 additions & 28 deletions app/lib/ui/screens/game/game_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,17 @@ import 'package:animations/animations.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shiritori/backend/backend.dart';
import 'package:shiritori/ui/screens/game/pages/pages.dart';

class GameScreen extends StatefulWidget {
const GameScreen({Key key}) : super(key: key);
const GameScreen({
Key key,
@required this.settings,
}) : assert(settings != null),
super(key: key);

final GameSettings settings;

@override
_GameScreenState createState() => _GameScreenState();
Expand All @@ -16,12 +23,28 @@ class GameScreen extends StatefulWidget {
class _GameScreenState extends State<GameScreen> {
static const _playCountdownSeconds = 3;

Game _game;

int _secondsRemaining;
Timer _playCountdownTimer;

bool get _showInGame => _secondsRemaining == 0;

@override
void initState() {
super.initState();
_game = Game.startNew(widget.settings);
_resetTimer();
}

@override
void dispose() {
_playCountdownTimer?.cancel();
super.dispose();
}

void _resetTimer() {
_secondsRemaining = _playCountdownSeconds;
// Delaying the timer to sync up better with the surrounding animation.
Future.delayed(const Duration(milliseconds: 300), () {
_playCountdownTimer = Timer.periodic(
Expand All @@ -31,40 +54,42 @@ class _GameScreenState extends State<GameScreen> {
});
}

@override
void dispose() {
_playCountdownTimer?.cancel();
super.dispose();
}

void _onPlayCountdownTimerTick() {
setState(() {});
if (_playCountdownTimer.tick == _playCountdownSeconds) {
_playCountdownTimer.cancel();
}
setState(() {
_secondsRemaining = _playCountdownSeconds - _playCountdownTimer.tick;
if (_playCountdownTimer.tick == _playCountdownSeconds) {
_playCountdownTimer.cancel();
}
});
}

int get _playCountdownSecondsRemaining {
return _playCountdownSeconds - (_playCountdownTimer?.tick ?? 0);
void _onRestart() {
_game = Game.startNew(widget.settings);
setState(_resetTimer);
}

@override
Widget build(BuildContext context) {
return PageTransitionSwitcher(
transitionBuilder: (child, animation, secondaryAnimation) {
return SharedAxisTransition(
transitionType: SharedAxisTransitionType.vertical,
animation: animation,
secondaryAnimation: secondaryAnimation,
child: child,
);
},
child: _playCountdownSecondsRemaining > 0
? Provider.value(
value: _playCountdownSecondsRemaining,
child: const CountdownPage(),
)
: const InGamePage(),
return ChangeNotifierProvider.value(
value: _game,
child: PageTransitionSwitcher(
transitionBuilder: (child, animation, secondaryAnimation) {
return SharedAxisTransition(
transitionType: SharedAxisTransitionType.vertical,
animation: animation,
secondaryAnimation: secondaryAnimation,
child: child,
);
},
child: !_showInGame
? Provider.value(
value: _secondsRemaining,
child: const CountdownPage(),
)
: InGamePage(
onRestart: _onRestart,
),
),
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class CountdownPage extends StatelessWidget {
style: textTheme.headline3,
),
Text(
game.settings.dictionary.language.name,
game.language.name,
style: textTheme.headline4,
),
],
Expand Down
44 changes: 38 additions & 6 deletions app/lib/ui/screens/game/pages/in_game/in_game_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@ import 'package:shiritori/ui/screens/game/game.dart';
import 'package:shiritori/ui/widgets/widgets.dart';

class InGamePage extends StatefulWidget {
const InGamePage({Key key}) : super(key: key);
const InGamePage({
Key key,
this.onRestart,
}) : super(key: key);

final VoidCallback onRestart;

@override
_InGamePageState createState() => _InGamePageState();
Expand Down Expand Up @@ -59,8 +64,7 @@ class _InGamePageState extends State<InGamePage> {

setState(() {
_textController.clear();
final transformed =
_game.settings.dictionary.language.mapToLanguage(value);
final transformed = _game.language.mapToLanguage(value);
_game.addGuess(transformed);
});
}
Expand Down Expand Up @@ -93,6 +97,10 @@ class _InGamePageState extends State<InGamePage> {

@override
Widget build(BuildContext context) {
final nextCharHint = Tuple(
_game.startingCharacterForNextGuess,
_game.language.mapFromLanguage(_game.startingCharacterForNextGuess),
);
return Scaffold(
resizeToAvoidBottomInset: true,
resizeToAvoidBottomPadding: true,
Expand All @@ -114,7 +122,30 @@ class _InGamePageState extends State<InGamePage> {
),
),
),
if (!_game.isFinished)
if (_game.isFinished) ...[
Material(
color: AppTheme.blue,
child: InkWell(
onTap: widget.onRestart,
child: SizedBox(
width: double.infinity,
height: 64.0,
child: Center(
child: DefaultTextStyle(
// TODO: Refactor to separate button stuff
style: Theme.of(context).textTheme.button.copyWith(
color: AppTheme.colorButtonForegroundPrimary,
fontWeight: FontWeight.bold,
fontSize: 24.0,
),
// TODO: intl
child: const Text('Restart'),
),
),
),
),
)
] else
TextField(
controller: _textController,
focusNode: _focusNode,
Expand All @@ -127,8 +158,9 @@ class _InGamePageState extends State<InGamePage> {
onEditingComplete: () {
// Do nothing. Prevents keyboard from hiding.
},
decoration: const InputDecoration(
border: OutlineInputBorder(
decoration: InputDecoration(
hintText: nextCharHint.fold((left, right) => '$left/$right'),
border: const OutlineInputBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(16.0),
topRight: Radius.circular(16.0),
Expand Down
11 changes: 4 additions & 7 deletions app/lib/ui/screens/home/home_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,11 @@ class HomeScreen extends StatelessWidget {
),
ExpandingRouteButton(
routeBuilder: (context) {
return ChangeNotifierProvider(
create: (_) => Game.startNew(
SingleplayerGameSettings(
dictionary: Dictionaries.of(context).japanese,
answeringDuration: const Duration(seconds: 10),
),
return GameScreen(
settings: SingleplayerGameSettings(
dictionary: Dictionaries.of(context).japanese,
answeringDuration: const Duration(seconds: 10),
),
child: const GameScreen(),
);
},
child: Text(intl.quickPlayButtonTitle),
Expand Down
12 changes: 4 additions & 8 deletions app/lib/ui/screens/home/widgets/home_menu.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import 'package:animations/animations.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:provider/provider.dart';
import 'package:shiritori/backend/backend.dart';
import 'package:shiritori/intl/intl.dart';
import 'package:shiritori/theme/theme.dart';
Expand Down Expand Up @@ -30,14 +29,11 @@ class HomeMenu extends StatelessWidget {
color: AppTheme.colorSingleplayer,
icon: const Text('遊ぶ'),
expandedChildBuilder: (context) {
return ChangeNotifierProvider(
create: (_) => Game.startNew(
SingleplayerGameSettings(
dictionary: Dictionaries.of(context).japanese,
answeringDuration: const Duration(seconds: 10),
),
return GameScreen(
settings: SingleplayerGameSettings(
dictionary: Dictionaries.of(context).japanese,
answeringDuration: const Duration(seconds: 10),
),
child: const GameScreen(),
);
},
),
Expand Down
25 changes: 25 additions & 0 deletions dict_parser/lib/generators/generators.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import 'dart:io';

import 'package:dict_parser/utils.dart';
import 'package:kana_kit/kana_kit.dart';
import 'package:meta/meta.dart';
import 'package:shared_models/shared_models.dart';
import 'package:xml/xml.dart';

part 'japanese.dart';

class Generator {
const Generator._({
@required this.language,
this.customEntries = const [],
@required this.generateEntries,
});

final Language language;
final Iterable<WordEntry> customEntries;
final Future<Iterable<WordEntry>> Function(List<String> args) generateEntries;

static final Generator japanese = _japanese;

static final List<Generator> all = [_japanese];
}
Loading

0 comments on commit 2c86c2e

Please sign in to comment.