Commit b7396ba1 authored by Adam Barth's avatar Adam Barth

Merge pull request #1379 from abarth/protect_editable_string

Hide EditableString implementation details
parents 7737117a f0ea0eaf
...@@ -109,7 +109,7 @@ class _InputState extends State<Input> { ...@@ -109,7 +109,7 @@ class _InputState extends State<Input> {
_editableString.selection.end); _editableString.selection.end);
} else if (!focused && _keyboardHandle.attached) { } else if (!focused && _keyboardHandle.attached) {
_keyboardHandle.release(); _keyboardHandle.release();
_editableString.composing = TextRange.empty; _editableString.didDetachKeyboard();
} }
} }
......
...@@ -23,8 +23,10 @@ class _KeyboardConnection { ...@@ -23,8 +23,10 @@ class _KeyboardConnection {
static final _KeyboardConnection instance = new _KeyboardConnection(); static final _KeyboardConnection instance = new _KeyboardConnection();
} }
/// An interface to the system's keyboard.
///
/// Most clients will want to use the [keyboard] singleton instance.
class Keyboard { class Keyboard {
Keyboard(this.service); Keyboard(this.service);
// The service is exposed in case you need direct access. // The service is exposed in case you need direct access.
......
...@@ -26,11 +26,7 @@ class TextRange { ...@@ -26,11 +26,7 @@ class TextRange {
end = position; end = position;
/// A text range that contains nothing and is not in the text. /// A text range that contains nothing and is not in the text.
const TextRange._empty() static const TextRange empty = const TextRange(start: -1, end: -1);
: start = -1,
end = -1;
static const TextRange empty = const TextRange._empty();
/// The index of the first character in the range. /// The index of the first character in the range.
final int start; final int start;
...@@ -43,11 +39,29 @@ class TextRange { ...@@ -43,11 +39,29 @@ class TextRange {
/// Whether this range is empty (but still potentially placed inside the text). /// Whether this range is empty (but still potentially placed inside the text).
bool get isCollapsed => start == end; bool get isCollapsed => start == end;
/// The text before this range.
String textBefore(String text) {
return text.substring(0, start);
}
/// The text after this range.
String textAfter(String text) {
return text.substring(end);
}
/// The text inside this range.
String textInside(String text) {
return text.substring(start, end);
}
} }
/// A string that can be manipulated by a keyboard. class _KeyboardClientImpl implements KeyboardClient {
class EditableString implements KeyboardClient { _KeyboardClientImpl({
EditableString({this.text: '', this.onUpdated, this.onSubmitted}) { this.text: '',
this.onUpdated,
this.onSubmitted
}) {
assert(onUpdated != null); assert(onUpdated != null);
assert(onSubmitted != null); assert(onSubmitted != null);
stub = new KeyboardClientStub.unbound()..impl = this; stub = new KeyboardClientStub.unbound()..impl = this;
...@@ -57,39 +71,24 @@ class EditableString implements KeyboardClient { ...@@ -57,39 +71,24 @@ class EditableString implements KeyboardClient {
/// The current text being edited. /// The current text being edited.
String text; String text;
// The range of text that is still being composed.
TextRange composing = TextRange.empty;
/// The range of text that is currently selected.
TextRange selection;
/// Called whenever the text changes. /// Called whenever the text changes.
final VoidCallback onUpdated; final VoidCallback onUpdated;
/// Called whenever the user indicates they are done editing the string. /// Called whenever the user indicates they are done editing the string.
final VoidCallback onSubmitted; final VoidCallback onSubmitted;
/// A keyboard client stub that can be attached to a keyboard service. // The range of text that is still being composed.
KeyboardClientStub stub; TextRange composing = TextRange.empty;
/// The text before the given range.
String textBefore(TextRange range) {
return text.substring(0, range.start);
}
/// The text after the given range. /// The range of text that is currently selected.
String textAfter(TextRange range) { TextRange selection = TextRange.empty;
return text.substring(range.end);
}
/// The text inside the given range. /// A keyboard client stub that can be attached to a keyboard service.
String textInside(TextRange range) { KeyboardClientStub stub;
return text.substring(range.start, range.end);
}
void _delete(TextRange range) { void _delete(TextRange range) {
if (range.isCollapsed || !range.isValid) return; if (range.isCollapsed || !range.isValid) return;
text = textBefore(range) + textAfter(range); text = range.textBefore(text) + range.textAfter(text);
} }
TextRange _append(String newText) { TextRange _append(String newText) {
...@@ -101,8 +100,8 @@ class EditableString implements KeyboardClient { ...@@ -101,8 +100,8 @@ class EditableString implements KeyboardClient {
TextRange _replace(TextRange range, String newText) { TextRange _replace(TextRange range, String newText) {
assert(range.isValid); assert(range.isValid);
String before = textBefore(range); String before = range.textBefore(text);
String after = textAfter(range); String after = range.textAfter(text);
text = before + newText + after; text = before + newText + after;
return new TextRange( return new TextRange(
...@@ -168,6 +167,42 @@ class EditableString implements KeyboardClient { ...@@ -168,6 +167,42 @@ class EditableString implements KeyboardClient {
} }
} }
/// A string that can be manipulated by a keyboard.
///
/// Can be displayed with [RawEditableLine]. For a more featureful input widget,
/// consider using [Input].
class EditableString {
EditableString({
String text: '',
VoidCallback onUpdated,
VoidCallback onSubmitted
}) : _client = new _KeyboardClientImpl(
text: text,
onUpdated: onUpdated,
onSubmitted: onSubmitted
);
final _KeyboardClientImpl _client;
/// The current text being edited.
String get text => _client.text;
// The range of text that is still being composed.
TextRange get composing => _client.composing;
/// The range of text that is currently selected.
TextRange get selection => _client.selection;
/// A keyboard client stub that can be attached to a keyboard service.
///
/// See [Keyboard].
KeyboardClientStub get stub => _client.stub;
void didDetachKeyboard() {
_client.composing = TextRange.empty;
}
}
/// A basic single-line input control. /// A basic single-line input control.
/// ///
/// This control is not intended to be used directly. Instead, consider using /// This control is not intended to be used directly. Instead, consider using
...@@ -337,11 +372,11 @@ class _EditableLineWidget extends LeafRenderObjectWidget { ...@@ -337,11 +372,11 @@ class _EditableLineWidget extends LeafRenderObjectWidget {
); );
return new StyledTextSpan(style, <TextSpan>[ return new StyledTextSpan(style, <TextSpan>[
new PlainTextSpan(value.textBefore(value.composing)), new PlainTextSpan(value.composing.textBefore(value.text)),
new StyledTextSpan(composingStyle, <TextSpan>[ new StyledTextSpan(composingStyle, <TextSpan>[
new PlainTextSpan(value.textInside(value.composing)) new PlainTextSpan(value.composing.textInside(value.text))
]), ]),
new PlainTextSpan(value.textAfter(value.composing)) new PlainTextSpan(value.composing.textAfter(value.text))
]); ]);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment