croupier: Become more Material
The implementation of the UI is now much more Material.
- Scaffold with Toolbar and Drawer
- Routes for Settings and Debug pages
- Styled text and buttons (though not all of them)
Fixed some minor bugs:
- Suit order in card collection should be Club/Diamond/Spade/Hearts
- Animating ZCards are now always drawn on top of static ZCards.
Added Debug Mode:
- This flag had to be threaded through the Croupier and Game logic.
When enabled, it will allow you to see the Debug Button bar.
Missing
- some backgrounds aren't styled right yet.
- styles are a complete copy-paste of the Syncslides styles
Change-Id: I1dd5d2de2d2996c867f54ce4ab067c9245e71710
diff --git a/Makefile b/Makefile
index 7ae15e9..c8306b0 100644
--- a/Makefile
+++ b/Makefile
@@ -46,7 +46,7 @@
SYNCBASE_FLAGS += $(SYNCBASE_NAME_FLAG)
endif
-# If this is not the first mojo shell, then you must reuse the devservers
+# If this is not the first mojo shell, then you must reuse the dev servers
# to avoid a "port in use" error.
ifneq ($(shell fuser 31841/tcp),)
REUSE_FLAG := --reuse-servers
@@ -130,6 +130,12 @@
endif
$(call RUN_SKY_APP,$<)
+# Occasionally, mojo will leave some dev servers running on port 31841, which
+# prevents proper restarts. This rule cleans up the offending process.
+.PHONY: stop-mojo
+stop-mojo:
+ -fuser -k 31841/tcp
+
CROUPIER_SHORTCUT_NAME := Croupier
CROUPIER_URL := mojo://storage.googleapis.com/mojo_services/croupier/croupier.flx
CROUPIER_URL_TO_ICON := https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png
diff --git a/lib/components/card.dart b/lib/components/card.dart
index e3dbd89..b2f5e71 100644
--- a/lib/components/card.dart
+++ b/lib/components/card.dart
@@ -57,7 +57,7 @@
animateEntrance = dataComponent.animateEntrance,
z = dataComponent.z;
- _ZCardState createState() => new _ZCardState();
+ ZCardState createState() => new ZCardState();
}
class Card extends widgets.StatefulComponent {
@@ -101,9 +101,15 @@
// Check if the data between these Cards matches.
// This isn't == since I don't want to override that and hashCode.
bool isMatchWith(Card c) {
- return c.card == card && c.faceUp == faceUp && c.width == width &&
- c.height == height && c.rotation == rotation && c.useKey == useKey &&
- c.visible == visible && c.animateEntrance == animateEntrance && c.z == z;
+ return c.card == card &&
+ c.faceUp == faceUp &&
+ c.width == width &&
+ c.height == height &&
+ c.rotation == rotation &&
+ c.useKey == useKey &&
+ c.visible == visible &&
+ c.animateEntrance == animateEntrance &&
+ c.z == z;
}
CardState createState() => new CardState();
@@ -121,7 +127,8 @@
widgets.Widget image = new widgets.Opacity(
opacity: config.visible ? 1.0 : 0.0,
child: new widgets.Transform(
- child: _imageFromCard(config.card, config.faceUp, config.width, config.height),
+ child: _imageFromCard(
+ config.card, config.faceUp, config.width, config.height),
transform:
new vector_math.Matrix4.identity().rotateZ(config.rotation),
alignment: new FractionalOffset(0.5, 0.5)));
@@ -130,14 +137,15 @@
}
}
-widgets.Widget _imageFromCard(logic_card.Card c, bool faceUp, double width, double height) {
+widgets.Widget _imageFromCard(
+ logic_card.Card c, bool faceUp, double width, double height) {
// TODO(alexfandrianto): Instead of 'default', what if we were told which theme to use?
String imageName =
"images/default/${c.deck}/${faceUp ? 'up' : 'down'}/${c.identifier}.png";
return new widgets.AssetImage(name: imageName, width: width, height: height);
}
-class _ZCardState extends widgets.State<ZCard> {
+class ZCardState extends widgets.State<ZCard> {
ValuePerformance<Point> _performance;
List<
Point> _pointQueue; // at least 1 longer than the current animation index.
@@ -215,6 +223,11 @@
return _animationIndex < _pointQueue.length - 1;
}
+ // Return the current animation position of the ZCard.
+ Point get localPosition {
+ return _performance.variable.value;
+ }
+
void _tryAnimate() {
// Let animations finish... (Is this a good idea?)
if (!_performance.isAnimating && _needsAnimation()) {
@@ -231,7 +244,8 @@
widgets.Widget build(widgets.BuildContext context) {
widgets.Widget image = new widgets.Transform(
- child: _imageFromCard(config.card, config.faceUp, config.width, config.height),
+ child: _imageFromCard(
+ config.card, config.faceUp, config.width, config.height),
transform: new vector_math.Matrix4.identity().rotateZ(config.rotation),
alignment: new FractionalOffset(0.5, 0.5));
diff --git a/lib/components/card_collection.dart b/lib/components/card_collection.dart
index 2248fba..9ece2cd 100644
--- a/lib/components/card_collection.dart
+++ b/lib/components/card_collection.dart
@@ -192,7 +192,10 @@
opacity: 0.45,
child: emptyBackgroundImage == ""
? null
- : new AssetImage(name: emptyBackgroundImage, fit: ImageFit.scaleDown, height: config.heightCard))));
+ : new AssetImage(
+ name: emptyBackgroundImage,
+ fit: ImageFit.scaleDown,
+ height: config.heightCard))));
}
double w = config.width ?? config.widthCard * 5;
@@ -269,19 +272,19 @@
decoration: new BoxDecoration(backgroundColor: Colors.white),
child: new Stack(<Widget>[
new Positioned(
- top: 0.0,
+ top: 2 * _produceRowHeight + 2 * _whiteLineHeight,
child: _produceRow(ss,
emptyBackgroundImage: "images/suits/Spade.png")),
new Positioned(
- top: _produceRowHeight + _whiteLineHeight,
+ top: 3 * _produceRowHeight + 3 * _whiteLineHeight,
child: _produceRow(hs,
emptyBackgroundImage: "images/suits/Heart.png")),
new Positioned(
- top: 2 * _produceRowHeight + 2 * _whiteLineHeight,
+ top: 0.0,
child: _produceRow(cs,
emptyBackgroundImage: "images/suits/Club.png")),
new Positioned(
- top: 3 * _produceRowHeight + 3 * _whiteLineHeight,
+ top: _produceRowHeight + _whiteLineHeight,
child: _produceRow(ds,
emptyBackgroundImage: "images/suits/Diamond.png"))
]));
diff --git a/lib/components/croupier.dart b/lib/components/croupier.dart
index 183a180..5ccdf6e 100644
--- a/lib/components/croupier.dart
+++ b/lib/components/croupier.dart
@@ -2,16 +2,16 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-import '../logic/croupier.dart' as logic_croupier;
-import '../logic/croupier_settings.dart' show CroupierSettings;
-import '../logic/game/game.dart' as logic_game;
-import 'game.dart' as component_game;
-import 'croupier_settings.dart' show CroupierSettingsComponent;
-import 'croupier_profile.dart' show CroupierProfileComponent;
+import 'dart:ui' as ui;
import 'package:flutter/material.dart';
-import 'dart:ui' as ui;
+import '../logic/croupier.dart' as logic_croupier;
+import '../logic/croupier_settings.dart' show CroupierSettings;
+import '../logic/game/game.dart' as logic_game;
+import '../styles/common.dart' as style;
+import 'croupier_profile.dart' show CroupierProfileComponent;
+import 'game.dart' as component_game;
typedef void NoArgCb();
@@ -24,8 +24,7 @@
}
class CroupierComponentState extends State<CroupierComponent> {
- ui.Size screenSize;
-
+ @override
void initState() {
super.initState();
// TODO(alexfandrianto): ui.window.size.width and ui.window.size.height?
@@ -45,18 +44,14 @@
});
}
- void sizeChanged(ui.Size newSize) {
- print(newSize);
- setState(() {
- screenSize = newSize;
- });
- }
-
Widget build(BuildContext context) {
- return new SizeObserver(onSizeChanged: sizeChanged, child: _buildHelper());
- }
+ // TODO(alexfandrianto): A better way to do this is to show the splash
+ // screen while the Store is initializing.
+ // https://github.com/vanadium/issues/issues/958
+ if (config.croupier.settings == null) {
+ return _buildSplashScreen();
+ }
- Widget _buildHelper() {
switch (config.croupier.state) {
case logic_croupier.CroupierState.Welcome:
// in which we show them a UI to start a new game, join a game, or change some settings.
@@ -64,49 +59,38 @@
padding: new EdgeDims.only(top: ui.window.padding.top),
child: new Column([
new FlatButton(
- child: new Text('Create Game'),
+ child: new Text('Create Game', style: style.Text.titleStyle),
onPressed: makeSetStateCallback(
logic_croupier.CroupierState.ChooseGame)),
new FlatButton(
- child: new Text('Join Game'),
+ child: new Text('Join Game', style: style.Text.titleStyle),
onPressed: makeSetStateCallback(
- logic_croupier.CroupierState.JoinGame)),
- new FlatButton(
- child: new Text('Settings'),
- onPressed: makeSetStateCallback(
- logic_croupier.CroupierState.Settings))
+ logic_croupier.CroupierState.JoinGame))
]));
- case logic_croupier.CroupierState.Settings:
- // in which we let them pick an avatar, name, and color. And return to the previous screen after.
- return new Container(
- padding: new EdgeDims.only(top: ui.window.padding.top),
- child: new CroupierSettingsComponent(
- config.croupier.settings,
- config.croupier.settings_manager.save,
- makeSetStateCallback(logic_croupier.CroupierState.Welcome)));
case logic_croupier.CroupierState.ChooseGame:
// in which we let them pick a game out of the many possible games... There aren't that many.
return new Container(
padding: new EdgeDims.only(top: ui.window.padding.top),
child: new Flex([
new FlatButton(
- child: new Text('Proto'),
+ child: new Text('Proto', style: style.Text.titleStyle),
onPressed: makeSetStateCallback(
logic_croupier.CroupierState.ArrangePlayers,
logic_game.GameType.Proto)),
new FlatButton(
- child: new Text('Hearts'),
+ child: new Text('Hearts', style: style.Text.titleStyle),
onPressed: makeSetStateCallback(
logic_croupier.CroupierState.ArrangePlayers,
logic_game.GameType.Hearts)),
- new FlatButton(child: new Text('Poker')),
new FlatButton(
- child: new Text('Solitaire'),
+ child: new Text('Poker', style: style.Text.titleStyle)),
+ new FlatButton(
+ child: new Text('Solitaire', style: style.Text.titleStyle),
onPressed: makeSetStateCallback(
logic_croupier.CroupierState.ArrangePlayers,
logic_game.GameType.Solitaire)),
new FlatButton(
- child: new Text('Back'),
+ child: new Text('Back', style: style.Text.subtitleStyle),
onPressed: makeSetStateCallback(
logic_croupier.CroupierState.Welcome))
], direction: FlexDirection.vertical));
@@ -128,10 +112,13 @@
return new Container(
padding: new EdgeDims.only(top: ui.window.padding.top),
child: new Column([
- new Text("Can join these games..."),
+ profileWidgets.length == 0
+ ? new Text("Looking for Games...",
+ style: style.Text.titleStyle)
+ : new Text("Available Games", style: style.Text.titleStyle),
new Grid(profileWidgets, maxChildExtent: 150.0),
new FlatButton(
- child: new Text('Back'),
+ child: new Text('Back', style: style.Text.subtitleStyle),
onPressed: makeSetStateCallback(
logic_croupier.CroupierState.Welcome))
]));
@@ -166,11 +153,17 @@
config.croupier.game.quit();
makeSetStateCallback(logic_croupier.CroupierState.Welcome)();
},
- width: screenSize.width,
- height: screenSize.height - ui.window.padding.top));
+ width: ui.window.size.width,
+ height: ui.window.size.height - ui.window.padding.top));
default:
assert(false);
return null;
}
}
+
+ // TODO(alexfandrianto): Can we do better than this?
+ Widget _buildSplashScreen() {
+ return new Container(
+ child: new Text("Loading Croupier...", style: style.Text.titleStyle));
+ }
}
diff --git a/lib/components/croupier_profile.dart b/lib/components/croupier_profile.dart
index d8fe840..0a9390a 100644
--- a/lib/components/croupier_profile.dart
+++ b/lib/components/croupier_profile.dart
@@ -2,10 +2,11 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-import '../logic/croupier_settings.dart' show CroupierSettings;
-
import 'package:flutter/material.dart';
+import '../logic/croupier_settings.dart' show CroupierSettings;
+import '../styles/common.dart' as style;
+
class CroupierProfileComponent extends StatelessComponent {
final CroupierSettings settings;
CroupierProfileComponent(this.settings);
@@ -14,7 +15,9 @@
return new Container(
decoration:
new BoxDecoration(backgroundColor: new Color(settings.color)),
- child: new Column(
- [new AssetImage(name: CroupierSettings.makeAvatarUrl(settings.avatar)), new Text(settings.name)]));
+ child: new Column([
+ new AssetImage(name: CroupierSettings.makeAvatarUrl(settings.avatar)),
+ new Text(settings.name, style: style.Text.liveNow)
+ ]));
}
}
diff --git a/lib/components/croupier_settings.dart b/lib/components/croupier_settings.dart
index fe6f194..fc218c5 100644
--- a/lib/components/croupier_settings.dart
+++ b/lib/components/croupier_settings.dart
@@ -31,9 +31,8 @@
class CroupierSettingsComponent extends StatefulComponent {
final CroupierSettings settings;
final SaveDataCb saveDataCb;
- final NoArgCb backCb;
- CroupierSettingsComponent(this.settings, this.saveDataCb, this.backCb);
+ CroupierSettingsComponent(this.settings, this.saveDataCb);
CroupierSettingsComponentState createState() =>
new CroupierSettingsComponentState();
@@ -61,18 +60,34 @@
}
Widget _makeImageButton(String url, NoArgCb cb) {
- return new FlatButton(child: new AssetImage(name: CroupierSettings.makeAvatarUrl(url)), onPressed: cb);
+ return new FlatButton(
+ child: new AssetImage(name: CroupierSettings.makeAvatarUrl(url)),
+ onPressed: cb);
}
Widget build(BuildContext context) {
+ return new Scaffold(
+ toolBar: _buildToolBar(), body: _buildSettingsPane(context));
+ }
+
+ Widget _buildToolBar() {
+ return new ToolBar(
+ left: new IconButton(
+ icon: "navigation/arrow_back",
+ onPressed: () => Navigator.of(context).pop()),
+ center: new Text("Settings"));
+ }
+
+ Widget _buildSettingsPane(BuildContext context) {
List<Widget> w = new List<Widget>();
w.add(_makeButtonRow(nameKey, new Text(config.settings.name)));
w.add(_makeButtonRow(
colorKey, _makeColoredRectangle(config.settings.color, "", null)));
w.add(_makeButtonRow(
- avatarKey, new AssetImage(name: CroupierSettings.makeAvatarUrl(config.settings.avatar))));
+ avatarKey,
+ new AssetImage(
+ name: CroupierSettings.makeAvatarUrl(config.settings.avatar))));
- w.add(new FlatButton(child: new Text("Return"), onPressed: config.backCb));
return new Column(w);
}
diff --git a/lib/components/debug_route.dart b/lib/components/debug_route.dart
new file mode 100644
index 0000000..a0551ed
--- /dev/null
+++ b/lib/components/debug_route.dart
@@ -0,0 +1,53 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+import 'package:flutter/material.dart';
+
+import '../logic/croupier.dart' show Croupier;
+import '../styles/common.dart' as style;
+
+// TODO(alexfandrianto): Remove this file once Flutter alpha branch is updated
+// and this route's Switch can be placed within the DrawerItem.
+// https://github.com/vanadium/issues/issues/957
+class DebugRoute extends StatefulComponent {
+ final Croupier croupier;
+
+ DebugRoute(this.croupier);
+
+ DebugRouteState createState() => new DebugRouteState();
+}
+
+class DebugRouteState extends State<DebugRoute> {
+ Widget build(BuildContext context) {
+ return new Scaffold(
+ toolBar: _buildToolBar(), body: _buildDebugPane(context));
+ }
+
+ Widget _buildToolBar() {
+ return new ToolBar(
+ left: new IconButton(
+ icon: "navigation/arrow_back",
+ onPressed: () => Navigator.of(context).pop()),
+ center: new Text("Debug Settings"));
+ }
+
+ Widget _buildDebugPane(BuildContext context) {
+ return new Row([
+ new Text('Debug Mode', style: style.Text.titleStyle),
+ new Switch(value: config.croupier.debugMode, onChanged: _handleDebugMode),
+ ],
+ justifyContent: FlexJustifyContent.spaceAround,
+ alignItems: FlexAlignItems.start);
+ }
+
+ void _handleDebugMode(bool value) {
+ print("new value is ${value}. Old is ${config.croupier.debugMode}");
+ setState(() {
+ config.croupier.debugMode = value;
+ if (config.croupier.game != null) {
+ config.croupier.game.debugMode = value;
+ }
+ });
+ }
+}
diff --git a/lib/components/game.dart b/lib/components/game.dart
index 9bb71b0..66d13da 100644
--- a/lib/components/game.dart
+++ b/lib/components/game.dart
@@ -12,6 +12,7 @@
import 'card.dart' as component_card;
import 'card_collection.dart'
show CardCollectionComponent, DropType, CardCollectionOrientation, AcceptCb;
+import '../styles/common.dart' as style;
import 'package:flutter/animation.dart';
import 'package:flutter/material.dart';
@@ -61,7 +62,8 @@
// A helper that subclasses might override to create buttons.
Widget _makeButton(String text, NoArgCb callback) {
- return new FlatButton(child: new Text(text), onPressed: callback);
+ return new FlatButton(
+ child: new Text(text, style: style.Text.liveNow), onPressed: callback);
}
@override
@@ -106,6 +108,25 @@
}
}
+ bool _isMoving(logic_card.Card c) {
+ CardAnimationData data = cardLevelMap[c];
+ RenderBox box = context.findRenderObject();
+ Point localOld =
+ data.oldPoint != null ? box.globalToLocal(data.oldPoint) : null;
+ Point localNew = box.globalToLocal(data.newPoint);
+
+ // We also need confirmation from the ZCard that we are moving.
+ component_card.GlobalCardKey zCardKey =
+ new component_card.GlobalCardKey(c, component_card.CardUIType.ZCARD);
+ component_card.ZCardState zCardKeyState = zCardKey.currentState;
+
+ // It is moving if there is an old position, the new one isn't equal to the
+ // old one, and the ZCard hasn't arrived at the new position yet.
+ return localOld != null &&
+ localOld != localNew &&
+ localNew != zCardKeyState?.localPosition;
+ }
+
// Helper to build the card animation layer.
// Note: This isn't a component because of its dependence on Widgets.
Widget buildCardAnimationLayer(List<int> visibleCardCollections) {
@@ -117,9 +138,20 @@
List<Widget> positionedCards = new List<Widget>();
- // Sort the cards by z-index.
+ // Sort the cards by z-index. If a card is animating, it gets a z bonus.
List<logic_card.Card> orderedKeys = cardLevelMap.keys.toList()
..sort((logic_card.Card a, logic_card.Card b) {
+ bool isMovingA = _isMoving(a);
+ bool isMovingB = _isMoving(b);
+
+ // Moving cards take much higher priority.
+ if (isMovingA && !isMovingB) {
+ return 1;
+ } else if (!isMovingA && isMovingB) {
+ return -1;
+ }
+
+ // If both are moving/non-moving, we break ties with the z-index.
double diff = cardLevelMap[a].z - cardLevelMap[b].z;
return diff.sign.toInt();
});
diff --git a/lib/components/hearts/hearts.part.dart b/lib/components/hearts/hearts.part.dart
index 9fa4991..a310ee5 100644
--- a/lib/components/hearts/hearts.part.dart
+++ b/lib/components/hearts/hearts.part.dart
@@ -207,19 +207,25 @@
});
}
- Widget _makeDebugButtons() => new Container(
- width: config.width,
- child: new Flex([
- new Flexible(flex: 1, child: new Text('P${config.game.playerNumber}')),
- new Flexible(
- flex: 5,
- child: _makeButton('Switch Player', _switchPlayersCallback)),
- new Flexible(
- flex: 5, child: _makeButton('Switch View', _switchViewCallback)),
- new Flexible(
- flex: 5, child: _makeButton('End Round', _endRoundDebugCallback)),
- new Flexible(flex: 4, child: _makeButton('Quit', _quitGameCallback))
- ]));
+ Widget _makeDebugButtons() {
+ if (config.game.debugMode == false) {
+ return new Flex([]);
+ }
+ return new Container(
+ width: config.width,
+ child: new Flex([
+ new Flexible(
+ flex: 1, child: new Text('P${config.game.playerNumber}')),
+ new Flexible(
+ flex: 5,
+ child: _makeButton('Switch Player', _switchPlayersCallback)),
+ new Flexible(
+ flex: 5, child: _makeButton('Switch View', _switchViewCallback)),
+ new Flexible(
+ flex: 5, child: _makeButton('End Round', _endRoundDebugCallback)),
+ new Flexible(flex: 4, child: _makeButton('Quit', _quitGameCallback))
+ ]));
+ }
@override
Widget _makeButton(String text, NoArgCb callback, {bool inactive: false}) {
diff --git a/lib/components/main_route.dart b/lib/components/main_route.dart
new file mode 100644
index 0000000..5a0a715
--- /dev/null
+++ b/lib/components/main_route.dart
@@ -0,0 +1,69 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+import 'package:flutter/material.dart';
+
+import '../logic/croupier.dart' show Croupier;
+import '../styles/common.dart' as style;
+import 'croupier.dart' show CroupierComponent;
+
+final GlobalKey _scaffoldKey = new GlobalKey();
+
+class MainRoute extends StatefulComponent {
+ final Croupier croupier;
+
+ MainRoute(this.croupier);
+
+ MainRouteState createState() => new MainRouteState();
+}
+
+class MainRouteState extends State<MainRoute> {
+ Widget build(BuildContext context) {
+ return new Scaffold(
+ key: _scaffoldKey,
+ toolBar: new ToolBar(
+ left:
+ new IconButton(icon: "navigation/menu", onPressed: _showDrawer),
+ center: new Text('Croupier')),
+ body: new Material(child: new CroupierComponent(config.croupier)));
+ }
+
+ void _showDrawer() {
+ showDrawer(
+ context: context,
+ child: new Block(<Widget>[
+ new DrawerHeader(
+ child: new Text('Croupier', style: style.Text.titleStyle)),
+ new DrawerItem(
+ icon: 'action/settings',
+ // TODO(alexfandrianto): Fix the Splash Screen, and we won't need
+ // to check if settings is null here.
+ // https://github.com/vanadium/issues/issues/958
+ onPressed:
+ config.croupier.settings != null ? _handleShowSettings : null,
+ child: new Text('Settings')),
+ // TODO(alexfandrianto): Once Flutter alpha branch is updated, this
+ // DrawerItem can have a Switch inside instead of DebugRoute.
+ // https://github.com/vanadium/issues/issues/957
+ new DrawerItem(
+ icon: 'action/build',
+ onPressed: _handleShowDebug,
+ child: new Text('Debug Mode')),
+ new DrawerItem(
+ icon: 'action/help', child: new Text('Help & Feedback'))
+ ]));
+ }
+
+ void _handleShowSettings() {
+ Navigator.of(context)
+ ..pop()
+ ..pushNamed('/settings');
+ }
+
+ void _handleShowDebug() {
+ Navigator.of(context)
+ ..pop()
+ ..pushNamed('/debug');
+ }
+}
diff --git a/lib/components/proto/proto.part.dart b/lib/components/proto/proto.part.dart
index d6b9873..4a11900 100644
--- a/lib/components/proto/proto.part.dart
+++ b/lib/components/proto/proto.part.dart
@@ -57,11 +57,16 @@
});
}
- Widget _makeDebugButtons() => new Flex([
- new Text('P${config.game.playerNumber}'),
- _makeButton('Switch View', _switchPlayersCallback),
- _makeButton('Quit', _quitGameCallback)
- ]);
+ Widget _makeDebugButtons() {
+ if (config.game.debugMode == false) {
+ return new Flex([]);
+ }
+ return new Flex([
+ new Text('P${config.game.playerNumber}'),
+ _makeButton('Switch View', _switchPlayersCallback),
+ _makeButton('Quit', _quitGameCallback)
+ ]);
+ }
void _switchPlayersCallback() {
setState(() {
diff --git a/lib/components/settings_route.dart b/lib/components/settings_route.dart
new file mode 100644
index 0000000..ab133bd
--- /dev/null
+++ b/lib/components/settings_route.dart
@@ -0,0 +1,19 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+import 'package:flutter/material.dart';
+
+import '../logic/croupier.dart' show Croupier;
+import 'croupier_settings.dart' show CroupierSettingsComponent;
+
+class SettingsRoute extends StatelessComponent {
+ final Croupier croupier;
+
+ SettingsRoute(this.croupier);
+
+ Widget build(BuildContext context) {
+ return new CroupierSettingsComponent(
+ croupier.settings, croupier.settings_manager.save);
+ }
+}
diff --git a/lib/components/solitaire/solitaire.part.dart b/lib/components/solitaire/solitaire.part.dart
index 44661ec..fdcec8f 100644
--- a/lib/components/solitaire/solitaire.part.dart
+++ b/lib/components/solitaire/solitaire.part.dart
@@ -18,8 +18,6 @@
Widget build(BuildContext context) {
SolitaireGame game = config.game as SolitaireGame;
- print("Building Solitaire!");
-
// Build Solitaire and have it fill up the card level map.
// Unfortunately, this is required so that we can know which card components
// to collect.
@@ -57,15 +55,21 @@
});
}
- Widget _makeDebugButtons() => new Container(
- width: config.width,
- child: new Flex([
- new Flexible(flex: 1, child: new Text('P${config.game.playerNumber}')),
- new Flexible(flex: 5, child: _makeButton('Cheat', _cheatCallback)),
- new Flexible(
- flex: 5, child: _makeButton('End Round', _endRoundDebugCallback)),
- new Flexible(flex: 4, child: _makeButton('Quit', _quitGameCallback))
- ]));
+ Widget _makeDebugButtons() {
+ if (config.game.debugMode == false) {
+ return new Flex([]);
+ }
+ return new Container(
+ width: config.width,
+ child: new Flex([
+ new Flexible(
+ flex: 1, child: new Text('P${config.game.playerNumber}')),
+ new Flexible(flex: 5, child: _makeButton('Cheat', _cheatCallback)),
+ new Flexible(
+ flex: 5, child: _makeButton('End Round', _endRoundDebugCallback)),
+ new Flexible(flex: 4, child: _makeButton('Quit', _quitGameCallback))
+ ]));
+ }
@override
Widget _makeButton(String text, NoArgCb callback, {bool inactive: false}) {
diff --git a/lib/logic/create_game.dart b/lib/logic/create_game.dart
index 94e7caa..ae08b66 100644
--- a/lib/logic/create_game.dart
+++ b/lib/logic/create_game.dart
@@ -7,17 +7,18 @@
import 'proto/proto.dart' as proto_impl;
import 'solitaire/solitaire.dart' as solitaire_impl;
-game_impl.Game createGame(game_impl.GameType gt, int pn,
+game_impl.Game createGame(game_impl.GameType gt, int pn, bool debugMode,
{int gameID, bool isCreator}) {
switch (gt) {
case game_impl.GameType.Proto:
- return new proto_impl.ProtoGame(pn, gameID: gameID, isCreator: isCreator);
+ return new proto_impl.ProtoGame(pn, gameID: gameID, isCreator: isCreator)
+ ..debugMode = debugMode;
case game_impl.GameType.Hearts:
return new hearts_impl.HeartsGame(pn,
- gameID: gameID, isCreator: isCreator);
+ gameID: gameID, isCreator: isCreator)..debugMode = debugMode;
case game_impl.GameType.Solitaire:
return new solitaire_impl.SolitaireGame(pn,
- gameID: gameID, isCreator: isCreator);
+ gameID: gameID, isCreator: isCreator)..debugMode = debugMode;
default:
assert(false);
return null;
diff --git a/lib/logic/croupier.dart b/lib/logic/croupier.dart
index 559b367..ee119ac 100644
--- a/lib/logic/croupier.dart
+++ b/lib/logic/croupier.dart
@@ -10,14 +10,7 @@
import 'game/game.dart'
show Game, GameType, GameStartData, stringToGameType, gameTypeToString;
-enum CroupierState {
- Welcome,
- Settings,
- ChooseGame,
- JoinGame,
- ArrangePlayers,
- PlayGame
-}
+enum CroupierState { Welcome, ChooseGame, JoinGame, ArrangePlayers, PlayGame }
typedef void NoArgCb();
@@ -36,6 +29,8 @@
Future _scanFuture;
Future _advertiseFuture;
+ bool debugMode = false; // whether to show debug buttons or not
+
Croupier() {
state = CroupierState.Welcome;
settings_everyone = new Map<int, CroupierSettings>();
@@ -46,6 +41,9 @@
settings_manager.load().then((String csString) {
settings = new CroupierSettings.fromJSONString(csString);
+ if (this.informUICb != null) {
+ this.informUICb();
+ }
settings_manager.createSettingsSyncgroup(); // don't wait for this future.
});
}
@@ -98,11 +96,6 @@
// data should be empty.
assert(data == null);
break;
- case CroupierState.Settings:
- // data should be empty.
- // All settings changes affect the croupier settings directly without changing app state.
- assert(data == null);
- break;
case CroupierState.ChooseGame:
if (data == null) {
// Back button pressed.
@@ -112,7 +105,7 @@
// data should be the game id here.
GameType gt = data as GameType;
- game = cg.createGame(gt, 0,
+ game = cg.createGame(gt, 0, this.debugMode,
isCreator: true); // Start as player 0 of whatever game type.
_advertiseFuture = settings_manager
@@ -137,7 +130,8 @@
// data would probably be the game id again.
GameStartData gsd = data as GameStartData;
- game = cg.createGame(stringToGameType(gsd.type), gsd.playerNumber,
+ game = cg.createGame(
+ stringToGameType(gsd.type), gsd.playerNumber, this.debugMode,
gameID: gsd.gameID); // Start as player 0 of whatever game type.
String sgName;
games_found.forEach((String name, GameStartData g) {
@@ -169,13 +163,6 @@
assert(false);
}
- // TODO(alexfandrianto): We may want to have a splash screen or something
- // when the user first loads the app. It takes a few seconds before the
- // Syncbase tables are created.
- if (settings == null) {
- return; // you can't switch till the settings are present.
- }
-
// A simplified way of clearing out the games and players found.
// They will need to be re-discovered in the future.
if (nextState == CroupierState.Welcome) {
diff --git a/lib/logic/game/game_def.part.dart b/lib/logic/game/game_def.part.dart
index f969623..70315df 100644
--- a/lib/logic/game/game_def.part.dart
+++ b/lib/logic/game/game_def.part.dart
@@ -91,6 +91,7 @@
_playerNumber = other;
}
+ bool debugMode = false;
String debugString = 'hello?';
NoArgCb updateCallback; // Used to inform components of when a change has occurred. This is especially important when something non-UI related changes what should be drawn.
diff --git a/lib/main.dart b/lib/main.dart
index 141b3a5..1f45727 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -3,10 +3,12 @@
// license that can be found in the LICENSE file.
import 'package:flutter/material.dart';
-import 'package:flutter/material.dart' show Colors;
import 'logic/croupier.dart' show Croupier;
-import 'components/croupier.dart' show CroupierComponent;
+import 'components/settings_route.dart' show SettingsRoute;
+import 'components/debug_route.dart' show DebugRoute;
+import 'components/main_route.dart' show MainRoute;
+import 'styles/common.dart' as style;
class CroupierApp extends StatefulComponent {
CroupierApp();
@@ -23,21 +25,17 @@
}
Widget build(BuildContext context) {
- return new Container(
- decoration: new BoxDecoration(
- backgroundColor: const Color(0xFF6666FF), borderRadius: 5.0),
- child: new DefaultTextStyle(
- style: Theme.of(context).text.body1,
- child: new CroupierComponent(this.croupier)));
+ return new MaterialApp(
+ title: 'Croupier',
+ routes: <String, RouteBuilder>{
+ "/": (RouteArguments args) => new MainRoute(croupier),
+ "/settings": (RouteArguments args) => new SettingsRoute(croupier),
+ "/debug": (RouteArguments args) => new DebugRoute(croupier)
+ },
+ theme: style.theme);
}
}
void main() {
- runApp(new MaterialApp(
- title: 'Croupier',
- routes: <String, RouteBuilder>{
- "/": (RouteArguments args) => new CroupierApp()
- },
- theme: new ThemeData(
- brightness: ThemeBrightness.light, primarySwatch: Colors.purple)));
+ runApp(new CroupierApp());
}
diff --git a/lib/styles/common.dart b/lib/styles/common.dart
new file mode 100644
index 0000000..ccbef24
--- /dev/null
+++ b/lib/styles/common.dart
@@ -0,0 +1,40 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+import 'package:flutter/material.dart';
+
+class Text {
+ static final Color secondaryTextColor = Colors.grey[500];
+ static final Color errorTextColor = Colors.red[500];
+ static final TextStyle titleStyle = new TextStyle(fontSize: 18.0);
+ static final TextStyle subtitleStyle =
+ new TextStyle(fontSize: 12.0, color: secondaryTextColor);
+ static final TextStyle liveNow =
+ new TextStyle(fontSize: 12.0, color: theme.accentColor);
+ static final TextStyle error = new TextStyle(color: errorTextColor);
+}
+
+class Size {
+ static const double thumbnailWidth = 250.0;
+ static const double listHeight = 150.0;
+ static const double thumbnailNavHeight = 150.0;
+ static const double thumbnailNavWidth = 267.0;
+}
+
+class Spacing {
+ static final EdgeDims extraSmallPadding = new EdgeDims.all(2.0);
+ static final EdgeDims smallPadding = new EdgeDims.all(5.0);
+ static final EdgeDims normalPadding = new EdgeDims.all(10.0);
+ static final EdgeDims normalMargin = new EdgeDims.all(2.0);
+ static final EdgeDims listItemMargin = new EdgeDims.TRBL(3.0, 6.0, 0.0, 6.0);
+ static final EdgeDims thumbnailNavMargin = new EdgeDims.all(3.0);
+}
+
+class Box {
+ static final BoxDecoration liveNow = new BoxDecoration(
+ border: new Border.all(color: theme.accentColor), borderRadius: 2.0);
+}
+
+ThemeData theme = new ThemeData(
+ primarySwatch: Colors.blueGrey, accentColor: Colors.orangeAccent[700]);
diff --git a/manifest.yaml b/manifest.yaml
index 49f0273..3bac6e9 100644
--- a/manifest.yaml
+++ b/manifest.yaml
@@ -1,3 +1,10 @@
+name: croupier
+material-design-icons:
+ - name: action/build
+ - name: action/help
+ - name: action/settings
+ - name: navigation/arrow_back
+ - name: navigation/menu
assets:
- images/default/classic/down/c10.png
- images/default/classic/down/c1.png
@@ -217,4 +224,4 @@
- images/avatars/Club.png
- images/avatars/Diamond.png
- images/avatars/Heart.png
- - images/avatars/Spade.png
\ No newline at end of file
+ - images/avatars/Spade.png