blob: 992f0cbfb79b66d12496c92039393c40cb02f7f3 [file] [log] [blame]
// Copyright 2015 The Chromium 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:sky/editing/editable_string.dart';
import 'package:sky/editing/editable_text.dart';
import 'package:sky/mojo/keyboard.dart';
import 'package:sky/painting/text_style.dart';
import 'package:sky/widgets/basic.dart';
import 'package:sky/widgets/theme.dart';
typedef void ValueChanged(value);
// TODO(eseidel): This isn't right, it's 16px on the bottom:
// http://www.google.com/design/spec/components/text-fields.html#text-fields-single-line-text-field
const EdgeDims _kTextfieldPadding = const EdgeDims.symmetric(vertical: 8.0);
class Input extends StatefulComponent {
// Current thinking is that Widget will have an optional globalKey
// or heroKey and it will ask Focus.from(this).isFocused which will
// check using its globalKey.
// Only one element can use a globalKey at a time and its' up to
// Widget.sync to maintain the mapping.
// Never makes sense to have both a localKey and a globalKey.
// Possibly a class HeroKey who functions as a UUID.
Input({String key,
this.placeholder,
this.onChanged,
this.focused})
: super(key: key);
String placeholder;
ValueChanged onChanged;
bool focused = false;
void initState() {
_editableValue = new EditableString(
text: _value,
onUpdated: _handleTextUpdated
);
super.initState();
}
void syncFields(Input source) {
placeholder = source.placeholder;
onChanged = source.onChanged;
focused = source.focused;
}
String _value = '';
bool _isAttachedToKeyboard = false;
EditableString _editableValue;
void _handleTextUpdated() {
scheduleBuild();
if (_value != _editableValue.text) {
_value = _editableValue.text;
if (onChanged != null)
onChanged(_value);
}
}
Widget build() {
ThemeData themeData = Theme.of(this);
if (focused && !_isAttachedToKeyboard) {
keyboard.show(_editableValue.stub);
_isAttachedToKeyboard = true;
}
TextStyle textStyle = themeData.text.subhead;
List<Widget> textChildren = <Widget>[];
if (placeholder != null && _value.isEmpty) {
Widget child = new Opacity(
key: "placeholder",
child: new Text(placeholder, style: textStyle),
opacity: themeData.hintOpacity
);
textChildren.add(child);
}
Color focusHighlightColor = themeData.accentColor;
Color cursorColor = themeData.accentColor;
if (themeData.primarySwatch != null) {
cursorColor = themeData.primarySwatch[200];
focusHighlightColor = focused ? themeData.primarySwatch[400] : themeData.hintColor;
}
textChildren.add(new EditableText(
value: _editableValue,
focused: focused,
style: textStyle,
cursorColor: cursorColor
));
Border focusHighlight = new Border(bottom: new BorderSide(
color: focusHighlightColor,
width: focused ? 2.0 : 1.0
));
Container input = new Container(
child: new Stack(textChildren),
padding: _kTextfieldPadding,
decoration: new BoxDecoration(border: focusHighlight)
);
return new Listener(
child: input,
onPointerDown: (_) => keyboard.showByRequest()
);
}
void didUnmount() {
if (_isAttachedToKeyboard)
keyboard.hide();
super.didUnmount();
}
}