Commit f0ea0eaf authored by Adam Barth's avatar Adam Barth

Hide EditableString implementation details

Previously, EditableString had many public members because it needed to
implement the KeyboardClient interface. However, that's confusing
because these methods cannot be called directly.

Now EditableString holds a private implementation of the KeyboardClient,
which hides the implementation details.

Fixes #208
Fixes #209
parent 7737117a
...@@ -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